Flutter自定义下拉选择框dropDownMenu

这篇具有很好参考价值的文章主要介绍了Flutter自定义下拉选择框dropDownMenu。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

利用PopupMenuButton和PopupMenuItem写了个下拉选择框,之所以不采用系统的,是因为自定义的更能适配项目需求,话不多说,直接看效果

flutter选择框,flutter,ios,android

下面直接贴出代码、代码中注释写的都很清楚,使用起来应该很方便,如果有任何问题,欢迎下方留言…
import 'package:flutter/material.dart';

class DropMenuWidget extends StatefulWidget {
  final List<Map<String, dynamic>> data; //数据
  final Function(String value) selectCallBack; //选中之后回调函数
  final String? selectedValue; //默认选中的值
  final Widget? leading; //前面的widget,一般是title
  final Widget trailing; //尾部widget,一般是自定义图片
  final Color? textColor;
  final Offset offset; //下拉框向下偏移量--手动调整间距---防止下拉框遮盖住显示的widget
  final TextStyle normalTextStyle; //下拉框的文字样式
  final TextStyle selectTextStyle; //下拉框选中的文字样式
  final double maxHeight; //下拉框的最大高度
  final double maxWidth; //下拉框的最大宽度
  final Color? backGroundColor; //下拉框背景颜色
  final bool animation; //是否显示动画---尾部图片动画
  final int duration; //动画时长
  const DropMenuWidget({
    super.key,
    this.leading,
    required this.data,
    required this.selectCallBack,
    this.selectedValue,
    this.trailing = const Icon(Icons.arrow_drop_down),
    this.textColor = Colors.white,
    this.offset = const Offset(0, 30),
    this.normalTextStyle = const TextStyle(
      color: Colors.white,
      fontSize: 12.0,
    ),
    this.selectTextStyle = const TextStyle(
      color: Colors.red,
      fontSize: 12.0,
    ),
    this.maxHeight = 200.0,
    this.maxWidth = 200.0,
    this.backGroundColor = const Color.fromRGBO(28, 34, 47, 1),
    this.animation = true,
    this.duration = 200,
  });

  @override
  State<DropMenuWidget> createState() => _DropMenuWidgetState();
}

class _DropMenuWidgetState extends State<DropMenuWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _animation;
  String _selectedLabel = '';
  String _currentValue = '';
  // 是否展开下拉按钮
  bool _isExpand = false;

  @override
  void initState() {
    super.initState();
    _currentValue = widget.selectedValue ?? '';
    if (widget.animation) {
      _animationController = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: widget.duration),
      );
      _animation = Tween(begin: 0.0, end: 0.5).animate(
        CurvedAnimation(
          parent: _animationController,
          curve: Curves.easeInOut,
        ),
      );
    }
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  _toggleExpand() {
    setState(() {
      if (_isExpand) {
        _animationController.forward();
      } else {
        _animationController.reverse();
      }
    });
  }

  //根据传值处理显示的文字
  _initLabel() {
    if (_currentValue.isNotEmpty) {
      _selectedLabel = widget.data
          .firstWhere((item) => item['value'] == _currentValue)['label'];
    } else if (widget.data.isNotEmpty) {
      // 没值默认取第一个
      _selectedLabel = widget.data[0]['label'];
      _currentValue = widget.data[0]['value'];
    }
  }

  @override
  Widget build(BuildContext context) {
    _initLabel();
    return PopupMenuButton(
      constraints: BoxConstraints(
        maxHeight: widget.maxHeight,
        maxWidth: widget.maxWidth,
      ),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(4.0),
      ),
      offset: widget.offset,
      color: widget.backGroundColor,
      onOpened: () {
        if (widget.animation) {
          setState(() {
            _isExpand = true;
            _toggleExpand();
          });
        }
      },
      onCanceled: () {
        if (widget.animation) {
          setState(() {
            _isExpand = false;
            _toggleExpand();
          });
        }
      },
      child: Container(
        alignment: Alignment.centerLeft,
        height: 40,
        child: FittedBox(
          //使用FittedBox是为了适配当字符串长度超过指定宽度的时候,会让字体自动缩小
          child: Row(
            children: [
              if (widget.leading != null) widget.leading!,
              Text(
                _selectedLabel,
                style: TextStyle(
                  color: widget.textColor,
                  fontSize: 14.0,
                ),
              ),
              if (widget.animation)
                AnimatedBuilder(
                  animation: _animation,
                  builder: (context, child) {
                    return Transform.rotate(
                      angle: _animation.value * 2.0 * 3.14, // 180度对应的弧度值
                      child: widget.trailing,
                    );
                  },
                ),
              if (!widget.animation) widget.trailing,
            ],
          ),
        ),
      ),
      itemBuilder: (context) {
        return widget.data.map((e) {
          return PopupMenuItem(
            child: Text(
              e['label'],
              style: e['value'] == _currentValue
                  ? widget.selectTextStyle
                  : widget.normalTextStyle,
            ),
            onTap: () {
              setState(() {
                _currentValue = e['value'];
                widget.selectCallBack(e['value']);
              });
            },
          );
        }).toList();
      },
    );
  }
}


