Flutter 列表选择器

需求

例如时间,国家地区码选择、日期选择,需要在列表中滑动只选择最中间的选项,单纯的 ListWheelScrollViewCupertinoPicker 都无法直接满足样式需求。

效果

效果图

组件代码

import 'dart:math';

import 'package:bubble_mobile/util/color_utils.dart';
import 'package:bubble_mobile/util/size_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class ListPick extends StatefulWidget {
  final int defaultIndex;
  final double itemExtend;
  final List<String> itemList;
  final ValueChanged<int> onSelectedItemChanged;
  final Color backgroundColor;
  final Color selectBackgroundColor;
  final Color selectFroegroundColor;
  final double textSize;
  final Color selectTextColor;
  final Color unselectTextColor;
  final BorderRadiusGeometry borderRadius;

  ListPick(
      {super.key,
      required this.defaultIndex,
      required this.itemExtend,
      required this.itemList,
      required this.onSelectedItemChanged,
      this.backgroundColor = ColorUtils.enableBackground,
      this.selectBackgroundColor = ColorUtils.mainTheme,
      this.selectFroegroundColor = ColorUtils.enableBackground,
      this.textSize = SizeUtils.fontBody,
      this.selectTextColor = ColorUtils.enableBackground,
      this.unselectTextColor = ColorUtils.commonFont,
      BorderRadiusGeometry? borderRadius})
      : assert(itemList.isNotEmpty),
        borderRadius =
            borderRadius ?? BorderRadius.circular(SizeUtils.blockWidth * 4);

  @override
  State<ListPick> createState() => _ListPickState();
}

class _ListPickState extends State<ListPick> {
  late int _currentSelectIndex;

  @override
  void initState() {
    super.initState();
    _currentSelectIndex = min(widget.defaultIndex, widget.itemList.length - 1);
  }

  @override
  Widget build(BuildContext context) {
    _currentSelectIndex = min(_currentSelectIndex, widget.itemList.length - 1);
    return Stack(
      children: [
        Positioned.fill(
            child: Container(
                color: widget.backgroundColor,
                child: Center(
                    child: Container(
                  height: widget.itemExtend,
                  decoration: BoxDecoration(
                    borderRadius: widget.borderRadius,
                    color: widget.selectBackgroundColor,
                  ),
                )))),
        Positioned.fill(
            child: ListWheelScrollView.useDelegate(
                controller: FixedExtentScrollController(
                    initialItem: _currentSelectIndex),
                physics: const FixedExtentScrollPhysics(),
                squeeze: 1,
                itemExtent: widget.itemExtend,
                onSelectedItemChanged: (value) {
                  setState(() {
                    _currentSelectIndex = value;
                  });
                  HapticFeedback.lightImpact();
                  widget.onSelectedItemChanged.call(value);
                },
                childDelegate: ListWheelChildBuilderDelegate(
                    childCount: widget.itemList.length,
                    builder: ((context, index) {
                      return Center(
                          child: Text(widget.itemList[index],
                              style: TextStyle(
                                  fontSize: widget.textSize,
                                  color: _currentSelectIndex == index
                                      ? widget.selectTextColor
                                      : widget.unselectTextColor)));
                    }))))
      ],
    );
  }
}

使用

ListPick(
  defaultIndex: _selectedCountryIndex ?? 0,
  itemExtend: SizeUtils.blockHeight * 6,
  onSelectedItemChanged: (value) => _selectedCountryIndex = value,
  itemList: _countryList!
      .map((e) => "+${e.phoneCode} | ${e.localName}")
      .toList(),
))
posted @ 2022-10-11 00:35  seliote  阅读(158)  评论(0)    收藏  举报