前提: 需求中有一个城市选择组件的需要,这边看现有的依赖库并没有有满足当前交互的组件,于是自己开发了一个城市列表,仅供记录和参考~~
这边后端有提供城市列表查询的接口,可以根据上一级id获取下一级列表;如果是现有的json数据,可能需要对当前内容改造一下~
组件由两部分组成
- 选中城市信息的展示
- 当前将选择的列表
我这边在当前组件存储了四个数据:
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,
),
),
),
);
},
))
],
));
}
}