阅读 457

Flutter 自定义数据选择器

flutter_picker,跟着demo敲代码尝试去实现自定义选择器,发现还是不行,做了一版,发现滚动多列的时候,容易导致后面一列的样式错乱,安装 city-picker 插件尝试拉取源码去改动,发现里面匹配就是全国的省市区的code,改动起来有点麻烦……

看到网上有一篇博客(现在没找到地址),基本实现多层级数据的,缺点是:数据必须需要按照层级都固定写死了,扩展性不好,最重要的,没有实现选中数据,点击确定之后,再次回显。

整理思路自己重新实现

针对 下面这种 数据格式,都能实现

[

    {

        "value": "xxx",

        "label": "xxx",

        "children": [

          {

            "value": "xxxx",

            "label": "xxx"

         ]}

    ]

  },

  ……

]复制代码

 

如果需要改动 键的名称,直接拿取改,稍看一下,就能改,核心逻辑都是按照多层级去实现的(当然移动端这种插件不会超过3-4列)

flutter_custom_dialog 用它来做dialog

dependencies:

  flutter_custom_dialog: ^1.2.0复制代码

Main.dart (关键代码)

import 'package:city_picker_demo/custom_picker.dart';

 

List<dynamic> paramsIndexs = [];

 

List<dynamic> paramsNames = [];

 

//按钮的点击事件 industriesData 为原始数据

 RaisedButton(

                 padding: EdgeInsets.all(0),

                 onPressed: () {

                   customPicker(context,{"indexs":paramsIndexs, "initData": industriesData, "colNum":2}, (opt){

                     print(opt['indexs']);

                     print(opt['names']);

                     setState(() {

                       paramsIndexs = opt['indexs'];

                       paramsNames = opt['names'];

                     });

                   });

                 },

                 child: Row(

                   children: [

                     Text('自定义城市选择'),

 

                   ],

                 ),

               ),复制代码

custom_picker.dart (完整代码)

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_custom_dialog/flutter_custom_dialog.dart';

/**
 * params 里面目前支持参数
 * indexs 指多个列的数组下标,如果是初始的时候可以传空数组
 * colNum 指多少列
 * initData 传入的初始数据
 */
YYDialog customPicker(BuildContext context, params, Function onConfirm) {
  return YYDialog().build(context)
    ..gravity = Gravity.bottom
    ..gravityAnimationEnable = true
    ..backgroundColor = Colors.transparent
    ..widget(ChooseList(params: params, onConfirm: onConfirm,))
    ..show();
}

class ChooseList extends StatefulWidget {
  final Function onConfirm;

  final params;

  const ChooseList({Key key, this.params, this.onConfirm,}) : super(key: key);

  @override
  _ChooseListState createState() => _ChooseListState();
}

class _ChooseListState extends State<ChooseList> {

  List<dynamic> colIndex=[]; //数组下标集合

  List<dynamic> colContentList = []; //所有列实时的数据源

  final List<FixedExtentScrollController> scrollController = [];

  @override
  void initState() {
    super.initState();
    final indexs = widget.params['indexs'];
    final colNum = widget.params['colNum'];
    if (scrollController.length == 0) {
      if(indexs.length == 0) { //没选择数据的时候是这个逻辑
        for (int i = 0; i < colNum; i++) { // colNum 表示多少列
          scrollController.add(FixedExtentScrollController(initialItem: 0));
        }
      } else { // 选择完数据的时候
        for (int i = 0; i < colNum; i++) {
          scrollController.add(FixedExtentScrollController(initialItem: indexs[i]));
        }
      }
    }
    initIndexs(indexs, colNum);
    colContentList = initData(colIndex, colNum, widget.params['initData']);

  }

  //初始化下标
  void initIndexs(indexs,colNum) {
    if(indexs.length ==0){
      for (int i = 0; i < colNum; i++) {
        colIndex.add(0);
      }
    } else { // 选中之后再次进来
      colIndex = indexs;
    }
  }

  /**
   * industriesData 数据源
   *
   * */
  initData(indexs, colNum, initData) {
    var dataList = []; //最终的各列的数据
    var level = 0;
    for(var i = 0; i < colNum; i++) {
      dataList.add([]);
    }
    recursionDataHandle(indexs, colNum, initData, level,dataList);
    return dataList;
  }

