Taiwan City Picker

Pub Version License: MIT Github: Stars

台灣縣市選擇器,可以自訂樣式。 Web Demo

Features

  • 設定座標由近到遠顯示
  • 縣市區黑名單、白名單控制顯示
  • 大小寫臺、台切換
  • 選項顯示郵遞區號
  • 英文語系
  • 文字輸入搜尋
  • 框線樣式設定
  • 水平和垂直佈局
  • 自訂 Builder
  • 提供 Controller 控制器

Options

基本設定

Option Description Type Default
controller 控制選擇狀態 TaiwanCityPickerController? null
onChange 選擇變更時的 Callback Function Function? null
countyHint 縣市選擇器的提示文字 String? null
districtHint 地區選擇器的提示文字 String? null
onlyCounty 是否只顯示縣市選擇器 bool false

Layout

Option Description Type Default
layoutDirection Layout 方向 LayoutDirection horizontal
mainAxisAlignment 主軸對齊方式 MainAxisAlignment start
crossAxisAlignment 副軸對齊方式 CrossAxisAlignment center
mainAxisSize 主軸大小 MainAxisSize max
spacing 縣市和地區選擇器之間的間距 double 12.0

Style

Option Description Type Default
border 輸入框邊框樣式 InputBorder? null
menuHeight 下拉選單的最大高度 double 200.0

功能設定

Option Description Type Default
searchable 是否啟用搜尋功能 bool false
language 顯示語言(中文/英文) Language zhTW
showZipCode 是否在地區名稱前顯示郵遞區號 bool false
stdWord 是否使用標準字(true: 臺,false: 台) bool true

Location

Option Description Type Default
latitude 參考點緯度(用於距離排序) double? null
longitude 參考點經度(用於距離排序) double? null

Filter

Option Description Type Default
whitelistCountyCode 縣市代碼白名單 List<String>? null
blacklistCountyCode 縣市代碼黑名單 List<String>? null
whitelistZipCode 郵遞區號白名單 List<int>? null
blacklistZipCode 郵遞區號黑名單 List<int>? null

Default Value

Option Description Type Default
defaultCountyCode 預設選擇的縣市代碼 String? null
defaultZipCode 預設選擇的郵遞區號 int? null

Custom UI Builder

Option Description Type Default
countyBuilder 自訂縣市選擇器 UI CountyBuilder? null
districtBuilder 自訂地區選擇器 UI DistrictBuilder? null
layoutBuilder 自訂整體佈局 LayoutBuilder? null

County Code 對照表

County Code
臺北市 63000
基隆市 10017
新北市 65000
連江縣 09007
宜蘭縣 10002
新竹市 10018
新竹縣 10004
桃園市 68000
苗栗縣 10005
臺中市 66000
彰化縣 10007
南投縣 10008
嘉義市 10020
嘉義縣 10010
雲林縣 10009
臺南市 67000
高雄市 64000
澎湖縣 10016
金門縣 09020
屏東縣 10013
臺東縣 10014
花蓮縣 10015

使用範例

基本使用

TaiwanCityPicker(
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {
    print('changeType: $changeType');
    print('county: $county');
    print('district: $district');
  },
)

Vertical (垂直 Layout)

