メインページロジック
Flutter自体には、3段階のリンク選択を可能にするCupertinoPickerが付属しています。
その後、TabPickerの相互作用によると、実装は、TabBar + TabBarView + ListViewを使用して、対応する相互作用関数を実現することができます困難ではないことがわかりました
ビルドの詳細
主にcity_pickersオープンソースプロジェクトをベースに改造を行いました。
以下は実装のメインコードです。
下のポップアップボックスの作成
///一番下のポップアップボックスを作る
Widget _bottomBuild() {
if (provinceCityAreaList == null) {
return Container();
}
return Scaffold(
appBar: PreferredSize(
child: Container(
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_buildHeaderTitle(),
_buildHeaderTabBar(),
Container(
height: 0.5,
margin: EdgeInsets.symmetric(horizontal: 16),
color: Color(0xFFEBEBEB),
)
],
),
),
preferredSize: Size.fromHeight(84)),
body: TabBarView(
controller: _tabController,
children: _buildTabBarView(),
),
);
TabBarView の実装ロジックは
///ヘッダータブバーを作る
List<Widget> _buildTabBarView() {
List<Widget> tabList = [];
tabList.add(_MyCityPicker(
key: Key('province'),
isShow: widget.showType.contain(ShowType.p),
height: widget.height,
controller: provinceController,
value: targetProvince.label,
itemList: provinceCityAreaList.map((v) {
return LabelSelectBean(
label: v.label, select: v.select == null ? false : v.select);
}).toList(),
changed: (index) {
_onProvinceChange(index);
Future.delayed(Duration(milliseconds: 200))
.then((value) => _tabController.animateTo(1));
},
));
if (_provinceName != null) {
tabList.add(_MyCityPicker(
key: Key('citys $targetProvince'),
// このプロパティは、強制的にリフレッシュする
isShow: widget.showType.contain(ShowType.c),
controller: cityController,
height: widget.height,
value: targetCity == null ? null : targetCity.label,
itemList: getCityItemList(),
changed: (index) {
_onCityChange(index);
},
));
}
if (_cityName != null && widget.showType == ShowType.pca) {
tabList.add(_MyCityPicker(
key: Key('towns $targetCity'),
isShow: widget.showType.contain(ShowType.a),
controller: areaController,
value: targetArea == null ? null : targetArea.label,
height: widget.height,
itemList: getAreaItemList(),
changed: (index) {
_areaName = targetCity.children[index].label;
_onAreaChange(index);
},
));
}
return tabList;
}
異なるCityPickerを追加することで、対応するTabBarViewを動的に表示します。
ここで落とし穴は、動的にTabBarを追加し、TabBarViewは、_tabControllerに再割り当てする必要があるだけでなく、動的にTabBarViewを追加し、2つの行の長さに合わせて、コールバックメソッドのそれぞれの選択の主な実装です。
setState(() {
_tabLabels = [targetProvince.label, "を選択する。];
_provinceName = targetProvince.label;
_tabController =
TabController(length: _tabLabels.length, vsync: this);
});
これは TabController が変更されるたびに動的に設定する必要があります。
TabBarView
タブバーの表示は主にリストを表示するためのものです。
_MyCityPickerメインビルダーコード
Container(
color: Colors.white,
child: ListView.builder(
itemBuilder: (context, index) {
return Material(
color: Colors.white,
child: InkWell(
child: Container(
padding: EdgeInsets.only(left: 16, top: 8, bottom: 8),
child: Row(
children: <Widget>[
Text(
'${widget.itemList[index].label} ',
maxLines: 1,
style: TextStyle(color: Colors.black, fontSize: 16),
overflow: TextOverflow.ellipsis,
),
widget.itemList[index].select
? Icon(
Icons.check,
size: 20,
color: Color(0xFFD71718),
)
: Container()
],
)),
onTap: () {
widget.changed(index);
},
));
},
itemCount: widget.itemList.length),
);
シンプルなリストビルダーです。
データ表示
必要なデータを選択した後、もう一度クリックすると、前回のデータを表示する必要があります。
void _initLocation(String locationCode) {
Result dataResult = widget.initDataResult;
if (dataResult != null && dataResult.provinceName != null) {
{
CityPoint point = provinceCityAreaList.firstWhere(
(province) => dataResult.provinceName == province.label,
orElse: () => null);
if (point != null) {
targetProvince = point;
targetProvince.select = true;
_provinceName = targetProvince.label;
} else {
targetProvince = provinceCityAreaList[0];
}
}
{
CityPoint point = targetProvince.children.firstWhere(
(city) => dataResult.cityName == city.label,
orElse: () => null);
if (point != null) {
targetCity = point;
targetCity.select = true;
_cityName = targetCity.label;
} else {
targetCity = targetProvince.children[0];
}
}
{
CityPoint point = targetCity.children.firstWhere(
(area) => dataResult.areaName == area.label,
orElse: () => null);
if (point != null) {
targetArea = point;
targetArea.select = true;
_areaName = targetArea.label;
} else {
targetArea = targetCity.children[0];
}
}
} else {
targetProvince = provinceCityAreaList[0];
targetCity = targetProvince.children[0];
targetArea = targetCity.children[0];
}
}
Resultの結果を通して表示されたデータを返し、対応するListデータを繰り返し処理して設定する必要があります。
メインコードは で特定のコードロジックを見ることができます。