  /**
   * 递归执行函数
   */
   void recursionDataHandle(indexs, colNum, initData, level,dataList) {
     for(var i = 0; i < initData.length; i++) {
       if(level != colNum) {
         dataList[level].add({"value": initData[i]['value'], "label": initData[i]['label']});
       } else { //已经执行n层
          return ;
       }
     }
     //处理下一级的数据
     var levelData =  initData[indexs[level]];
     if(levelData !=null  && levelData['children'] != null && levelData['children'].length>0) { //递归
       level++; //层级加1
       recursionDataHandle(indexs, colNum, initData[indexs[level-1]]['children'], level, dataList);
     }
   }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      height: 280,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.vertical(
            top: Radius.circular(16)),
        color: Colors.white,
      ),
      child: Column(
        children: [
          vGap(10),
          Padding(
            padding: EdgeInsets.symmetric(horizontal: 20),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              crossAxisAlignment: CrossAxisAlignment.center, //横轴居中对齐(默认)
              children: [
                GestureDetector( //手势
                    onTap: () {
                      Navigator.pop(context);
                    },
                    child: Text(
                      "取消",
                      style: TextStyle(
                          color: Colors.grey,
                          fontSize: 14),
                    )),
                Text(
                  "",
                  style: TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w600),
                ),
                GestureDetector(
                    onTap: () {
                      Navigator.pop(context);
                      var names = getAllNames();
                      widget.onConfirm({'indexs':colIndex, "names":names });
                    },
                    child: Text("确定",
                        style: TextStyle(
                            color: Colors.blueAccent,
                            fontSize: 14))),
              ],
            ),
          ),
          vGap(10),
          Row(
            children: cuputedScroll()
          )
        ],
      ),
    );
  }

  Widget buildCity(
      {List<dynamic> list,
        FixedExtentScrollController scroll,
        int columnNum,
        Function onSelected}) {
    return Expanded(
      flex: 1,
      child: Container(
          height: 230,
          child: list.length != 0
              ? CupertinoPicker.builder(
            scrollController: scroll,
            itemExtent: 30,
            diameterRatio: 3,
            squeeze: 0.8,
            onSelectedItemChanged: (int _index) {
              selectdeHandel(_index, columnNum);
            },
            itemBuilder: (context, index) {
              return Center(
                  child: Text(
                    "${list[index]['label']}",
                    style: TextStyle(
                        fontSize: 14,
                        fontWeight: FontWeight.w600),
                  ));
            },
            childCount: list.length,
          )
              : Container()),
    );
  }

  // 纵向间距
  static SizedBox vGap(double height){
    return SizedBox(
      height: height,
    );
  }

  // 计算 scroll的列
  cuputedScroll () {
    List<Widget> buildCitys =[];
    for(var i =0; i< colContentList.length; i++ ){
      buildCitys.add(buildCity(list: colContentList[i], scroll: scrollController[i],columnNum: i));
    }
    return buildCitys;
  }

  // 滑动某一列的列的时候
  selectdeHandel(int _index, columnNum) {
    for(var i = columnNum; i< colIndex.length; i++) {
      setState(() {
        if(i== columnNum) {
          colIndex[i] = _index;
        } else {
          colIndex[i] = 0;
        }
      });
    }
    var tmpData  = initData(colIndex, widget.params['colNum'],  widget.params['initData']);
    setState(() {
      colContentList = tmpData;
    });
    if(columnNum !=colIndex.length-1) { //不是最后一列,滚动前一列,则后面每一列都需要滚动第一个元素位置上
      if (scrollController[columnNum+1].hasClients) {
        scrollController[columnNum+1].jumpTo(0.0);
      }
    }
  }

  //获取数据的对应的名称
  getAllNames() {
    List<dynamic> names = [];
    for(var i = 0; i < colContentList.length; i++) {
      names.add(colContentList[i][colIndex[i]]['label']);
    }
    return names;
  }
}复制代码

效果: 1.做到了选中数据再次点击选择器数据回显。 2同时滑动第一列的时候,第二列(后续列都会重新回到第一个元素上),同时实现数据的联动

打印login.jpg

2323332.gif


作者:陈炳
链接:https://juejin.cn/post/7037507200163512351

伪原创工具 SEO网站优化  https://www.237it.com/ 


文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