Reputation: 1175
I am looking for a way to display a TextField with dropdown list showing previous inputs by the user. The contents of the dropdown list are stored in shared preferences. I know how to implement them separately but I am struggling to find a solution that combines the two.
I have searched everywhere but all the solutions I've found are for autocomplete or something similar. I'm not looking for an autocomplete solution, just a dropdown that appears under the TextField widget when it is focused, and fills in the text that's selected. The image below is taken from a website, I want to do the same thing for my mobile app.
What I have so far:
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
OutlinedButton(
style: OutlinedButton.styleFrom(
primary: Colors.red,
backgroundColor: Colors.white,
side: const BorderSide(color: Colors.red, width: 1.0),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(32.0))),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [Icon(LineIcons.googlePlusG, size: 20.0), SizedBox(width: 8.0), Text('Google 登入')],
),
onPressed: () {
focusNode.unfocus();
},
),
OutlinedButton(
style: OutlinedButton.styleFrom(
primary: Colors.indigo,
backgroundColor: Colors.white,
side: const BorderSide(color: Colors.indigo, width: 1.0),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(32.0))),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [Icon(LineIcons.facebookF, size: 16.0), SizedBox(width: 8.0), Text('Facebook 登入')],
),
onPressed: () {
focusNode.unfocus();
},
),
Container(margin: const EdgeInsets.symmetric(vertical: 16.0), color: Colors.grey.shade300, height: 1.0),
Row(
children: const [
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text('帳號', style: MyFonts.inputText),
),
),
],
),
TextFormField(
validator: RequiredValidator(errorText: 'Username is required'),
controller: usernameEdit,
style: MyFonts.inputText,
keyboardType: TextInputType.text,
cursorColor: Colors.black,
cursorHeight: 20.0,
decoration: InputDecoration(
isDense: true,
hintText: '請輸入帳號',
hintStyle: MyFonts.hintText,
contentPadding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 16.0),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
borderSide: const BorderSide(color: MyColors.theme),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
),
),
textInputAction: TextInputAction.next,
onEditingComplete: () => focusNode.nextFocus(),
),
const SizedBox(height: 16.0),
Row(
children: const [
Expanded(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text('密碼', style: MyFonts.inputText),
),
),
],
),
TextFormField(
validator: RequiredValidator(errorText: 'Password is required'),
controller: pwdEdit,
style: MyFonts.inputText,
keyboardType: TextInputType.visiblePassword,
cursorColor: Colors.black,
cursorHeight: 20.0,
obscureText: hidePwd,
decoration: InputDecoration(
suffixIcon: IconButton(
color: Colors.grey,
onPressed: () => setState(() {
hidePwd = !hidePwd;
}),
icon: Icon((hidePwd) ? Icons.visibility_off : Icons.visibility),
),
isDense: true,
hintText: '請輸入密碼',
hintStyle: MyFonts.hintText,
contentPadding: const EdgeInsets.symmetric(horizontal: 16.0),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
borderSide: const BorderSide(color: MyColors.theme),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
),
),
textInputAction: TextInputAction.next,
onEditingComplete: () => focusNode.nextFocus(),
),
const SizedBox(height: 16.0),
Row(
children: [
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: MyColors.theme,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(32.0))),
),
onPressed: () async {
var sharedPrefs = await SharedPreferences.getInstance();
sharedPrefs.setString('username', usernameEdit.text);
sharedPrefs.setString('pwd', pwdEdit.text);
focusNode.unfocus();
},
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'登入',
style: MyFonts.buttonText,
),
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
focusNode.unfocus();
Navigator.pushNamed(context, '/signup');
},
child: const Text('加入會員', style: MyFonts.textButtonText)),
TextButton(onPressed: () {}, child: const Text('忘記密碼?', style: MyFonts.textButtonText)),
],
)
],
)
Upvotes: 0
Views: 762
Reputation: 1038
use flutter package flutter_typeahead
Demo:
sample code:
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: TypeAheadField<Story>(
noItemsFoundBuilder: (value) {
return ListTile(
title: Text('no Story Found'));
},
hideOnEmpty: false,
getImmediateSuggestions: true,
textFieldConfiguration: TextFieldConfiguration(
autofocus: true,
controller: storyTextController,
style: TextStyle(
fontFamily: 'Roboto',
fontSize: 25,
fontWeight: FontWeight.bold,
color: ThaqalaynColors.colorPurple),
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'search',
hintStyle: TextStyle(
fontFamily: 'Roboto',
fontSize: 25,
fontWeight: FontWeight.bold,
color: ThaqalaynColors.colorPurple),
),
),
suggestionsCallback: (String pattern) async {
return pattern.isNotEmpty
? storyController.storyList
.where((item) => item.title
.toLowerCase()
.contains(pattern.toLowerCase()))
.toList()
: storyController.storyList.getRange(0, 3).toList();
},
itemBuilder: (context, Story suggestion) {
return ListTile(
title: Text(suggestion.title),
);
},
onSuggestionSelected: (Story suggestion) {
storyTextController.text = suggestion.title;
print("Suggestion selected ${suggestion.title}");
},
),
),
Upvotes: 3