flutter如何实现一个城市列表

290 阅读2分钟

前提: 需求中有一个城市选择组件的需要,这边看现有的依赖库并没有有满足当前交互的组件,于是自己开发了一个城市列表,仅供记录和参考~~

这边后端有提供城市列表查询的接口,可以根据上一级id获取下一级列表;如果是现有的json数据,可能需要对当前内容改造一下~

组件由两部分组成

  1. 选中城市信息的展示
  2. 当前将选择的列表

我这边在当前组件存储了四个数据:

  var showCityData; // 展示的城市列表信息
  var cityInfo = []; //存储城市信息
  int step = 1; // 当前步骤
  int maxStep = 2; // 最长步骤

调用组件需要传两个数据:

  final Function(dynamic data)? onchange; // 存储城市信息函数
  final defaultValue;// 城市信息Value

整体代码

import 'package:flutter/material.dart';


class CityList extends StatefulWidget {
  const CityList({Key? key, this.onchange, this.defaultValue})
      : super(key: key);

  final Function(dynamic data)? onchange;
  // ignore: prefer_typing_uninitialized_variables
  final defaultValue;

  @override
  // ignore: library_private_types_in_public_api
  _CityList createState() => _CityList();
}

//基础组件
class _CityList extends State<CityList> {
  @override
  void initState() {
    super.initState();
    loadData();
  }

  bool isFalse = false;

  // ignore: prefer_typing_uninitialized_variables
  var showCityData; // 展示的城市列表信息
  var cityInfo = []; //存储城市信息
  int step = 1;
  int maxStep = 2; // 最长步骤

  loadData() async {
    // 该处为接口调用
    // ~~~~~~~~~~~~~~~~~~~~~~
    // 参数为:
    // widget.defaultValue?.length > 1
    //    ? widget
    //    .defaultValue[widget.defaultValue?.length - 2].id
    //    : 1
    
    if (成功) {
      setState(() {
        showCityData = addressInfo.dataModel?.data;
        cityInfo = widget.defaultValue ?? [];
        isFalse = false;
        step = widget.defaultValue.length > 1
            ? widget.defaultValue.length
            : 1; // 判断当前步骤
      });
    }
    if (失败) {
      errorReset();
    }
  }

  errorReset() {
    CommonToast.show(context, '城市列表查询失败,请重试', type: ToastType.error);
    setState(() {
      isFalse = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    return isFalse
        ? SizedBox(
            height: 450,
            child: Center(
                child: InkWell(
              onTap: loadData,
              child: Container(
                alignment: Alignment.center,
                decoration: BoxDecoration(
                  color: const Color(0xff333333),
                  borderRadius: BorderRadius.circular(50),
                ),
                height: 42,
                margin: const EdgeInsets.only(bottom: 20),
                width: 100,
                child: const Text("重新加载",
                    style: TextStyle(fontSize: 13, color: Color(0xffffffff))),
              ),
            )))
        : Container(
            padding: const EdgeInsets.only(top: 20, left: 20),
            child: Column(
              children: <Widget>[
                Row(children: <Widget>[
                  ...cityInfo.asMap().entries.map(
                    (entry) {
                      return TextButton(
                        child: Text(
                          entry.value.name,
                          style: const TextStyle(
                              fontSize: 15,
                              fontWeight: FontWeight.w500,
                              color: Colors.black),
                        ),
                        onPressed: () async {
                          // 展示重新选择城市
                          if (entry.key < maxStep - 1) {
                              // 该处为接口调用
                              // ~~~~~~~~~~~~~~~~~~~~~~
                              // 参数为:
                              // entry.key == 0? ‘默认值’ : cityInfo[entry.key - 1].id
                            if (成功) {
                              setState(() {
                                step = entry.key + 1;
                                showCityData = addressInfo.dataModel?.data;
                                // cityInfo.removeLast();
                                cityInfo.removeRange(
                                    entry.key + 1, cityInfo.length);
                              });
                            }
                            if (失败) {
                              errorReset();
                            }
                          }
                        },
                      );
                    },
                  ).toList(),
                ]),
                Expanded(
                    child: ListView.builder(
                  itemCount: showCityData?.length ?? 0,
                  itemBuilder: (context, index) {
                    //显示单词列表项
                    return ListTile(
                      title: InkWell(
                        onTap: () async {
                          // 修改列表内容
                          setState(() {
                            try {
                              cityInfo.removeAt(step - 1);
                              // ignore: empty_catches
                            } catch (e) {}
                            cityInfo.insert(step - 1, showCityData[index]);
                          });
                          // 更改父级内容
                          widget.onchange?.call(cityInfo);
                          // 如果选择了市 关闭弹框
                          if (step >= maxStep) {
                            Navigator.pop(context);
                            return;
                          }
                          // 列表内容更新
                           // 该处为接口调用
                              // ~~~~~~~~~~~~~~~~~~~~~~
                              // 参数为:
                              // showCityData[index].id
                          if (成功) {
                            setState(() {
                              step = step + 1;
                              showCityData = addressInfo.dataModel?.data;
                            });
                          }
                          if (失败) {
                            errorReset();
                          }
                        },
                        child: Text(
                          showCityData[index].name.toString(),
                          style: TextStyle(
                            fontSize: 15,
                            color: cityInfo
                                    .any((v) => v.id == showCityData[index].id)
                                ? Colors.red
                                : Colors.black,
                            // fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                    );
                  },
                ))
              ],
            ));
  }
}