【问题标题】:How i can create dropdown like this in flutter我如何在颤动中创建这样的下拉列表
【发布时间】:2021-11-03 11:16:19
【问题描述】:

大家好,我正在做一些项目,需要创建一个自定义下拉菜单, 像这样

我可以在这里做代码,代码很乱,但一旦我让它工作,我会重构它。或者,如果您有其他方法可以做到这一点,我愿意接受建议。

  GlobalKey? actionKey = GlobalKey();

 List<String> picked = [];

  List<IconData> icons = [
    Icons.blur_circular_outlined,
    Icons.sports_basketball,
    Icons.sports_baseball_sharp,
    Icons.sports_tennis_rounded,
    Icons.people,
  ];
  List<String> sports = [
    "Fudbal",
    "Kosarka",
    "Tenis",
    "Stoni tenis",
    "Kuglanje"
  ];
  List<int> ints = [0, 1, 2, 3, 4];

  List<bool> booles = [false, false, false, false, false];
  OverlayEntry? overlayEntry;
  var position;
  double? y;
  double? x;
  void findDropdownData() {
    RenderBox renderBox =
        actionKey!.currentContext!.findRenderObject() as RenderBox;
    position = renderBox.localToGlobal(Offset.zero);
    y = position!.dy;
    x = position!.dx;
  }

  OverlayEntry _overlayEntryBuilder() {
    return OverlayEntry(
      builder: (context) {
        return Positioned(
          // top: position,
          left: 16.w,
          right: 16.w,
          child: Material(
            child: dropdownExpanded(),
          ),
        );
      },
    );
  }

  Widget buildRows(i) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 17.w, vertical: 15.h),
      child: Row(
        children: [
          SizedBox(
            height: 24.h,
            width: 24.w,
            child: Checkbox(
              activeColor: style.purpleMain,
              value: booles[i],
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(4)),
              onChanged: (value) {
                setState(() {
                  booles[i] = value!;
                  booles[i] == true
                      ? picked.add(sports[i])
                      : picked.remove(sports[i]);
                });
              },
            ),
          ),
          SizedBox(
            width: 10.w,
          ),
          Text(
            sports[i],
            style: TextStyle(
              color: booles[i] == true ? style.purpleMain : Colors.grey,
            ),
          ),
          const Spacer(),
          Icon(
            icons[i],
            color: booles[i] == true ? style.purpleMain : Colors.grey,
            size: 15,
          ),
        ],
      ),
    );
  }

  Widget dropdown() {
    return GestureDetector(
      key: actionKey,
      onTap: () {
        setState(() {
          isPressed = !isPressed;
        });
        if (isPressed == false) {
          overlayEntry = _overlayEntryBuilder();
          Overlay.of(context)!.insert(overlayEntry!);
        }
      },
      child: Container(
        width: double.infinity,
        height: 50.h,
        decoration: BoxDecoration(
          border: Border.all(color: style.e8e8e8),
          borderRadius: BorderRadius.circular(8),
        ),
        padding: EdgeInsets.only(left: 16.w, right: 13.w),
        child: Row(
          children: [
            picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
            const Spacer(),
            const Icon(
              Icons.arrow_drop_down,
              color: style.bdbdbd,
            ),
          ],
        ),
      ),
    );
  }

  Widget pickedEmpty() {
    return Text(
      "Možete obeležiti više aktivnosti",
      style: TextStyle(
        fontSize: 16.sp,
        color: style.bdbdbd,
        fontWeight: FontWeight.w400,
      ),
    );
  }

  Widget pickedNotEmpty() {
    List<Widget> list = <Widget>[];
    for (var i = 0; i < picked.length; i++) {
      list.add(
        Padding(
          padding: EdgeInsets.only(right: 5.w),
          child: Text(
            picked[i],
            style: TextStyle(
              fontSize: 16.sp,
              color: style.bdbdbd,
              fontWeight: FontWeight.w400,
            ),
          ),
        ),
      );
    }
    return Row(children: list);
  }

  Widget dropdownExpanded() {
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        border: Border.all(color: style.purpleMain),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Column(
        children: [
          GestureDetector(
            onTap: () {
              setState(() {
                isPressed = !isPressed;
              });
              overlayEntry?.remove();
            },
            child: Container(
              width: double.infinity,
              height: 50.h,
              padding: EdgeInsets.only(left: 16.w, right: 13.w),
              child: Row(
                children: [
                  picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
                  const Spacer(),
                  const Icon(
                    Icons.arrow_drop_up,
                    color: style.bdbdbd,
                  ),
                ],
              ),
            ),
          ),
          const Divider(
            height: 0,
            thickness: 1,
            color: style.e8e8e8,
            indent: 17,
            endIndent: 17,
          ),
          Column(
            children: [
              for (int i in ints) buildRows(i),
            ],
          ),
        ],
      ),
    );
  }

