Flutter - 位置选择器

狗子自导自演-《佬kei圣_裴ker》

ps: 内心戏真多[白眼] ,不就是locationPicker吗?

预告片(截图)

在这里插入图片描述

编剧(插件)

  flutter_picker: ^1.1.5
  // address_picker: ^0.0.1  狗子直接下载这个插件的代码
  // 用到了 address_manager.dart和address_model.dart文件

主演(PickerHelper及其他剧组借来的address_manager和address_model)

  • 自行创建PickerHelper (参考了一位博主的文章 微微加了点料)

import 'package:album/common/address_manager.dart';
import 'package:album/common/address_model.dart';
import 'package:album/practice/practice_address_location.dart';
import 'package:flutter/material.dart';
import 'package:flutter_picker/flutter_picker.dart';

const double _kPickerSheetHeight = 216.0;
const double _kPickerItemHeight = 32.0;

typedef PickerConfirmCityCallback = Function(List<dynamic>,List<int>);

class PickerHelper {

 static final textDarkGrayColor = Color.fromRGBO(64, 64, 64, 1.0);

 ///普通简易选择器
 static void openSimpleDataPicker<T>(
     BuildContext context, {
       @required List<T> list,
       String title,
       @required T value,
       PickerDataAdapter adapter,
       @required PickerConfirmCallback onConfirm,
     }) {
   var incomeIndex = 0;
   if (list != null) {
     for (int i = 0; i < list.length; i++) {
       if (list[i] == value) {
         incomeIndex = i;
         break;
       }
     }
   }
   openModalPicker(context,
       adapter: adapter ??
           PickerDataAdapter(
             pickerdata: list,
             isArray: false,
           ),
       onConfirm: onConfirm,
       selecteds: [incomeIndex],
       title: title);
 }

 ///数字选择器
 static void openNumberPicker(
     BuildContext context, {
       String title,
       List<NumberPickerColumn> datas,
       NumberPickerAdapter adapter,
       @required PickerConfirmCallback onConfirm,
     }) {
   openModalPicker(context,
       adapter: adapter ?? NumberPickerAdapter(data: datas ?? []),
       title: title,
       onConfirm: onConfirm);
 }

 ///日期选择器
 static void openDateTimePicker(
     BuildContext context, {
       String title,
       DateTime maxValue,
       DateTime minValue,
       DateTime value,
       DateTimePickerAdapter adapter,
       @required PickerConfirmCallback onConfirm,
     }) {
   openModalPicker(context,
       adapter: adapter ??
           DateTimePickerAdapter(
               type: PickerDateTimeType.kYMD,
               isNumberMonth: true,
               yearSuffix: "年",
               maxValue: maxValue,
               minValue: minValue,
               value: value ?? DateTime.now(),
               monthSuffix: "月",
               daySuffix: "日"),
       title: title,
       onConfirm: onConfirm);
 }

 ///地址选择器
 static void openCityPicker(BuildContext context,
     {String title,
       @required PickerConfirmCityCallback onConfirm,
       List<int> selectCityIndex}) async {
   /* 用于array
   * [
   *   {'一级标题1':
   *      [ {'二级标题1' : ['三级标题1','三级标题2']},
   *        {'二级标题2' : ['三级标题1','三级标题2']},
   *      ],
   *    '一级标题1':
   *      [ {'二级标题1' : ['三级标题1','三级标题2']},
   *        {'二级标题2' : ['三级标题1','三级标题2']},
   *      ],
   *   },
   * ]
   * */
   List<AddressProvince> provinces = await AddressManager.loadAddressData(context);
   openModalPicker(context,
       adapter: PickerDataAdapter(
           data: provinces.map((addressProvince) {
             var province = addressProvince.province;
             var cities = addressProvince.cities;
             return PickerItem(
               text: Center(
                 child: Text(
                   province,
                   style: TextStyle(color: textDarkGrayColor,fontSize: 17),
                 ),
               ),
               value: province,
               children: cities.map((cityModel) {

                 var cityStr = cityModel.city;
                 return PickerItem(
                   text: Center(
                     child: Text(
                       cityStr,
                       style: TextStyle(color: textDarkGrayColor,fontSize: 17),
                     ),
                   ),
                   value: cityStr,
                   children: cityModel.district.map((districtModel) {
                     var area = districtModel.area;
                     return PickerItem(
                         text: Center(
                           child: Text(
                             area,
                             style: TextStyle(color: textDarkGrayColor,fontSize: 17),
                           ),
                         ),
                         value: area
                     );
                   }).toList(),
                 );

               }).toList(),
             );
           }).toList()
       ),
       title: title, onConfirm: (pick, value) {
     onConfirm(pick.adapter.getSelectedValues(),value);
       },selecteds: selectCityIndex ?? [0,0,0]);
 }

 static void openModalPicker(
     BuildContext context, {
       @required PickerAdapter adapter,
       String title,
       List<int> selecteds,
       @required PickerConfirmCallback onConfirm,
     }) {
   new Picker(
     adapter: adapter,
     title: new Text(title ?? "",style: Utils.getNormalTextStyle(17),),
     selecteds: selecteds,
     cancelText: '取消',
     confirmText: '确定',
     cancelTextStyle: TextStyle(color: Colors.black,fontSize: 16.0),
     confirmTextStyle: TextStyle(color: Colors.black,fontSize: 16.0),
     textAlign: TextAlign.right,
     itemExtent: _kPickerItemHeight,
     height: _kPickerSheetHeight,
     selectedTextStyle: TextStyle(color: textDarkGrayColor,fontSize: 17),
     onConfirm: onConfirm,
   ).showModal(context);
 }

}

