Flutter自定义底部选择器插件custom_bottom_picker的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter自定义底部选择器插件 custom_bottom_picker 的使用

custom_bottom_picker 是一个强大的 Flutter 插件,允许开发者轻松实现自定义的底部选择器。该插件不仅支持文本列表的选择,还支持自定义 Widget 列表的选择,并且可以同时显示多个项目。

特性

  • 文本选择器
  • 自定义 Widget 选择器
  • 支持多列选择(文本和 Widget)
  • 可定制颜色

示例效果

手机端 平板端
手机端 平板端

开始使用

添加依赖

在你的 pubspec.yaml 文件中添加以下依赖:

dependencies:
  custom_bottom_picker: 1.0.1

然后运行 flutter pub get 来安装依赖。

基本用法

以下是一个简单的示例,展示如何使用 custom_bottom_picker 实现一个国家选择器:

import 'package:custom_bottom_picker/custom_bottom_picker.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Bottom Picker Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        scaffoldBackgroundColor: const Color.fromARGB(255, 235, 235, 241),
        useMaterial3: false,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int countryIndex = 8;
  final List<String> countryData = [
    'America',
    'Austria',
    'Canada',
    'Egypt',
    'France',
    'Greece',
    'India',
    'Indonesia',
    'Japan',
    'Malaysia',
    'South Africa',
    'Spain',
    'Viet Nam',
  ];

  void showCountry() async {
    final result = await showCustomBottomPicker(
      context: context,
      options: const CustomBottomPickerOptions(
        pickerTitle: 'Country',
      ),
      sections: [
        CustomBottomPickerSection.list(
          id: 'country',
          defaultIndex: countryIndex,
          children: countryData,
        ),
      ],
    );
    if (result != null) {
      setState(() => countryIndex = result.getById('country')!);
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Custom Bottom Picker Demo'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: showCountry,
          child: const Text('Select Country'),
        ),
      ),
    );
  }
}

参数说明

showCustomBottomPicker 方法参数

  • sections: 定义要显示在选择器中的每一列的信息。
  • options: 用于自定义选择器的外观,如背景颜色、文本颜色等。
  • radius: 设置模态框顶部两边的圆角半径,默认为 24。

CustomBottomPickerSection

  • id: 标识选择器中的某一段。
  • children: 文本列表,用于普通文本显示。
  • itemBuilder: 如果你想使用自己的 Widget 作为项,则需要指定此函数。

CustomBottomPickerOptions

  • backgroundColor: 背景颜色,默认是 Theme.of(context).scaffoldBackgroundColor
  • foregroundColor: 前景色,默认是 Theme.of(context).cardColor
  • textColor: 文本颜色,默认是 Theme.of(context).textTheme.bodyLarge?.color
  • activeColor: 当前选中的日期或按钮的颜色,默认是 Theme.of(context).primaryColor
  • pickerTitle: 显示在选择器顶部的标题。

返回值

选择器的返回值类型是 CustomBottomPickerResult,它继承自 List,因此也可以像普通列表一样获取值。

CustomBottomPickerResult? result = await showCustomBottomPicker(...);

// 获取第一个项目的值
result![0];

// 使用指定的 ID 获取结果
result!.getById('country');

完整示例 Demo

下面是一个完整的示例 Demo,展示了如何使用 custom_bottom_picker 实现国家选择器、环境和日志级别选择器以及自定义 Widget 选择器。

