You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建带InkWell的特定样式Flutter下拉按钮

自定义Flutter下拉按钮实现

以下是符合需求的完整实现代码,包含自定义下拉触发区域、选中状态UI更新和选中项高亮:

import 'package:flutter/material.dart';

class CustomDropdown extends StatefulWidget {
  const CustomDropdown({super.key});

  @override
  State<CustomDropdown> createState() => _CustomDropdownState();
}

class _CustomDropdownState extends State<CustomDropdown> {
  // 选项列表
  final List<String> options = ['选项1', '选项2', '选项3', '选项4'];
  // 保存选中的选项,初始为null表示未选择
  String? selectedOption;

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        // 左侧文本
        const Text('选择选项:'),
        const SizedBox(width: 8),
        // AssetImage(请确保已在pubspec.yaml中配置对应资源)
        Image.asset(
          'assets/icon.png',
          width: 24,
          height: 24,
        ),
        const SizedBox(width: 8),
        // 下拉触发区域InkWell
        InkWell(
          onTap: () => _showOptionsMenu(context),
          child: Container(
            padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
            decoration: BoxDecoration(
              border: Border.all(color: Colors.grey),
              borderRadius: BorderRadius.circular(4),
            ),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                // 显示选中的文本或默认提示
                Text(
                  selectedOption ?? '请选择',
                  style: TextStyle(
                    color: selectedOption != null ? Colors.black : Colors.grey,
                  ),
                ),
                const SizedBox(width: 8),
                // 根据选中状态切换图标
                Icon(
                  selectedOption != null ? Icons.check : Icons.arrow_drop_down,
                  color: selectedOption != null ? Colors.green : Colors.grey,
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }

  // 弹出选项菜单
  void _showOptionsMenu(BuildContext context) async {
    final RenderBox renderBox = context.findRenderObject() as RenderBox;
    final Offset offset = renderBox.localToGlobal(Offset.zero);
    final String? result = await showMenu<String>(
      context: context,
      position: RelativeRect.fromLTRB(
        offset.dx,
        offset.dy + renderBox.size.height,
        offset.dx + renderBox.size.width,
        offset.dy + renderBox.size.height + 200,
      ),
      items: options.map((option) {
        return PopupMenuItem<String>(
          value: option,
          child: Text(
            option,
            // 选中项显示红色
            style: TextStyle(
              color: selectedOption == option ? Colors.red : Colors.black,
            ),
          ),
        );
      }).toList(),
    );

    // 更新选中状态
    if (result != null) {
      setState(() {
        selectedOption = result;
      });
    }
  }
}

// 用于测试的主函数
void main() => runApp(const MaterialApp(home: Scaffold(body: Center(child: CustomDropdown()))));

关键实现细节说明:

  • 状态管理:通过selectedOption变量跟踪选中的选项,调用setState更新UI
  • InkWell触发区域:自定义了带边框的容器,根据选中状态切换显示的文本和图标(未选时显示下拉箭头,选中时显示对勾)
  • 弹出菜单:使用showMenu方法在指定位置弹出选项列表,通过RelativeRect控制菜单的显示位置
  • 选中项高亮:在PopupMenuItem中判断当前选项是否为选中状态,若是则设置文本颜色为红色
  • AssetImage配置:请确保在pubspec.yaml中添加资源路径,示例配置如下:
    assets:
      - assets/icon.png
    

内容的提问来源于stack exchange,提问作者farhan khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 14:10:12