使用
Container(
              color: Colors.grey,
              width: 130,
              alignment: Alignment.centerLeft,
              child: DropMenuWidget(
                leading: const Padding(
                  padding: EdgeInsets.only(right: 10),
                  child: Text('当前选中:'),
                ),
                data: const [
                  {'label': '华为', 'value': '1'},
                  {'label': '小米', 'value': '2'},
                  {'label': 'Apple', 'value': '3'},
                  {'label': '乔布斯', 'value': '4'},
                  {'label': '啦啦啦啦啦', 'value': '5'},
                  {'label': '呵呵', 'value': '7'},
                  {'label': '乐呵乐呵', 'value': '7'},
                ],
                selectCallBack: (value) {
                  print('选中的value是:$value');
                },
                offset: const Offset(0, 40),
                selectedValue: '3', //默认选中第三个
              ),
            )

简书地址如果喜欢,希望给个star😄😄文章来源地址https://www.toymoban.com/news/detail-847404.html

到了这里,关于Flutter自定义下拉选择框dropDownMenu的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter Android & IOS 获取通讯录联系人列表

    1.在 pubspec.yaml 文件中添加 contacts_service 和 permission_handler 插件的依赖: 2.在你的 Dart 代码中,导入 contacts_service 插件: 3.权限请求: Android 需要在 android/app/src/main/AndroidManifest.xml 文件中添加以下内容: IOS 需要在 ios/Runner/Info.plist 文件中添加以下内容: 在ios系统上如果进行

    2024年02月08日
    浏览(53)
  • Flutter与Android开发:构建跨平台移动应用的新选择

    本文内容提纲如下: 介绍Flutter技术:Flutter是一种由Google推出的开源UI工具包,用于构建高性能、跨平台的移动应用。文章将介绍Flutter的基本概念、特点和优势,包括其快速的开发速度、一致的用户界面和丰富的UI组件库等。 Flutter与Android开发的对比:文章将对比Flutter与传统

    2023年04月21日
    浏览(186)
  • 【flutter】使用permission_handler配置android和 iOS的权限

    flutter在pub.flutter-io.cn插件库中有很多的关于权限配置的插件,但是就我个人而言,比较推荐使用permission_handler这个插件。当我们打开permission_handler时候,往往新手小白会因为它的官网文档而弄的一头雾水,权限配置往往涉及到android和ios两个方向的相关知识,有可能大多数人就

    2024年02月12日
    浏览(43)
  • Flutter视频播放器在iOS端和Android端都能实现全屏播放

    Flutter开发过程中,对于视频播放的三方组件有很多,在Android端适配都挺好,但是在适配iPhone手机的时候,如果设置了 UIInterfaceOrientationLandscapeLeft 和 UIInterfaceOrientationLandscapeRight 都为false的情况下,无法做到全屏播放,因为FLutter的 SystemChrome.setPreferredOrientations 方法不适配iOS端

    2024年02月05日
    浏览(47)
  • flutter实现下拉菜单组件——基于PopupMenuButton

    客户端日常开发和学习过程,下拉菜单是一个很常见的组件,本文主要介绍flutter中实现下拉菜单组件的一个方案,基于PopupMenuButton来进行实现。 PopupMenuButton PopupMenuButton 是一个非常常见的弹出菜单栏。 属性介绍: 话不多说,直接上代码 (1)新建MenuItem.dart通用菜单项类,代码

    2024年02月07日
    浏览(66)
  • flutter实现下拉框功能——基于DropdownButtonFormField

    客户端日常开发和学习过程,下拉框是一个很常见的组件,本文主要介绍flutter中实现下拉框的一个方案,基于DropdownButtonFormField来进行实现。 DropdownButtonFormField 是一个组合控件,将[DropdownButton]包装在[FormField]中,用法如下: 话不多说,直接上代码,实现下拉框的完整代码如

    2024年02月12日
    浏览(46)
  • 【Flutter】Flutter 使用 pull_to_refresh 实现下拉刷新和上拉加载

    【Flutter】Flutter 使用 pull_to_refresh 实现下拉刷新和上拉加载 你好!在移动开发中,下拉刷新和上拉加载是非常常见的功能。 今天,我将为你介绍一个非常实用的 Flutter 包—— pull_to_refresh 。在这篇文章中,我们将学习如何使用这个包,以及如何在实际业务中应用它。 文章的重

    2024年02月07日
    浏览(42)
  • Flutter 使用bloc模拟首页实现下拉刷新

    思考:这篇文章主要是记录bloc与下拉刷新功能的使用 本篇文章是延续上一篇文章中所包含的bloc和自定义http库的使用,使用发现在上一篇文章中对bloc的理解有些误区导致最后实现好几个方式都感觉不尽人意,最终尝试查看官方示例与个人示例进行比对后发现了问题所在, 下面

    2024年02月11日
    浏览(38)
  • flutter开发实战-下拉刷新与上拉加载更多实现

    flutter开发实战-下拉刷新与上拉加载更多实现 在开发中经常遇到列表需要下拉刷新与上拉加载更多,这里使用EasyRefresh,版本是3.3.2+1 EasyRefresh可以在Flutter应用程序上轻松实现下拉刷新和上拉加载。它几乎支持所有Flutter Scrollable小部件。它的功能与安卓的SmartRefreshLayout非常相似

    2024年02月07日
    浏览(44)
  • Flutter 库:强大的下拉刷新上拉加载框架——EasyRefresh

    EasyRefresh 是一个用于 Flutter 应用程序的简单易用的 下拉刷新 和 上拉加载 框架。它支持几乎所有的 Flutter 可滚动小部件。它的功能与Android 的 SmartRefreshLayout 非常相似,并吸收了许多第三方库的优点。EasyRefresh 集成了各种样式的页眉和页脚,但没有任何限制,您可以轻松自定

    2024年01月19日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包