Flutter轮盘选择插件fl_list_wheel的使用

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

Flutter轮盘选择插件fl_list_wheel的使用

在本指南中,我们将详细介绍如何使用 fl_list_wheel 插件来创建轮盘选择器。该插件提供了多种类型的轮盘选择器,包括日期选择器、时间选择器和多列表联动选择器等。

运行 Web 示例

要运行 Web 示例,请访问以下链接:

所有组件

以下是 fl_list_wheel 中所有可用的组件:

final picker = [
  /// FlListWheel
  FlListWheel.builder(),

  /// FlListWheel
  FlListWheel.count(),

  /// FlListWheelState
  FlListWheelState.builder(),

  /// FlListWheelState
  FlListWheelState.count(),

  /// 日期选择器
  DatePicker(),

  /// 日期时间选择器
  DateTimePicker(),

  /// 多列表联动选择器
  MultiListLinkagePicker(),

  /// 多列表轮盘联动选择器
  MultiListWheelLinkagePicker(),

  /// 单列表选择器
  SingleListPicker(),

  /// 单列表轮盘选择器
  SingleListWheelPicker(),
];

如果使用 show 方法必须初始化以下两个方法

如果你打算使用 show 方法,你必须初始化以下两个方法:

[@override](/user/override)
void initState() {
  super.initState();
  FlListWheel.push = (Widget picker) {
    return showModalBottomSheet(
        context: context,
        shape: const RoundedRectangleBorder(
            borderRadius: BorderRadius.vertical(top: Radius.circular(4))),
        builder: (_) => picker);
  };
  FlListWheel.pop = (dynamic value) {
    return Navigator.of(context).pop(value);
  };
}

FlListWheelFlListWheelState

FlListWheelState 可以自己管理 FixedExtentScrollController init 和 dispose

Widget build() {
  return ListView(children: [
    FlListWheel.builder(
        onSelectedItemChanged: (_) {
          debugPrint('ListWheel.builder : $_');
        },
        itemBuilder: (_, int index) => Text(numberList[index]),
        itemCount: numberList.length),

    FlListWheel.count(
        options: const WheelOptions(),
        onSelectedItemChanged: (_) {
          debugPrint('ListWheel.count : $_');
        },
        children: numberList.map((item) => Text(item)).toList()),

    FlListWheelState(
        count: numberList.length,
        initialItem: 5,
        builder: (_) =>
            FlListWheel.builder(
                controller: _,
                onSelectedItemChanged: (_) {
                  debugPrint('ListWheelState.builder : $_');
                },
                itemBuilder: (_, int index) => Text(numberList[index]),
                itemCount: numberList.length)),
    FlListWheelState(
        initialItem: 5,
        count: numberList.length,
        builder: (_) =>
            FlListWheel.count(
                controller: _,
                options: const WheelOptions(),
                onSelectedItemChanged: (_) {
                  debugPrint('ListWheelState.builder : $_');
                },
                children: numberList.map((item) => Text(item)).toList()))
  ]);
}

日期选择器

void func() {
  DatePicker().show();
}

Widget build() {
  return DatePicker(
      height: 200,
      startDate: defaultDate.subtract(const Duration(days: 365)),
      endDate: defaultDate.add(const Duration(days: 365)),
      defaultDate: defaultDate,
      options: options,
      onChanged: (DateTime dateTime) {
        debugPrint(dateTime.toString());
      },
      itemBuilder: (String text) => Text(text, style: const TextStyle(fontSize: 16)),
      unit: const DatePickerUnit.yd(year: '年', day: '日', month: '月'));
}

日期时间选择器

void func() {
  DateTimePicker().show();
}

Widget build() {
  return DateTimePicker(
      options: BasePickerOptions<DateTime>().merge(PickerOptions<DateTime>(
          contentPadding: const EdgeInsets.symmetric(horizontal: 12),
          verifyConfirm: (DateTime? dateTime) {
            debugPrint(dateTime?.toString() ?? 'verifyConfirm');
            return true;
          },
          verifyCancel: (DateTime? dateTime) {
            debugPrint(dateTime?.toString() ?? 'verifyCancel');
            return true;
          })),
      startDate: defaultDate.subtract(const Duration(days: 365)),
      defaultDate: defaultDate,
      endDate: defaultDate.add(const Duration(days: 365)),
      onChanged: (DateTime dateTime) {
        debugPrint(dateTime.toString());
      },
      height: 200,
      unit: const DateTimePickerUnit.yd(year: '年', month: '', day: ''));
}

区域选择器

void func() {
  Future<void> pick() async {
    final items = mapToLinkageItems(areaDataMap);
    final position = await MultiListWheelLinkagePicker<String>(
        wheelOptions: const WheelOptions.cupertino(),
        height: 200,
        onChanged: (List<int> index) {
          debugPrint('AreaPicker onChanged= $index');
        },
        onValueChanged: (List<String> list) {
          debugPrint('AreaPicker onValueChanged= $list');
        },
        items: mapToLinkageItems(areaDataMap),
        isScrollable: false)
        .show();
    if (position == null) return;
    List<String> value = [];
    List<PickerLinkageItem> resultList = items;
    position.map((index) {
      if (index < resultList.length) {
        value.add(resultList[index].value);
        resultList = resultList[index].children;
      }
    }).toList();
    debugPrint(value.toString());
  }
}