TaiwanCityPicker(
  layoutDirection: LayoutDirection.vertical,
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Custom Border (框線設定)

TaiwanCityPicker(
  border: OutlineInputBorder(
    borderRadius: BorderRadius.circular(12),
    borderSide: BorderSide(color: Colors.blue, width: 2),
  ),
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Location Sorting (距離由近到遠排序)

TaiwanCityPicker(
  latitude: 24.0541621,   // 台中市緯度
  longitude: 120.6478417, // 台中市經度
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Whitelist Zip Code (只顯示樹林、龜山)

TaiwanCityPicker(
  whitelistZipCode: [238, 333], // 樹林區、龜山區
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Blacklist County (不顯示外島縣市)

TaiwanCityPicker(
  blacklistCountyCode: ['09007', '10016', '09020'], // 金門、連江、澎湖
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Variant Chinese characters (異體字)

TaiwanCityPicker(
  defaultZipCode: 950,
  stdWord: false,
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Default County Code (預設臺中市)

TaiwanCityPicker(
  defaultCountyCode: '66000', // 臺中市代碼
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Default Zip Code (預設信義區 110)

TaiwanCityPicker(
  defaultZipCode: 110, // 信義區郵遞區號
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Searchable Mode

TaiwanCityPicker(
  searchable: true, // 啟用搜尋功能
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Controller Methods (控制器操作)

final TaiwanCityPickerController controller = TaiwanCityPickerController();

TaiwanCityPicker(
  controller: controller,
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

ElevatedButton(
  onPressed: () => controller.setCountyCode('64000'),
  child: Text('設定高雄市'),
),
ElevatedButton(
  onPressed: () => controller.setZipCode(238),
  child: Text('設定樹林區'),
),
ElevatedButton(
  onPressed: () => controller.reset(),
  child: Text('清空'),
),

English Mode (英文)

TaiwanCityPicker(
  layoutDirection: LayoutDirection.vertical,
  language: Language.enUS,
  showZipCode: true,
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Only County (只需要縣市選擇)

TaiwanCityPicker(
  onlyCounty: true,
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

Custom Builder 1 (自訂樣式 1)

TaiwanCityPicker(
  countyBuilder:
      (
        BuildContext context,
        List<TaiwanCityModel> counties,
        TaiwanCityModel? selectedCounty,
        void Function(TaiwanCityModel?) onCountySelected,
        String hintText,
      ) {
        return Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(colors: [Colors.blue, Colors.lightBlue]),
            borderRadius: BorderRadius.circular(12),
          ),
          child: Row(
            children: [
              Padding(
                padding: EdgeInsets.all(12),
                child: Icon(Icons.location_city, color: Colors.white),
              ),
              Expanded(
                child: DropdownButton<TaiwanCityModel>(
                  value: selectedCounty,
                  hint: Text(hintText, style: TextStyle(color: Colors.white)),
                  isExpanded: true,
                  underline: SizedBox.shrink(),
                  dropdownColor: Colors.blue,
                  items: counties.map((county) {
                    return DropdownMenuItem<TaiwanCityModel>(
                      value: county,
                      child: Text(county.countyName, style: TextStyle(color: Colors.white)),
                    );
                  }).toList(),
                  onChanged: onCountySelected,
                ),
              ),
            ],
          ),
        );
      },
  districtBuilder:
      (
        BuildContext context,
        List<TaiwanCityModel> districts,
        TaiwanCityModel? selectedDistrict,
        void Function(TaiwanCityModel?)? onDistrictSelected,
        String hintText,
        bool enabled,
      ) {
        return Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: enabled ? [Colors.green, Colors.lightGreen] : [Colors.grey.shade500, Colors.grey.shade500],
            ),
            borderRadius: BorderRadius.circular(12),
          ),
          child: Row(
            children: [
              Padding(
                padding: EdgeInsets.all(12),
                child: Icon(Icons.location_on, color: enabled ? Colors.white : Colors.grey.shade100),
              ),
              Expanded(
                child: DropdownButton<TaiwanCityModel>(
                  iconDisabledColor: Colors.grey.shade100,
                  value: selectedDistrict,
                  hint: Text(hintText, style: TextStyle(color: enabled ? Colors.white : Colors.grey.shade100)),
                  isExpanded: true,
                  underline: SizedBox.shrink(),
                  dropdownColor: Colors.green,
                  items: enabled
                      ? districts
                            .map(
                              (district) => DropdownMenuItem<TaiwanCityModel>(
                                value: district,
                                child: Text('${district.townName} (${district.zipCode})', style: TextStyle(color: Colors.white)),
                              ),
                            )
                            .toList()
                      : null,
                  onChanged: enabled ? onDistrictSelected : null,
                ),
              ),
            ],
          ),
        );
      },
  layoutBuilder: (BuildContext context, Widget countyWidget, Widget districtWidget) {
    return Card(
      elevation: 3,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Column(crossAxisAlignment: CrossAxisAlignment.start, spacing: 12, children: [countyWidget, districtWidget]),
      ),
    );
  },
)

Custom Builder 2 (自訂樣式 2)

TaiwanCityPicker(
  defaultCountyCode: '63000',
  countyBuilder:
      (
        BuildContext context,
        List<TaiwanCityModel> counties,
        TaiwanCityModel? selectedCounty,
        void Function(TaiwanCityModel?) onCountySelected,
        String hintText,
      ) {
        return SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: SegmentedButton<TaiwanCityModel>(
            segments: counties.map((county) {
              return ButtonSegment<TaiwanCityModel>(
                value: county,
                label: Text(county.countyName, style: TextStyle(fontSize: 12)),
              );
            }).toList(),
            emptySelectionAllowed: true,
            selected: selectedCounty != null ? {selectedCounty} : {},
            onSelectionChanged: (Set<TaiwanCityModel> selection) {
              onCountySelected(selection.isNotEmpty ? selection.first : null);
            },
            multiSelectionEnabled: false,
            showSelectedIcon: false,
          ),
        );
      },
  districtBuilder:
      (
        BuildContext context,
        List<TaiwanCityModel> districts,
        TaiwanCityModel? selectedDistrict,
        void Function(TaiwanCityModel?)? onDistrictSelected,
        String hintText,
        bool enabled,
      ) {
        return Expanded(
          child: ListView(
            children: districts.map((district) {
              return RadioListTile<TaiwanCityModel>(
                title: Text('(${district.zipCode}) ${district.townName}'),
                value: district,
                contentPadding: EdgeInsets.zero,
                groupValue: selectedDistrict,
                onChanged: enabled ? onDistrictSelected : null,
              );
            }).toList(),
          ),
        );
      },
  layoutBuilder: (BuildContext context, Widget countyWidget, Widget districtWidget) {
    return SizedBox(
      height: 500,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [SizedBox(height: 8), countyWidget, SizedBox(height: 8), districtWidget],
      ),
    );
  },
  onChange: (ChangeType changeType, SelectedCounty? county, SelectedDistrict? district) {},
)

資料來源

3碼郵遞區號與行政區地理座標對照KML

Libraries

taiwan_city_picker