import 'package:custom_bottom_picker/custom_bottom_picker.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Bottom Picker Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        scaffoldBackgroundColor: const Color.fromARGB(255, 235, 235, 241),
        useMaterial3: false,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int countryIndex = 8;
  List<String> countryData = [
    'America',
    'Austria',
    'Canada',
    'Egypt',
    'France',
    'Greece',
    'India',
    'Indonesia',
    'Japan',
    'Malaysia',
    'South Africa',
    'Spain',
    'Viet Nam',
  ];

  int logLevelIndex = 2;
  List<String> logLevels = ['Debug', 'Info', 'Warning', 'Error', 'Fatal'];

  int envIndex = 1;
  List<String> envs = ['Test', 'Develop', 'Staging', 'Production'];

  static Widget widgetRow(BuildContext context, String text, Color color) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Icon(Icons.stop_rounded, color: color, size: 28),
        const SizedBox(width: 8),
        Text(
          text,
          style: Theme.of(context).textTheme.bodySmall?.copyWith(
                fontWeight: FontWeight.bold,
                fontSize: 17,
              ),
        ),
        Container(
          margin: const EdgeInsets.symmetric(horizontal: 16),
          height: 2,
          width: 64,
          decoration: BoxDecoration(color: color),
        ),
        Icon(Icons.account_circle_rounded, color: color),
      ],
    );
  }

  int widgetIndex = 2;
  late List<Widget> widgets = [
    widgetRow(context, 'Debug', Colors.grey),
    widgetRow(context, 'Info', Colors.blue),
    widgetRow(context, 'Warning', Colors.orange),
    widgetRow(context, 'Error', Colors.red),
    widgetRow(context, 'Critical', Colors.purple),
  ];

  void showCountry() async {
    final result = await showCustomBottomPicker(
      context: context,
      options: const CustomBottomPickerOptions(pickerTitle: 'Country'),
      sections: [
        CustomBottomPickerSection.list(
          id: 'country',
          defaultIndex: countryIndex,
          children: countryData,
        ),
      ],
    );
    if (result != null) {
      setState(() => countryIndex = result.getById('country')!);
    }
  }

  void showEnvLog() async {
    final result = await showCustomBottomPicker(
      context: context,
      options: const CustomBottomPickerOptions(pickerTitle: 'Log Level'),
      sections: [
        CustomBottomPickerSection.list(
          id: 'env',
          title: 'Environment',
          flex: 3,
          defaultIndex: envIndex,
          children: envs,
        ),
        CustomBottomPickerSection.list(
          id: 'level',
          title: 'Level',
          flex: 2,
          defaultIndex: logLevelIndex,
          children: logLevels,
        ),
      ],
    );
    if (result != null) {
      setState(() {
        envIndex = result.getById('env')!;
        logLevelIndex = result.getById('level')!;
      });
    }
  }

  void showWidgets() async {
    final result = await showCustomBottomPicker(
      context: context,
      options: const CustomBottomPickerOptions(pickerTitle: 'Log Level'),
      sections: [
        CustomBottomPickerSection.builder(
          id: 'widget',
          flex: 3,
          defaultIndex: envIndex,
          itemCount: widgets.length,
          itemBuilder: (context, index) {
            return widgets[index];
          },
        ),
      ],
    );
    if (result != null) {
      setState(() {
        widgetIndex = result.getById('widget')!;
      });
    }
  }

  Widget button(String text, void Function() onTap) {
    return Material(
      borderRadius: BorderRadius.circular(12),
      color: Theme.of(context).cardColor,
      clipBehavior: Clip.antiAlias,
      child: InkWell(
        onTap: onTap,
        child: Container(
          height: 48,
          width: 240,
          alignment: Alignment.center,
          child: Text(
            text,
            style: Theme.of(context).textTheme.bodyMedium,
          ),
        ),
      ),
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: <Widget>[
            Container(
              height: 240,
              alignment: Alignment.center,
              child: Text(
                'Custom Bottom Picker',
                style: Theme.of(context)
                    .textTheme
                    .headlineSmall
                    ?.copyWith(fontWeight: FontWeight.bold),
              ),
            ),
            button(
              'Country: ${countryData[countryIndex]}',
              showCountry,
            ),
            const SizedBox(height: 24),
            button(
              'LogLevel: ${envs[envIndex]} - ${logLevels[logLevelIndex]}',
              showEnvLog,
            ),
            const SizedBox(height: 24),
            button(
              'Widgets builder',
              showWidgets,
            ),
            const SizedBox(height: 24),
          ],
        ),
      ),
    );
  }
}

更多关于Flutter自定义底部选择器插件custom_bottom_picker的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义底部选择器插件custom_bottom_picker的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用custom_bottom_picker插件的示例代码。这个插件允许你创建一个自定义的底部选择器,非常适合用于日期选择、时间选择或者任何需要底部弹出选择器的场景。

首先,确保你已经在pubspec.yaml文件中添加了custom_bottom_picker依赖:

dependencies:
  flutter:
    sdk: flutter
  custom_bottom_picker: ^最新版本号  # 请替换为实际发布的最新版本号

然后,运行flutter pub get来获取依赖。

接下来是一个简单的示例代码,展示如何使用custom_bottom_picker

import 'package:flutter/material.dart';
import 'package:custom_bottom_picker/custom_bottom_picker.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _selectedValue = '请选择';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Custom Bottom Picker Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _selectedValue,
              style: TextStyle(fontSize: 24),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                showPicker(context);
              },
              child: Text('打开选择器'),
            ),
          ],
        ),
      ),
    );
  }

  void showPicker(BuildContext context) {
    List<String> items = ['选项1', '选项2', '选项3', '选项4', '选项5'];
    showCustomBottomPicker(
      context: context,
      builder: (context) {
        return CustomBottomPicker(
          itemCount: items.length,
          itemBuilder: (context, index) {
            return Container(
              alignment: Alignment.center,
              child: Text(items[index]),
            );
          },
          onConfirm: (index) {
            setState(() {
              _selectedValue = items[index];
            });
            Navigator.of(context).pop();
          },
        );
      },
    );
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮和一个文本显示区域。当用户点击按钮时,会弹出一个底部选择器。选择器的选项是预定义的字符串列表。当用户选择一个选项并点击确认时,选择的选项会显示在文本区域中。

关键部分是showPicker函数,它使用showCustomBottomPicker方法来显示选择器。CustomBottomPicker小部件通过itemBuilder回调来构建每个选项的UI,并通过onConfirm回调来处理用户的选择。

这个示例提供了一个基本的框架,你可以根据自己的需求进一步自定义和扩展它,比如添加更多的样式、处理更复杂的数据等。

回到顶部