【问题标题】:Flutter DropDownSearch value resets on changing focus to other widgetsFlutter DropDownSearch 值在将焦点更改为其他小部件时重置
【发布时间】:2021-02-04 20:11:11
【问题描述】:

我正在使用dropdownsearch 在布局中创建下拉搜索小部件,当我将焦点更改为其他小部件时,每次都会重置值类型。该插件还有一个名为 selected item 的属性,如果您在更改焦点时使用它,它会重置为最初选择的项目。

/dropdown_search/example

这是我的代码:

DropdownSearch<StudyName>(
                         mode: Mode.BOTTOM_SHEET,

                         items: _studyNamemodel,
                         itemAsString: (StudyName u) => u.studyName,
                         onChanged: (StudyName data) { print(data.modalityIDFkey);
                         //FocusScope.of(context).nextFocus();
                         _selectedStudyname=data.studyName;
                         },
                         maxHeight: 300,
                         onFind: (String filter) => getData(filter),
                         label: "Study Name",
                       ),

【问题讨论】:

    标签: android flutter dart dropdown flutter-dependencies


    【解决方案1】:

    您可以在下面复制粘贴运行完整代码
    我用官方的例子来模拟这个案例
    为避免重建清除选定项,您需要使用selectedItem: _selected
    onChanged_selected = data;
    在工作演示中,您可以看到Hot reload 之后,User 仍然被正确选择并且Person 已被重置

    用你的代码编码 sn-p

    StudyName _selected;
    
    DropdownSearch<StudyName>(
             selectedItem: _selected,
             mode: Mode.BOTTOM_SHEET,            
             items: _studyNamemodel,
             itemAsString: (StudyName u) => u.studyName,
             onChanged: (StudyName data) { 
                _selected = data;
    
                print(data.modalityIDFkey);
                //FocusScope.of(context).nextFocus();
                _selectedStudyname=data.studyName;
             },
             maxHeight: 300,
             onFind: (String filter) => getData(filter),
             label: "Study Name",
           ),
    

    用官方例子编写sn-p代码

    UserModel _selectedItemUser;
    ...
    DropdownSearch<UserModel>(
        selectedItem: _selectedItemUser,
        mode: Mode.BOTTOM_SHEET,
        isFilteredOnline: true,
        showClearButton: true,
        showSearchBox: true,
        label: 'User *',
        dropdownSearchDecoration: InputDecoration(
            filled: true,
            fillColor:
                Theme.of(context).inputDecorationTheme.fillColor),
        //autoValidate: true,
        validator: (UserModel u) =>
            u == null ? "user field is required " : null,
        onFind: (String filter) => getData(filter),
        onChanged: (UserModel data) {
          print(data);
          _selectedItemUser = data;
        },
        dropdownBuilder: _customDropDownExample,
        popupItemBuilder: _customPopupItemBuilderExample,
      ),
    

    工作演示

    完整代码

    import 'package:dio/dio.dart';
    import 'package:dropdown_search/dropdown_search.dart';
    import 'package:flutter/material.dart';
    
    class UserModel {
      final String id;
      final DateTime createdAt;
      final String name;
      final String avatar;
    
      UserModel({this.id, this.createdAt, this.name, this.avatar});
    
      factory UserModel.fromJson(Map<String, dynamic> json) {
        if (json == null) return null;
        return UserModel(
          id: json["id"],
          createdAt:
              json["createdAt"] == null ? null : DateTime.parse(json["createdAt"]),
          name: json["name"],
          avatar: json["avatar"],
        );
      }
    
      static List<UserModel> fromJsonList(List list) {
        if (list == null) return null;
        return list.map((item) => UserModel.fromJson(item)).toList();
      }
    
      ///this method will prevent the override of toString
      String userAsString() {
        return '#${this.id} ${this.name}';
      }
    
      ///this method will prevent the override of toString
      bool userFilterByCreationDate(String filter) {
        return this?.createdAt?.toString()?.contains(filter);
      }
    
      ///custom comparing function to check if two users are equal
      bool isEqual(UserModel model) {
        return this?.id == model?.id;
      }
    
      @override
      String toString() => name;
    }
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          //enable this line if you want test Dark Mode
          //theme: ThemeData.dark(),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      final _formKey = GlobalKey<FormState>();
      String _selectedItemCountry = "Italia";
      UserModel _selectedItemUser;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: Text("DropdownSearch Demo")),
          body: Padding(
            padding: const EdgeInsets.all(25),
            child: Form(
              key: _formKey,
              autovalidate: true,
              child: ListView(
                padding: EdgeInsets.all(4),
                children: <Widget>[
                  ///Menu Mode with no searchBox
                  DropdownSearch<String>(
                    validator: (v) => v == null ? "required field" : null,
                    hint: "Select a country",
                    mode: Mode.MENU,
                    showSelectedItem: true,
                    items: ["Brazil", "Italia (Disabled)", "Tunisia", 'Canada'],
                    label: "Menu mode *",
                    showClearButton: true,
                    onChanged: print,
                    popupItemDisabled: (String s) => s.startsWith('I'),
                    selectedItem: "Brazil",
                  ),
                  Divider(),
                  DropdownSearch<UserModel>(
                    selectedItem: _selectedItemUser,
                    mode: Mode.BOTTOM_SHEET,
                    isFilteredOnline: true,
                    showClearButton: true,
                    showSearchBox: true,
                    label: 'User *',
                    dropdownSearchDecoration: InputDecoration(
                        filled: true,
                        fillColor:
                            Theme.of(context).inputDecorationTheme.fillColor),
                    //autoValidate: true,
                    validator: (UserModel u) =>
                        u == null ? "user field is required " : null,
                    onFind: (String filter) => getData(filter),
                    onChanged: (UserModel data) {
                      print(data);
                      _selectedItemUser = data;
                    },
                    dropdownBuilder: _customDropDownExample,
                    popupItemBuilder: _customPopupItemBuilderExample,
                  ),
                  Divider(),
    
                  ///custom itemBuilder and dropDownBuilder
                  DropdownSearch<UserModel>(
                    showSelectedItem: true,
                    compareFn: (UserModel i, UserModel s) => i.isEqual(s),
                    label: "Person",
                    onFind: (String filter) => getData(filter),
                    onChanged: (UserModel data) {
                      print(data);
                    },
                    dropdownBuilder: _customDropDownExample,
                    popupItemBuilder: _customPopupItemBuilderExample2,
                  ),
                  Divider(),
    
                  ///BottomSheet Mode with no searchBox
                  DropdownSearch<String>(
                    mode: Mode.BOTTOM_SHEET,
                    maxHeight: 300,
                    items: ["Brazil", "Italia", "Tunisia", 'Canada'],
                    label: "Custom BottomShet mode",
                    onChanged: print,
                    selectedItem: _selectedItemCountry,
                    showSearchBox: true,
                    searchBoxDecoration: InputDecoration(
                      border: OutlineInputBorder(),
                      contentPadding: EdgeInsets.fromLTRB(12, 12, 8, 0),
                      labelText: "Search a country",
                    ),
                    popupTitle: Container(
                      height: 50,
                      decoration: BoxDecoration(
                        color: Theme.of(context).primaryColorDark,
                        borderRadius: BorderRadius.only(
                          topLeft: Radius.circular(20),
                          topRight: Radius.circular(20),
                        ),
                      ),
                      child: Center(
                        child: Text(
                          'Country',
                          style: TextStyle(
                            fontSize: 24,
                            fontWeight: FontWeight.bold,
                            color: Colors.white,
                          ),
                        ),
                      ),
                    ),
                    popupShape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.only(
                        topLeft: Radius.circular(24),
                        topRight: Radius.circular(24),
                      ),
                    ),
                  ),
                  Divider(),
    
                  ///merge online and offline data in the same list and set custom max Height
                  DropdownSearch<UserModel>(
                    items: [
                      UserModel(name: "Offline name1", id: "999"),
                      UserModel(name: "Offline name2", id: "0101")
                    ],
                    maxHeight: 300,
                    onFind: (String filter) => getData(filter),
                    label: "choose a user",
                    onChanged: print,
                    showSearchBox: true,
                  ),
                  Divider(),
                ],
              ),
            ),
          ),
        );
      }
    
      Widget _customDropDownExample(
          BuildContext context, UserModel item, String itemDesignation) {
        return Container(
          child: (item?.avatar == null)
              ? ListTile(
                  contentPadding: EdgeInsets.all(0),
                  leading: CircleAvatar(),
                  title: Text("No item selected"),
                )
              : ListTile(
                  contentPadding: EdgeInsets.all(0),
                  leading: CircleAvatar(
                    backgroundImage: NetworkImage(item.avatar),
                  ),
                  title: Text("Dropdown ${item.name}"),
                  subtitle: Text(
                    item.createdAt.toString(),
                  ),
                ),
        );
      }
    
      Widget _customPopupItemBuilderExample(
          BuildContext context, UserModel item, bool isSelected) {
        return Container(
          margin: EdgeInsets.symmetric(horizontal: 8),
          decoration: !isSelected
              ? null
              : BoxDecoration(
                  border: Border.all(color: Theme.of(context).primaryColor),
                  borderRadius: BorderRadius.circular(5),
                  color: Colors.white,
                ),
          child: ListTile(
            selected: isSelected,
            title: Text("Popup ${item.name}"),
            subtitle: Text(item.createdAt.toString()),
            leading: CircleAvatar(
              backgroundImage: NetworkImage(item.avatar),
            ),
          ),
        );
      }
    
      Widget _customPopupItemBuilderExample2(
          BuildContext context, UserModel item, bool isSelected) {
        return Container(
          margin: EdgeInsets.symmetric(horizontal: 8),
          decoration: !isSelected
              ? null
              : BoxDecoration(
                  border: Border.all(color: Theme.of(context).primaryColor),
                  borderRadius: BorderRadius.circular(5),
                  color: Colors.white,
                ),
          child: ListTile(
            selected: isSelected,
            title: Text(item.name),
            subtitle: Text(item.createdAt.toString()),
            leading: CircleAvatar(
              backgroundImage: NetworkImage(item.avatar),
            ),
          ),
        );
      }
    
      Future<List<UserModel>> getData(filter) async {
        var response = await Dio().get(
          "https://5d85ccfb1e61af001471bf60.mockapi.io/user",
          queryParameters: {"filter": filter},
        );
    
        var models = UserModel.fromJsonList(response.data);
        return models;
      }
    }
    

    【讨论】:

      【解决方案2】:

      此问题已在 0.4.6 版中修复。请检查一下。 此外,在 v0.4.6 中,您可以在不使用 setState() 的情况下,使用 GlobalKey 以编程方式设置选定值,有关详细信息,请参阅插件示例。

      【讨论】:

        猜你喜欢
        • 2022-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-18
        • 2019-05-31
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        相关资源
        最近更新 更多