Widget build() {
  return MultiListWheelLinkagePicker<String>(
      options: options,
      wheelOptions: const WheelOptions.cupertino(),
      height: 200,
      onChanged: (List<int> index) {
        debugPrint('AreaPicker onChanged= $index');
      },
      onValueChanged: (List<String> list) {
        debugPrint('AreaPicker onValueChanged= $list');
      },
      items: mapToLinkageItems(areaDataMap),
      isScrollable: false);
}

完整示例代码

以下是一个完整的示例代码,展示了如何使用 fl_list_wheel 插件来创建一个简单的轮盘选择器页面。

import 'package:device_preview_minus/device_preview_minus.dart';
import 'package:example/src/list_wheel_page.dart';
import 'package:example/src/picker/area_picker.dart';
import 'package:example/src/picker/date_picker.dart';
import 'package:example/src/picker/date_time_picker.dart';
import 'package:example/src/picker/multi_list_linkage_picker.dart';
import 'package:example/src/picker/multi_list_wheel_linkage_picker.dart';
import 'package:example/src/picker/multi_list_wheel_picker.dart';
import 'package:example/src/picker/single_list_picker.dart';
import 'package:example/src/picker/single_list_wheel_picker.dart';
import 'package:fl_list_wheel/fl_list_wheel.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(DevicePreview(
      enabled: kIsWeb,
      defaultDevice: Devices.ios.iPhone13Mini,
      builder: (context) => MaterialApp(
          locale: DevicePreview.locale(context),
          theme: ThemeData.light(),
          darkTheme: ThemeData.dark(),
          debugShowCheckedModeBanner: false,
          builder: (BuildContext context, Widget? child) {
            return DevicePreview.appBuilder(context, child);
          },
          home: Scaffold(
              appBar: AppBar(title: const Text('FlScrollView')),
              body: const HomePage()))));
}

const List<Color> colorList = [
  ...Colors.accents,
  ...Colors.primaries,
];

class AppBarText extends AppBar {
  AppBarText(String text, {super.key})
      : super(
            elevation: 0,
            title: Text(text,
                style:
                    const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            centerTitle: true);
}

class ElevatedText extends StatelessWidget {
  const ElevatedText(this.text, {this.onTap, super.key});

  final VoidCallback? onTap;
  final String text;

  [@override](/user/override)
  Widget build(BuildContext context) {
    final current = ElevatedButton(onPressed: onTap, child: Text(text));
    if (defaultTargetPlatform == TargetPlatform.android &&
        defaultTargetPlatform == TargetPlatform.iOS) return current;
    return Padding(padding: const EdgeInsets.all(10), child: current);
  }
}

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

  [@override](/user/override)
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  [@override](/user/override)
  void initState() {
    super.initState();
    FlListWheel.push = (Widget picker) {
      return showModalBottomSheet(
          context: context,
          shape: const RoundedRectangleBorder(
              borderRadius: BorderRadius.vertical(top: Radius.circular(4))),
          builder: (_) => picker);
    };
    FlListWheel.pop = (dynamic value) {
      return Navigator.of(context).pop(value);
    };
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ListView(
        padding: const EdgeInsets.symmetric(horizontal: 10),
        children: [
          ElevatedText('FlListWheel', onTap: () {
            push(const ListWheelPage());
          }),
          ElevatedText('DatePicker', onTap: () {
            push(DatePickerPage());
          }),
          ElevatedText('DateTimePicker', onTap: () {
            push(DateTimePickerPage());
          }),
          ElevatedText('AreaPicker', onTap: () {
            push(const AreaPickerPage());
          }),
          ElevatedText('MultiListLinkagePicker', onTap: () {
            push(const MultiListLinkagePickerPage());
          }),
          ElevatedText('MultiListWheelPicker', onTap: () {
            push(const MultiListWheelPickerPage());
          }),
          ElevatedText('MultiListWheelLinkagePicker', onTap: () {
            push(const MultiListWheelLinkagePickerPage());
          }),
          ElevatedText('SingleListPicker', onTap: () {
            push(const SingleListPickerPage());
          }),
          ElevatedText('SingleListWheelPicker', onTap: () {
            push(const SingleListWheelPickerPage());
          }),
          ElevatedText('show CustomPicker', onTap: customPicker),
        ]);
  }