这里是结果

这就是我想要完成的事情

所以我只想向下移动这个扩展的下拉菜单,以及如果我不使用覆盖它应该如何更新覆盖中的这些布尔值,但我需要在另一个内容的顶部打开该下拉列表。感谢您的帮助。

【问题讨论】:

    标签: android ios flutter dart hybrid-mobile-app


    【解决方案1】:

    使用smart_select,它是完全可定制的,你可以使用这个库轻松实现你想要的设计。

    【讨论】:

    • 抱歉,我不知道如何使用这个包实现我的设计?
    【解决方案2】:

    更新答案

    关于 UI,它就像一个 Flutter 中的扩展 Tile Widget。您可以使用扩展磁贴实现该下拉菜单并在子项中传递项目列表, 对于expandcollapse tile 在选择每个项目后,您可以创建一个全局键并在 UI 中控制它。

    final GlobalKey<AppExpansionTileState> expansionTile = new GlobalKey();
    

    折叠→expansionTile.currentState.collapse();

    ExpansionTile(
      title: Text(
        "Možete obeležiti više aktivnosti",
        style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
      ),
      children: <Widget>[
        // put items here
      ],
    ),
    

    小号:

    Widget customDropDown() => Container(
          // color: Colors.white,
          padding: const EdgeInsets.all(10),
          child: ListTileTheme(
            dense: true,
            child: ExpansionTile(
              title: const Text(
                "Možete obeležiti više aktivnosti",
                style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
              ),
              children: <Widget>[
                Container(
                  width: double.infinity,
                  decoration: const BoxDecoration(
                      color: Colors.white,
                      borderRadius:
                          BorderRadius.vertical(bottom: Radius.circular(20))),
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Column(
                      children: const [
                        ListTile(
                          leading: Icon(Icons.ac_unit),
                          title: Text("something"),
                        ),
                        ListTile(
                          leading: Icon(Icons.ac_unit),
                          title: Text("something"),
                        ),
                        ListTile(
                          leading: Icon(Icons.ac_unit),
                          title: Text("something"),
                        ),
                        ListTile(
                          leading: Icon(Icons.ac_unit),
                          title: Text("something"),
                        )
                      ],
                    ),
                  ),
                )
              ],
            ),
          ),
        );
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: Scaffold(
            body: SafeArea(
              child: Stack(
                children: [pageDesign(), customDropDown()],
              ),
            ),
          ),
        );
      }
    
      fakeWidget(color) => Container(
            height: 100,
            width: double.infinity,
            color: color,
            child: const Center(
              child: Text("widget1"),
            ),
          );
    
      Widget pageDesign() => Column(
            children: [
              /* you should control this size in diffrent orientation and for big size 
                      device to handle responsive
                      */
              const SizedBox(
                height: 80,
              ),
              fakeWidget(
                Colors.green,
              ),
              fakeWidget(
                Colors.yellow,
              ),
              fakeWidget(
                Colors.orange,
              ),
              fakeWidget(
                Colors.blue,
              ),
            ],
          );
    

    【讨论】:

    • 感谢您的回复。如何在 ExpansionTile 下方重叠内容而不推送它(如 DropDown 小部件)?
    • @Milos 我添加了一个示例,您可以将此小部件与堆栈混合以实现 UI。
    猜你喜欢
    • 2021-09-25
    • 2019-11-21
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 2020-06-10
    • 2021-11-21
    相关资源
    最近更新 更多