address_selecter.dart 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import 'dart:convert';
  2. import 'dart:ui' as ui show window;
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter/services.dart';
  6. class AddressSelecter extends StatefulWidget {
  7. final String title;
  8. final Function(String province, String city, String county) onSelected;
  9. final Color unselectedColor;
  10. final Color selectedColor;
  11. final double itemTextFontSize;
  12. final TextStyle titleTextStyle;
  13. AddressSelecter(
  14. {Key key,
  15. @required this.onSelected,
  16. this.title,
  17. this.unselectedColor: Colors.grey,
  18. this.selectedColor: Colors.blue,
  19. this.itemTextFontSize: 14.0,
  20. this.titleTextStyle: const TextStyle(
  21. fontSize: 16.0, color: Colors.black, fontWeight: FontWeight.bold)})
  22. : super(key: key);
  23. @override
  24. createState() => _AddressSelecterState();
  25. }
  26. class _AddressSelecterState extends State<AddressSelecter>
  27. with TickerProviderStateMixin {
  28. int _index = 0;
  29. TabController _tabController;
  30. ScrollController _controller;
  31. /// TabBar不能动态加载,所以初始化3个,其中两个文字置空,点击事件拦截住。
  32. List<Tab> myTabs = <Tab>[Tab(text: '请选择'), Tab(text: ''), Tab(text: '')];
  33. List provinces = [];
  34. List cities = [];
  35. List counties = [];
  36. /// 当前列表数据
  37. List mList = [];
  38. /// 三级联动选择的position
  39. var _positions = [0, 0, 0];
  40. double itemHeight = 48.0;
  41. @override
  42. void initState() {
  43. super.initState();
  44. _controller = ScrollController();
  45. _tabController = TabController(vsync: this, length: myTabs.length);
  46. _initData();
  47. }
  48. @override
  49. void dispose() {
  50. _tabController?.dispose();
  51. _controller?.dispose();
  52. super.dispose();
  53. }
  54. @override
  55. Widget build(BuildContext context) {
  56. return Material(
  57. color: Colors.white,
  58. child: Container(
  59. height:
  60. MediaQueryData.fromWindow(ui.window).size.height * 9.0 / 16.0,
  61. child: Column(children: <Widget>[
  62. Stack(children: <Widget>[
  63. Container(
  64. width: double.infinity,
  65. alignment: Alignment.center,
  66. padding: const EdgeInsets.symmetric(vertical: 16.0),
  67. child:
  68. Text("${widget.title}", style: widget.titleTextStyle)),
  69. Positioned(
  70. right: 0,
  71. child: IconButton(
  72. icon: Icon(Icons.close, size: 22),
  73. onPressed: () => Navigator.maybePop(context)))
  74. ]),
  75. _line,
  76. Container(
  77. color: Colors.white,
  78. alignment: Alignment.centerLeft,
  79. child: TabBar(
  80. controller: _tabController,
  81. isScrollable: true,
  82. onTap: (index) {
  83. if (myTabs[index].text.isEmpty) {
  84. _tabController.animateTo(_index);
  85. return;
  86. }
  87. switch (index) {
  88. case 0:
  89. mList = provinces;
  90. break;
  91. case 1:
  92. mList =
  93. cities = provinces[_positions[0]]['cityList'];
  94. break;
  95. case 2:
  96. mList =
  97. counties = cities[_positions[1]]['countyList'];
  98. break;
  99. }
  100. setState(() {
  101. _index = index;
  102. _controller.animateTo(_positions[_index] * itemHeight,
  103. duration: Duration(milliseconds: 10),
  104. curve: Curves.ease);
  105. });
  106. },
  107. indicatorSize: TabBarIndicatorSize.label,
  108. unselectedLabelColor: Colors.black,
  109. labelColor: widget.selectedColor,
  110. tabs: myTabs)),
  111. _line,
  112. Expanded(
  113. child: provinces.length > 0
  114. ? _buildListView()
  115. : CupertinoActivityIndicator(animating: false))
  116. ])));
  117. }
  118. void _initData() async {
  119. ///
  120. rootBundle
  121. .loadString(
  122. 'assets/area.json')
  123. .then((value) {
  124. provinces = json.decode(value);
  125. setState(() => mList = provinces);
  126. });
  127. setState(() {});
  128. }
  129. Widget _buildListView() {
  130. return ListView.builder(
  131. controller: _controller,
  132. itemBuilder: (context, index) => InkWell(
  133. child: Container(
  134. padding: EdgeInsets.symmetric(horizontal: 16.0),
  135. height: itemHeight,
  136. alignment: Alignment.centerLeft,
  137. child: Row(children: <Widget>[
  138. Text(mList[index]["name"],
  139. style: TextStyle(
  140. fontSize: widget.itemTextFontSize,
  141. color: mList[index]["name"] == myTabs[_index].text
  142. ? widget.selectedColor
  143. : widget.unselectedColor)),
  144. SizedBox(height: 8),
  145. Offstage(
  146. offstage: mList[index]["name"] != myTabs[_index].text,
  147. child: Icon(Icons.check,
  148. size: 16.0, color: widget.selectedColor))
  149. ])),
  150. onTap: () {
  151. myTabs[_index] = Tab(text: mList[index]["name"]);
  152. _positions[_index] = index;
  153. _index++;
  154. switch (_index) {
  155. case 1:
  156. mList = cities = provinces[_positions[0]]['cityList'];
  157. myTabs[1] = Tab(text: "请选择");
  158. myTabs[2] = Tab(text: "");
  159. break;
  160. case 2:
  161. mList = counties = cities[_positions[1]]['countyList'];
  162. myTabs[2] = Tab(text: "请选择");
  163. break;
  164. case 3:
  165. _index = 2;
  166. widget.onSelected(
  167. provinces[_positions[0]]["name"],
  168. cities[_positions[1]]["name"],
  169. counties[_positions[2]]["name"]);
  170. Navigator.maybePop(context);
  171. break;
  172. }
  173. setState(() {});
  174. _controller.animateTo(0.0,
  175. duration: Duration(milliseconds: 100), curve: Curves.ease);
  176. _tabController.animateTo(_index);
  177. }),
  178. itemCount: mList.length);
  179. }
  180. Widget _line = Container(height: 0.6, color: Color(0xFFEEEEEE));
  181. }