siteCity为返回数据后的站点数组,包含一级站点一级二级站点。
site为一级站点数组
newCitys为二级站点数组
index用于保存二级站点的索引值
city用于界面显示站点信息值。
void siteCityReturn() {
HttpRequest()
.request("https://mock.apifox.cn/m1/2853584-0-default/zhandian",
method: DioMethod.get)
.then((value) {
print(value);
Area area = Area.fromJson(value);
setState(() {
siteCity = area.result;
newCitys = siteCity[0]["citys"];
for (dynamic a in siteCity) {
site.add(a["name"]);
}
});
});
}
HttpRequest代码如下
import 'package:dio/dio.dart';
/// 请求方法
enum DioMethod {
get,
post,
put,
delete,
patch,
head,
}
class HttpRequest {
/// 单例模式
static HttpRequest? _instance;
factory HttpRequest() => _instance ?? HttpRequest._internal();
static HttpRequest? get instance => _instance ?? HttpRequest._internal();
/// 连接超时时间
static const int connectTimeout = 60 * 1000;
/// 响应超时时间
static const int receiveTimeout = 60 * 1000;
/// Dio实例
static Dio _dio = Dio();
/// 初始化
HttpRequest._internal() {
// 初始化基本选项
BaseOptions options = BaseOptions(
baseUrl: 'http://127.0.0.1:7001/app/',
connectTimeout: Duration(milliseconds: connectTimeout),
receiveTimeout: Duration(milliseconds: receiveTimeout));
_instance = this;
// 初始化dio
_dio = Dio(options);
// 添加拦截器
_dio.interceptors.add(InterceptorsWrapper(
onRequest: _onRequest, onResponse: _onResponse, onError: _onError));
}
/// 请求拦截器
void _onRequest(RequestOptions options, RequestInterceptorHandler handler) {
// 对非open的接口的请求参数全部增加userId
if (!options.path.contains("open")) {
options.queryParameters["userId"] = "xxx";
}
// 头部添加token
options.headers["token"] = "xxx";
// 更多业务需求
handler.next(options);
// super.onRequest(options, handler);
}
/// 相应拦截器
void _onResponse(
Response response, ResponseInterceptorHandler handler) async {
// 请求成功是对数据做基本处理
if (response.statusCode == 200) {
// ....
} else {
// ....
}
if (response.requestOptions.baseUrl.contains("???????")) {
// 对某些单独的url返回数据做特殊处理
}
handler.next(response);
}
/// 错误处理
void _onError(DioError error, ErrorInterceptorHandler handler) {
handler.next(error);
}
/// 请求类
Future<T> request<T>(
String path, {
DioMethod method = DioMethod.get,
Map<String, dynamic>? params,
data,
CancelToken? cancelToken,
Options? options,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
const _methodValues = {
DioMethod.get: 'get',
DioMethod.post: 'post',
DioMethod.put: 'put',
DioMethod.delete: 'delete',
DioMethod.patch: 'patch',
DioMethod.head: 'head'
};
options ??= Options(method: _methodValues[method]);
try {
Response response;
response = await _dio.request(path,
data: data,
queryParameters: params,
cancelToken: cancelToken,
options: options,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress);
return response.data;
} on DioError catch (e) {
rethrow;
}
}
/// 开启日志打印
/// 需要打印日志的接口在接口请求前 DioUtil.instance?.openLog();
void openLog() {
_dio.interceptors
.add(LogInterceptor(responseHeader: false, responseBody: true));
}
}
var result = await showModalBottomSheet(
context: context,
backgroundColor: Color.fromRGBO(1, 1, 1, 0),
builder: (context) {
return StatefulBuilder(builder:
(BuildContext context,
StateSetter setState) {
return Container();}
); });
// 中间分割线
Widget _selectionOverlayWidget() {
return Padding(
padding: const EdgeInsets.only(left: 0, right: 0),
child: Column(
children: [
const Divider(
height: 1,
color: Colors.black,
),
Expanded(child: Container()),
const Divider(
height: 1,
color: Colors.black,
),
],
),
);
}
onSelectedItemChanged当选中数据改变时,修改二级选择器中的数组数据。children为选择器中每一项的内容,通过遍历数组返回Text居中显示。
CupertinoPicker(
itemExtent: 60,
selectionOverlay:
_selectionOverlayWidget(),
onSelectedItemChanged: (position) {
print(position);
setState(() {
newCitys = siteCity[position]["citys"];});
},
children: [
for (var site in site)
Center(Child:Text(site)),]
)
CupertinoPicker(
itemExtent: 60,
selectionOverlay:
_selectionOverlayWidget(),
onSelectedItemChanged:
(position) {
index = position; },
children: [
for (var city in newCitys)
Center(child:Text(city)),
]
)
void onChanged(val) {
setState(() {
city = val;
});
}
在弹框中的确定容器添加手势,onTap方法中调用onChanged方法,将二级选择器中选中的站点名字作为参数,重绘UI,Navigator.pop关闭弹框。
GestureDetector(
onTap: () {
onChanged(
newCitys[index]);
Navigator.pop(context);
},
)
GestureDetector(
onTap: () async {
index = 0;
newCitys = siteCity[0]["citys"];
var result = await showModalBottomSheet(
context: context,
backgroundColor: Color.fromRGBO(1, 1, 1, 0),
builder: (context) {
return StatefulBuilder(builder:
(BuildContext context,
StateSetter setState) {
return Container(
padding: const EdgeInsets.only(
left: 15, right: 15),
height: 350,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15))),
child: Column(
children: [
const SizedBox(
height: 12,
),
const Text(
"选择站点",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: Colors.black),
),
SizedBox(
height: 180,
child: Row(
children: [
Expanded(
flex: 1,
child: CupertinoPicker(
itemExtent: 60,
selectionOverlay:
_selectionOverlayWidget(),
onSelectedItemChanged:
(position) {
print(position);
setState(() {
newCitys = siteCity[
position]
["citys"];
});
},
children: [
for (var site in site)
Center(
child:
Text(site)),
])),
Expanded(
flex: 1,
child: CupertinoPicker(
itemExtent: 60,
selectionOverlay:
_selectionOverlayWidget(),
onSelectedItemChanged:
(position) {
index = position;
},
children: [
for (var city
in newCitys)
Center(
child:
Text(city)),
])),
],
),
),
const SizedBox(
height: 32,
),
Row(
children: [
Expanded(
flex: 1,
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Container(
alignment:
Alignment.center,
height: 40,
decoration: BoxDecoration(
border: Border.all(
color:
Colors.black,
width: 1),
borderRadius:
const BorderRadius
.all(
Radius
.circular(
24))),
child: const Text(
"取消",
style: TextStyle(
color: Colors.black,
fontSize: 17,
fontWeight:
FontWeight
.w500),
),
),
)),
const SizedBox(
width: 15,
),
Expanded(
flex: 1,
child: GestureDetector(
onTap: () {
onChanged(
newCitys[index]);
Navigator.pop(context);
},
child: Container(
alignment:
Alignment.center,
height: 40,
decoration: const BoxDecoration(
color: Colors.black,
borderRadius:
BorderRadius.all(
Radius
.circular(
24))),
child: const Text(
"确定",
style: TextStyle(
color: Colors.white,
fontSize: 17,
fontWeight:
FontWeight
.w500),
),
),
)),
],
)
],
),
);
});
});
},
child: Container(
height: 40,
padding: const EdgeInsets.fromLTRB(12, 0, 12, 0),
decoration: const BoxDecoration(
color: Color.fromRGBO(247, 249, 250, 1),
borderRadius:
BorderRadius.all(Radius.circular(4))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
city,
style: const TextStyle(
color: Color.fromRGBO(26, 26, 26, 1),
fontSize: 14,
fontWeight: FontWeight.w400),
),
const Spacer(),
const Icon(Icons.chevron_right)
],
),
),
),