The Flutter project needs to implement a picker similar to the address. The data is in JSON format. There are some blogs on the Internet that can’t meet the requirements.

Flutter_picker, I tried to implement the custom selector with demo code, but it still didn’t work. After making a version, I found that scrolling multiple columns would easily cause the style disorder of the following column, so I installed city-picker plug-in and tried to pull the source code to change. It is found that the matching is the national code of provinces and cities, and it is a bit troublesome to change it…

See there is a blog on the Internet (now did not find the address), the basic implementation of multi-level data, disadvantages are: data must be written according to the level of fixed, scalability is not good, the most important, there is no implementation of select data, click OK, and then echo again.

Organize your ideas and re-implement them

For the following data format, can be implemented

[{" value ":" XXX ", "label" : "XXX", "children" : [{" value ":" XXXX ", "label" : "XXX"}]},...]Copy the code

 

If you need to change the name of the key, just take it and change it. After a look, you can change it. The core logic is implemented in accordance with multiple levels (of course, the mobile terminal plug-in will not exceed 3-4 columns).

Flutter_custom_dialog uses it to make dialog

Dependencies: flutter_custom_dialog: ^ 1.2.0Copy the code

Main.dart (Key code)

import 'package:city_picker_demo/custom_picker.dart'; List<dynamic> paramsIndexs = []; List<dynamic> paramsNames = []; // Button click event industriesData is the original data 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 (' select custom cities'),],),),Copy the code

Custom_picker.dart (full code)

import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_custom_dialog/flutter_custom_dialog.dart'; /** * params now supports the parameter * indexs = array index, / 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=[]; // array subscript set List<dynamic> colContentList = []; / / all final column real-time data sources 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++) {/ / how many columns scrollController colNum said. The 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 layer return already executed; Var levelData = initData[indexs[level]]; if(levelData ! =null && levelData['children'] ! = null && levelData['children'].length>0) {// level++; // 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, / / transverse center alignment (the default) the children: [GestureDetector(// gesture onTap: () {navigator.pop (context);}, Child: Text(" undo ", style: TextStyle) 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(" yes ", 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,); } // Calculate the scroll column 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) {// Not the last column, 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; }}Copy the code

Effect: 1. After selecting the data, click the selector again to display the data. 2. When sliding the first column at the same time, the second column (subsequent columns will return to the first element), and realize data linkage at the same time

Project source github.com/chenbing11/… Please help yourself to the master branch

For vue, the plugin would have been dead on the street, and it’s still not used to dart.

Creation is not easy, please give more likes + attention, thank you! If you have any questions, I will respond to them.