场地(界面)

import 'package:album/common/picker_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

// Utils 是临时创建的 (小朋友们自行归位nao~)
class Utils {

  // 获取屏幕宽度 (狗子(我本人) 放到了common.dart里)
  static double kScreenWidth(BuildContext context) => MediaQuery.of(context).size.width;
  // 项目中通用背景色 (有条件的可以单独放在color_marco.dart 文件自己建哈)
  static final backGrayColor = Color.fromRGBO(249, 249, 249, 1.0);
  // 文字通用样式 方便统一改字体
  static TextStyle getNormalTextStyle(double fontSize,{Color fontColor = Colors.black,FontWeight fontWeight}) {
    return TextStyle(
      color: fontColor,
      fontWeight: fontWeight,
      fontSize: fontSize,
    );
  }
  // base navigationBar
  static AppBar getCustomAppBar(String title) {
    return AppBar(
      iconTheme: IconThemeData(
        color: Colors.black,
      ),
      backgroundColor: Color.fromRGBO(247, 247, 247, 1.0),
      brightness: Brightness.light,
      centerTitle: true,
      title: Text(
        title,
        style: Utils.getNormalTextStyle(17),
      ),
      elevation: 2.0,
    );
  }

}

class PracticeAddressLocation extends StatefulWidget {
  @override
  _PracticeAddressLocationState createState() => _PracticeAddressLocationState();
}

class _PracticeAddressLocationState extends State<PracticeAddressLocation> {

  // 小朋友可以把这个些杂七杂八的放到 viewModel中 狗子为了方便直接整了
  // --------- 以下这堆便是杂七杂八 ---------
  // 标题
  var titles = ['地区'];

  // 地区
  List<int> locationSelectIndexs;
  List<dynamic> location;

  // 隐藏键盘  void可不写 狗子(小编本人)不习惯
  void hiddenKeyboard() {
    FocusScope.of(context).requestFocus(FocusNode());
  }
  // --------- 以上这堆便是杂七杂八 ---------

  // 点击事件
  void tapActions(actionName) {

    // 主戏
    if (actionName == '地区') {
      PickerHelper.openCityPicker(context, onConfirm: (selectInfo,selectLocation) {
        location = selectInfo;
        locationSelectIndexs = selectLocation;
        setState(() {});
      },title: '选择地区',selectCityIndex: locationSelectIndexs);
    }

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: Utils.getCustomAppBar('编辑资料'),
      body: Container(
        child: GestureDetector(
          onTap: hiddenKeyboard,
          child: ListView.builder(
            itemBuilder: (context,index) {

              var title = titles[index];
              // 用处: 当有头像的情况 在未选择头像的情况下 显示promptLabel
              var offstage = false;

              return Container(
                color: Colors.white,
                height: offstage == true ? 64 : 57,
                child: Column(
                  children: <Widget>[
                    // tile 默认高度56
                    Expanded(
                      child: Container(
                        alignment: Alignment.center,
                        child: ListTile(
                          leading: Text('地区',style: Utils.getNormalTextStyle(16),),
                          trailing: GestureDetector(
                            child: Container(
                              width: 200,
                              child: Row(
                                mainAxisAlignment: MainAxisAlignment.end,
                                children: <Widget>[
                                  Expanded(
                                    child: Stack(
                                      alignment: Alignment.centerRight,
                                      children: <Widget>[

                                        Offstage( // 当有选择头像这种情况的时候
                                          offstage: false,
                                          child: Container(child: TextField(
                                            decoration: InputDecoration(
                                                hintText: '未选择',
                                                border: InputBorder.none
                                            ),
                                            textAlign: TextAlign.right,
                                            cursorColor: Colors.red, // 修改光标颜色
                                            enabled: false,
                                            // controller: TextEditingController(text: '我是默认文字'),
                                            keyboardType: TextInputType.number, // 键盘类型
                                            inputFormatters: [ // 输入框文字限制
                                              LengthLimitingTextInputFormatter(11),
                                            ],
                                            onChanged: (text) {

                                            },
                                          )),
                                        ),

                                        // 有头像的情况(与当前文章无关 可忽略)
                                        Offstage(
                                          offstage: !offstage,
                                          child: ClipRRect(
                                            borderRadius: BorderRadius.all(Radius.circular(2)),
                                            child: Container(
                                              width: 50,
                                              height: 50,
                                              // child: Image(),
                                            ),
                                          ),
                                        ),


                                      ],
                                    ),
                                  ),
                                  Container(child: Icon(Icons.keyboard_arrow_right),),
                                ],
                              ),
                            ),
                          ),
                          onTap: () {
                            tapActions(title);
                          },
                        ),
                      ),
                    ),
                    Offstage(
                      offstage: false,
                      child: Container(height: 1,color: Utils.backGrayColor,),
                    )
                  ],
                ),
              );
            },itemCount: titles.length,
          ),
        ),
      ),
    );
  }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值