Flutter switches cities

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