只有记在脑海里的才是自己的,如果还没来得及,请写下来
FxPickerView 实现省市区类似的多级联动PickerView,最多支持4级联动
2020-11-12 / 4 min read

效果:

1:布局说明

1.1:FxPickerView 多级联动的PickerView

  /// [title] 选择器的标题
  /// [selectController] 控制器(提供数据源,提供外部控制选中行)
  /// [selectedCallBack] 选中回调
  FxPickerView({
    Key key,
    this.title,
    @required this.selectedCallBack,
    @required this.selectController
  }) : super(key: key);

1.2:FxPickerController 提供数据源,外部控制api

  • 数据源说明:
    FxPkInfo:每个可滚动的item对象
  /// [id] 唯一标识
  /// [name] 显示的名称
  FxPkInfo({
    this.id,
    this.name
  });
  • 数据源说明:
    FxPkItemsInfo:包含第二级列表的数据源,为了实现联动效果,比如省后面包含市,需要在 items中设置省对应的市的数据源
  /// [items] 对应的二级数据源,比如省下面的市
  FxPkItemsInfo({
    String id,
    String name,
    List<FxPkInfo> items
  }) :  items = items ?? [],
        super(id: id, name: name);

FxPickerController 提供 dataSource 设置FxPickerView的数据源,pickerScrollControllers保存了每列的控制器,外部可以获取控制器去控制FxPickerView的选择行

  /// [sectionCount] 指定 FxPickerView 多少列,默认1列,省市区则为3列,最大4列
  /// [defSelectedIdOrNames] 指定默认选中的行,提供id或者name去判断 ['id1', 'id2', 'id3']
  FxPickerController({
    this.sectionCount = 1,
    List<String> defSelectedIdOrNames,
  }) : assert(sectionCount < 5 && sectionCount > 0),
      _initSelectedIdOrNames = defSelectedIdOrNames ?? []

2:使用事列

2.1:布局参考

底部弹出的布局,需要使用Stack来实现图层覆盖,Offstage控制弹框的显示与隐藏

@override
  Widget build(BuildContext context) {
    return Stack(
        children: [
          Positioned.fill(
            child: Column(
              children: [
                RaisedButton(
                  child: Text(name111),
                  onPressed: () {
                    print('xxxxxxx');
                    updateData();
                  },
                ),
              ],
            ),
          ),
          Positioned.fill(
            child: Offstage(
              offstage: bottomHiddenPicker,
              child: FxPickerView(
                title: '选取区域',
                selectController: fxPickerSelectController,
                selectedCallBack: (selecteds) {
                  setState(() {
                    bottomHiddenPicker = true;
                  });
                  if (selecteds == null || selecteds.length == 0) {
                    return;
                  }
                  List<String> listNames = [];
                  for (FxPkInfo info in selecteds) {
                    listNames.add(info.name);
                  }
                  setState(() {
                    name111 = listNames.join(',');
                  });
                }
              )
            ),
          )
        ],
      );

2.2:数据源参考

  • 注意:
    sectionCount 指定显示多少列与数据源定义的结构一致;
    defSelectedIdOrNames 可传,指定默认选中的行
    FxPkItemsInfo 结构表示 存在 二级 数据源
    FxPkInfo 结构表示 不存在二级 数据源
@override
  void initState() {
    super.initState();
    fxPickerSelectController = FxPickerController(
      sectionCount: 3,
      defSelectedIdOrNames: ['2', '23']
    );
    fxPickerSelectController.dataSource = [ 
      FxPkItemsInfo(id: '1', name: '浙江省', items: [
        FxPkItemsInfo(id: '11', name: '杭州市', items: [ 
          FxPkInfo(id: '111', name: '1区'),
          FxPkInfo(id: '112', name: '2区'),
          FxPkInfo(id: '113', name: '3区'),
          FxPkInfo(id: '114', name: '4区')]), 
        FxPkItemsInfo(id: '12', name: '宁波市', items: [
          FxPkInfo(id: '121', name: '5区'),
          FxPkInfo(id: '122', name: '6区')]),
        FxPkItemsInfo(id: '13', name: '金华市', items: [ 
          FxPkInfo(id: '131', name: '7区')])
      ]), 
      FxPkItemsInfo(id: '2', name: '安徽省', items: [
        FxPkItemsInfo(id: '21', name: '合肥市', items: [ 
          FxPkInfo(id: '211', name: '1区'),
          FxPkInfo(id: '212', name: '2区'),
          FxPkInfo(id: '213', name: '3区'),
          FxPkInfo(id: '214', name: '4区')]), 
        FxPkItemsInfo(id: '22', name: '芜湖市', items: [ 
          FxPkInfo(id: '221', name: '11区'),
          FxPkInfo(id: '222', name: '21区'),
          FxPkInfo(id: '223', name: '31区'),
          FxPkInfo(id: '224', name: '41区')]),
        FxPkItemsInfo(id: '23', name: '宣城市', items: [ 
          FxPkInfo(id: '231', name: '41区'),
          FxPkInfo(id: '232', name: '42区'),
          FxPkInfo(id: '233', name: '43区'),
          FxPkInfo(id: '234', name: '44区')]),
        FxPkItemsInfo(id: '24', name: '马鞍山', items: [
          FxPkInfo(id: '241', name: '61区'),
          FxPkInfo(id: '242', name: '62区'),
          FxPkInfo(id: '243', name: '63区'),
          FxPkInfo(id: '244', name: '64区')]),
        FxPkItemsInfo(id: '25', name: '黄山市', items: [
          FxPkInfo(id: '251', name: '71区'),
          FxPkInfo(id: '2511', name: '611区'),
          FxPkInfo(id: '2512', name: '612区'),
          FxPkInfo(id: '2513', name: '613区'),
          FxPkInfo(id: '2514', name: '614区'),
          FxPkInfo(id: '252', name: '72区')])
        ]), 

    ];
  }

项目路径:https://github.com/cmtwfx1/fx_pickerview.git