  Future<void> customPicker() async {
    Widget picker = CustomPicker<String>(
        options: PickerOptions<String>(
            decoration: const BoxDecoration(
                color: Colors.red,
                borderRadius: BorderRadius.vertical(top: Radius.circular(10))),
            verifyConfirm: (String? value) {
              debugPrint('verifyConfirm $value');
              return true;
            },
            verifyCancel: (String? value) {
              debugPrint('verifyCancel $value');
              return true;
            },
            title: Container(
                alignment: Alignment.center,
                padding:
                    const EdgeInsets.symmetric(horizontal: 10, vertical: 2),
                decoration: BoxDecoration(
                    color: Colors.lightBlue,
                    borderRadius: BorderRadius.circular(6)),
                child: const Text('Title'))),
        content: Container(
            height: 300,
            alignment: Alignment.center,
            color: Colors.blue.withOpacity(0.2),
            child: const Text('showCustomPicker',
                style: TextStyle(color: Colors.black))),
        confirmTap: () {
          return 'Confirm';
        },
        cancelTap: () {
          return 'Cancel';
        });
    final String? data = await showModalBottomSheet<String?>(
        context: context, builder: (_) => picker);
    debugPrint(data);
  }

  void push(Widget widget) {
    showCupertinoModalPopup(context: context, builder: (_) => widget);
  }
}

class ExtendedScaffold extends StatelessWidget {
  const ExtendedScaffold(
      {super.key, this.appBar, this.children = const [], this.padding});

  final AppBar? appBar;
  final List<Widget> children;
  final EdgeInsetsGeometry? padding;

  [@override](/user/override)
  Widget build(BuildContext context) {
    Widget current = ListView(children: children);
    if (padding != null) {
      current = Padding(padding: padding!, child: current);
    }

    return Scaffold(appBar: appBar, body: current);
  }
}

更多关于Flutter轮盘选择插件fl_list_wheel的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter轮盘选择插件fl_list_wheel的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter中使用fl_list_wheel插件来实现轮盘选择的示例代码。这个插件允许你创建一个类似于iOS的PickerView的组件,非常适合用于日期选择、选项轮盘等场景。

首先,你需要在你的pubspec.yaml文件中添加fl_list_wheel依赖:

dependencies:
  flutter:
    sdk: flutter
  fl_list_wheel: ^0.1.0  # 请检查最新版本号并替换

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

接下来是一个简单的示例代码,展示了如何使用fl_list_wheel创建一个基本的轮盘选择组件:

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

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

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

class ListWheelPage extends StatefulWidget {
  @override
  _ListWheelPageState createState() => _ListWheelPageState();
}

class _ListWheelPageState extends State<ListWheelPage> {
  final List<String> items = List<String>.generate(20, (index) => "Item $index");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter List Wheel Example'),
      ),
      body: Center(
        child: ListWheelScrollView(
          children: items.map((item) {
            return ListWheelChildBuilderDelegate(
              builder: (context, index) {
                return Center(
                  child: Text(
                    items[index],
                    style: TextStyle(fontSize: 24),
                  ),
                );
              },
              childCount: items.length,
            ).build(context, 0);  // 这里的0是初始位置索引,实际使用中通常不需要传递
          }).toList(),
          physics: FixedExtentScrollPhysics(),
          itemExtent: 50.0,  // 每个item的高度
        ),
      ),
    );
  }
}

注意:上面的代码中有几个需要注意的点:

  1. ListWheelScrollView:这是主要的轮盘组件,它接受一个或多个子组件。在这个例子中,我们使用了ListWheelChildBuilderDelegate来动态生成子组件。

  2. ListWheelChildBuilderDelegate:这个委托类用于按需构建子组件,避免一次性构建所有子组件带来的性能开销。builder函数定义了如何构建每个子组件,而childCount指定了总共有多少个子组件。

  3. itemExtent:定义了每个子组件在轮盘中的垂直或水平占据的空间大小。

  4. FixedExtentScrollPhysics:为轮盘提供了固定的滚动物理效果,使得每次滚动都定位到一个子组件的中心。

错误:上面的代码实际上有一个问题,即ListWheelScrollView不能直接接受一个ListWheelChildBuilderDelegate作为子组件。正确的做法是将ListWheelChildBuilderDelegate传递给ListWheelScrollViewchildDelegate属性。下面是修正后的代码:

import 'package:flutter/material.dart';
import 'package:fl_list_wheel/fl_list_wheel.dart';  // 注意:实际中可能没有这个包,请使用flutter_list_wheel或其他有效包

// ...(省略main函数和MyApp类)

class _ListWheelPageState extends State<ListWheelPage> {
  final List<String> items = List<String>.generate(20, (index) => "Item $index");

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter List Wheel Example'),
      ),
      body: Center(
        child: ListWheelScrollView.useDelegate(
          childDelegate: ListWheelChildBuilderDelegate(
            builder: (context, index) {
              return Center(
                child: Text(
                  items[index],
                  style: TextStyle(fontSize: 24),
                ),
              );
            },
            childCount: items.length,
          ),
          itemExtent: 50.0,
          physics: FixedExtentScrollPhysics(),
        ),
      ),
    );
  }
}

注意ListWheelScrollView.useDelegate可能不是实际API的一部分,这里只是为了说明childDelegate的使用方式。实际使用中,你应该查看fl_list_wheel或类似插件的文档,使用正确的API和方法。如果fl_list_wheel不是你要找的包,请考虑使用flutter_list_wheel_view或其他类似的包。

希望这个示例能帮助你开始在Flutter项目中使用轮盘选择组件!

回到顶部