Without further ado, let’s look at the pictures
Click on the province to switch to the corresponding province, click on the city, select the city, and multiple selections can be made at the county level.
Not much to say, let’s look at the code
import 'package:flutter/material.dart'; class AreaModel { final String id; final String name; final List<AreaModel>? childrens; AreaModel(this.id, this.name, this.childs); factory AreaModel.fromMap(Map<String, dynamic> map) { final id = map['id'] as String; final name = map['name'] as String; final List<AreaModel>? childrens = (map['childs'] as List?)?.map((childMap) { return AreaModel.fromMap(childMap); }).toList(); return AreaModel(id, name, children); } } class LocationFilterPage extends StatelessWidget { @override Widget build(BuildContext context) { return LocationSelectionPage(); } } class LocationSelectionPage extends StatefulWidget { @override _LocationSelectionPageState createState() => _LocationSelectionPageState(); } class _LocationSelectionPageState extends State<LocationSelectionPage> { AreaModel? selectedProvince; AreaModel? selectedCity; AreaModel? selectedDistrict; List<AreaModel> selectedDistricts = []; @override void initState() { super.initState(); //The first province and its first city and first district and county are selected by default. if (provinces.isNotEmpty) { if (homeG.showarea == true) { if (homeG.city.length > 0) { for (var province in provinces) { for (var city in province.childrens!) { if (city.name == homeG.city) { setState(() { selectedProvince = province; selectedCity = city; for (var districtName in homeG.area) { for (var district in city.childrens!) { if (district.name == districtName) { selectedDistricts.add(district); print('selectedDistricts${selectedDistricts}'); } } } }); return; } } } } } else { selectedProvince = provinces[0]; if (selectedProvince!.childs != null & amp; & amp; selectedProvince!.childs!.isNotEmpty) { selectedCity = selectedProvince!.childs![0]; if (selectedCity!.childs!.length > 0) { if (selectedCity!.childs != null & amp; & amp; selectedCity!.childs!.isNotEmpty) { selectedDistrict = selectedCity!.childs![0]; } } } } } } void saveSelectedValues() { List<String> selectedDistrictNames = selectedDistricts.map((district) => district.name).toList(); homeG.city = selectedCity!.name; homeG.area = selectedDistrictNames; homeG.showarea = true; Navigator.pop(context, 'Refresh'); } void resetSelection() { setState(() { //Reset button click event handling selectedDistricts.clear(); selectedProvince = provinces.isNotEmpty ? provinces[0] : null; selectedCity = selectedProvince != null & amp; & amp; selectedProvince!.childs!.isNotEmpty ? selectedProvince!.childs![0] : null; if (selectedCity!.childs!.length > 0) { selectedDistrict = selectedCity != null & amp; & amp; selectedCity!.childs!.isNotEmpty ? selectedCity!.childs![0] : null; } }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( leading:IconButton( icon: icon( Icons.arrow_back_ios, size: 17, color: AppColors.blackColor, ), onPressed: () { Navigator.pop(context); }, ), backgroundColor: Colors.transparent, elevation: 0, centerTitle: true, title: Text('Switch City', style: CustomTextStyle.primaryTitle_1), ), body: Container( color: Color(0xFFF4F5F9), width: double.infinity, child: Column( mainAxisSize: MainAxisSize.max, children: [ Expanded( flex: 9, child: buildSelectionRow(), ), Expanded( flex: 1, child: Container( padding: EdgeInsets.fromLTRB(12, 8, 12, 8), decoration: BoxDecoration( color: Color(0xFFFFFFFF), border: Border( top: BorderSide(width: 0.5, color: Color(0xFFEEEEEE)), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ InkWell( onTap: () { setState(() { resetSelection(); }); }, child: Container( width: 113, height: 44, alignment:Alignment.center, decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: Color(0xFFF7F7F7), ), child: Text( 'Reset', style: CustomTextStyle.text16_5, ), ), ), InkWell( onTap: () { saveSelectedValues(); }, child: Container( width: 222, height: 44, alignment:Alignment.center, decoration: BoxDecorationLoginStyle.primary1Box, child: Text( 'Sure', style: CustomTextStyle.text16_6, ), ), ), ], ), ), ) ], ), ), ); } Widget buildSelectionRow() { return Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 1, child: Container( color: Colors.white, child: buildSelectionList(provinces, selectedProvince, (selected) { setState(() { selectedProvince = selected; selectedCity = selectedProvince!.childs![0]; selectedDistrict = selectedCity!.childs![0]; selectedDistricts = []; }); }), )), Expanded( flex: 1, child: Container( decoration: BoxDecoration( color: Color(0xFFF4F5F9), ), child: buildSelectionList1( selectedProvince?.childs [], selectedCity, (selected) { setState(() { selectedCity = selected; if (selectedCity!.childs!.length > 0) { selectedDistrict = selectedCity!.childs![0]; selectedDistricts = []; } List<String> selectedDistrictNames = selectedDistricts .map((district) => district.name) .toList(); }); }), )), Expanded( flex: 1, child: Container( decoration: BoxDecoration( color: Color(0xFFF4F5F9), border: Border( left: BorderSide(width: 0.5, color: Color(0xFFE4E8F8)))), child: buildSelectionLists( selectedCity?.childs [], selectedDistrict, (selected) { setState(() { selectedDistrict = selected; if (selectedDistricts.contains(selectedDistrict)) { selectedDistricts.remove(selectedDistrict); } else { selectedDistricts.add(selectedDistrict!); } List<String> selectedDistrictNames = selectedDistricts .map((district) => district.name) .toList(); }); }), )) ], ); } Widget buildSelectionLists(List<AreaModel> items, AreaModel? selected, Function(AreaModel) onItemSelected) { return Container( // height: 500, child: ListView.builder( itemCount: items.length, shrinkWrap: true, itemBuilder: (context, index) { final item = items[index]; return ListTile( title: Text( item.name, style: selectedDistricts.contains(item) ? CustomTextStyle.text22_1 : CustomTextStyle.text16_2, ), onTap: () { onItemSelected(item); }, ); }, ), ); } Widget buildSelectionList(List<AreaModel> items, AreaModel? selected, Function(AreaModel) onItemSelected) { return Container( // height: 500, child: ListView.builder( itemCount: items.length, shrinkWrap: true, itemBuilder: (context, index) { final item = items[index]; final isSelected = item == selected; return ListTile( title: Text( item.name, style: isSelected ? CustomTextStyle.text22_1 : CustomTextStyle.text16_2, ), onTap: () { onItemSelected(item); }, ); }, )); } Widget buildSelectionList1(List<AreaModel> items, AreaModel? selected, Function(AreaModel) onItemSelected) { return Container( child: ListView.builder( itemCount: items.length, shrinkWrap: true, itemBuilder: (context, index) { final item = items[index]; final isSelected = item == selected; return ListTile( title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 80, child: Text( item.name, softWrap: true, style: isSelected ? CustomTextStyle.text22_1 : CustomTextStyle.text16_2, ), ), if(isSelected) Container( width: 18, height: 18, alignment:Alignment.center, decoration: BoxDecorationStyle1.primaryFFD32367Box, child: Text( selectedDistricts.length == 0 ? 'Complete' : '${selectedDistricts.length}', style: CustomTextStyle.text12_4), ), ], ), onTap: () { onItemSelected(item); }, ); }, )); } }
Province, city and county area code, private