返回顶部
首页 > 资讯 > 移动开发 >flutter 动手撸一个城市选择citypicker功能
  • 812
分享到

flutter 动手撸一个城市选择citypicker功能

2024-04-02 19:04:59 812人浏览 安东尼
摘要

城市选择器在项目开发中一般都会用到,基于Flutter版本的也有一个city_pickers但是已经很久没有人维护了,项目中之前也用的是这个,最近升级到flutter1.17.x后,

城市选择器在项目开发中一般都会用到,基于Flutter版本的也有一个city_pickers但是已经很久没有人维护了,项目中之前也用的是这个,最近升级到flutter1.17.x后,发现有一定的概率闪退,无奈之下,只能自动动手撸一个了

demo下载地址:https://GitHub.com/qqcc1388/city_picker

CityPickerView能够实现以下功能

  • 显示省市区地址,市或者区可以为空白数据
  • 省市区数据支持自定义,但是格式要按照city.JSON中个格式来,如果需要外部传入省市区数据,直接使用params参数即可
  • 支持选中之后回调选中内容以及对于的省市区code码

思路

 利用cupertino.dart中的CupertinoPicker来实现单层数据显示,通过row实现3层数据的滚动显示,然后让3个CupertinoPicker实现联动即可实现地址选择器,

代码


import 'dart:convert';
import 'package:city_picker/city_result.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

typedef ResultBlock = void Function(CityResult result);

class CityPickerView extends StatefulWidget {
  // json数据可以从外部传入,如果外部有值,取外部值
  final List params;
  // 结果返回
  final ResultBlock onResult;
  CityPickerView({this.onResult, this.params});
  @override
  _CityPickerViewState createState() => _CityPickerViewState();
}

class _CityPickerViewState extends State<CityPickerView> {
  List datas = [];
  int provinceIndex;
  int cityIndex;
  int areaindex;

  FixedExtentScrollController provinceScrollController;
  FixedExtentScrollController cityScrollController;
  FixedExtentScrollController areaScrollController;

  CityResult result = CityResult();

  bool isshow = false;

  List get provinces {
    if (datas.length > 0) {
      if (provinceIndex == null) {
        provinceIndex = 0;
        result.province = provinces[provinceIndex]['label'];
        result.provinceCode = provinces[provinceIndex]['value'].toString();
      }
      return datas;
    }
    return [];
  }

  List get citys {
    if (provinces.length > 0) {
      return provinces[provinceIndex]['children'] ?? [];
    }
    return [];
  }

  List get areas {
    if (citys.length > 0) {
      if (cityIndex == null) {
        cityIndex = 0;
        result.city = citys[cityIndex]['label'];
        result.cityCode = citys[cityIndex]['value'].toString();
      }
      List list = citys[cityIndex]['children'] ?? [];
      if (list.length > 0) {
        if (areaIndex == null) {
          areaIndex = 0;
          result.area = list[areaIndex]['label'];
          result.areaCode = list[areaIndex]['value'].toString();
        }
      }
      return list;
    }
    return [];
  }

  // 保存选择结果
  _saveInfoData() {
    var prs = provinces;
    var cts = citys;
    var ars = areas;
    if (provinceIndex != null && prs.length > 0) {
      result.province = prs[provinceIndex]['label'];
      result.provinceCode = prs[provinceIndex]['value'].toString();
    } else {
      result.province = '';
      result.provinceCode = '';
    }

    if (cityIndex != null && cts.length > 0) {
      result.city = cts[cityIndex]['label'];
      result.cityCode = cts[cityIndex]['value'].toString();
    } else {
      result.city = '';
      result.cityCode = '';
    }

    if (areaIndex != null && ars.length > 0) {
      result.area = ars[areaIndex]['label'];
      result.areaCode = ars[areaIndex]['value'].toString();
    } else {
      result.area = '';
      result.areaCode = '';
    }
  }

  @override
  void dispose() {
    provinceScrollController.dispose();
    cityScrollController.dispose();
    areaScrollController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();

    //初始化控制器
    provinceScrollController = FixedExtentScrollController();
    cityScrollController = FixedExtentScrollController();
    areaScrollController = FixedExtentScrollController();

    //读取city.json数据
    if (widget.params == null) {
      _loadCitys().then((value) {
        setState(() {
          isShow = true;
        });
      });
    } else {
      datas = widget.params;
      setState(() {
         isShow = true;
      });
    }
  }

  Future _loadCitys() async {
    var cityStr = await rootBundle.loadString('assets/city.json');
    datas = json.decode(cityStr) as List;
    //result默认取第一组值
    return Future.value(true);
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Container(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            _firstView(),
            _contentView(),
          ],
        ),
      ),
    );
  }

  Widget _firstView() {
    return Container(
      height: 44,
      child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            FlatButton(
              child: Text('取消'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
            FlatButton(
              child: Text('确定'),
              onPressed: () {
                if (widget.onResult != null) {
                  widget.onResult(result);
                }
                Navigator.pop(context);
              },
            ),
          ]),
      decoration: BoxDecoration(
        border: Border(
            bottom: BorderSide(color: Colors.grey.withOpacity(0.1), width: 1)),
      ),
    );
  }

  Widget _contentView() {
    return Container(
      // color: Colors.orange,
      height: 200,
      child: isShow
          ? Row(
              children: <Widget>[
                Expanded(child: _provincePickerView()),
                Expanded(child: _cityPickerView()),
                Expanded(child: _areapickerView()),
              ],
            )
          : Center(
              child: CupertinoActivityIndicator(
                animating: true,
              ),
            ),
    );
  }

  Widget _provincePickerView() {
    return Container(
      child: CupertinoPicker(
        scrollController: provinceScrollController,
        children: provinces.map((item) {
          return Center(
            child: Text(
              item['label'],
              style: TextStyle(color: Colors.black87, fontSize: 16),
              maxLines: 1,
            ),
          );
        }).toList(),
        onSelectedItemChanged: (index) {
          provinceIndex = index;
          if (cityIndex != null) {
            cityIndex = 0;
            if (cityScrollController.positions.length > 0) {
              cityScrollController.jumpTo(0);
            }
          }
          if (areaIndex != null) {
            areaIndex = 0;
            if (areaScrollController.positions.length > 0) {
              areaScrollController.jumpTo(0);
            }
          }
          _saveInfoData();
          setState(() {});
        },
        itemExtent: 36,
      ),
    );
  }

  Widget _cityPickerView() {
    return Container(
      child: citys.length == 0
          ? Container()
          : CupertinoPicker(
              scrollController: cityScrollController,
              children: citys.map((item) {
                return Center(
                  child: Text(
                    item['label'],
                    style: TextStyle(color: Colors.black87, fontSize: 16),
                    maxLines: 1,
                  ),
                );
              }).toList(),
              onSelectedItemChanged: (index) {
                cityIndex = index;
                if (areaIndex != null) {
                  areaIndex = 0;
                  if (areaScrollController.positions.length > 0) {
                    areaScrollController.jumpTo(0);
                  }
                }
                _saveInfoData();
                setState(() {});
              },
              itemExtent: 36,
            ),
    );
  }

  Widget _areaPickerView() {
    return Container(
      width: double.infinity,
      child: areas.length == 0
          ? Container()
          : CupertinoPicker(
              scrollController: areaScrollController,
              children: areas.map((item) {
                return Center(
                  child: Text(
                    item['label'],
                    style: TextStyle(color: Colors.black87, fontSize: 16),
                    maxLines: 1,
                  ),
                );
              }).toList(),
              onSelectedItemChanged: (index) {
                areaIndex = index;
                _saveInfoData();
                setState(() {});
              },
              itemExtent: 36,
            ),
    );
  }
}

class CityResult {
  /// 省市区
  String province = '';
  String city = '';
  String area = '';

  /// 对应的编码
  String provinceCode = '';
  String cityCode = '';
  String areaCode = '';

  CityResult({
    this.province,
    this.city,
    this.area,
    this.provinceCode,
    this.cityCode,
    this.areaCode,
  });

  CityResult.fromJson(Map<String, dynamic> json) {
    province = json['province'];
    city = json['city'];
    area = json['area'];
    provinceCode = json['provinceCode'];
    cityCode = json['cityCode'];
    areaCode = json['areaCode'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> datas = new Map<String, dynamic>();
    datas['province'] = this.province;
    datas['city'] = this.city;
    datas['area'] = this.area;
    datas['provinceCode'] = this.provinceCode;
    datas['cityCode'] = this.cityCode;
    datas['areaCode'] = this.areaCode;

    return datas;
  }
}

用法


 // var cityStr = await rootBundle.loadString('assets/city.json');
    // List datas = json.decode(cityStr) as List;
  showModalBottomSheet(
      context: context,
      isScrollControlled: true,
      builder: (ctx) {
        return CityPickerView(
          // params: datas,
          onResult: (res) {
            print(res.toJson());
            setState(() {
              citySelect = res.toJson().toString();
            });
          },
        );
      },
    );

demo下载地址:Https://github.com/qqcc1388/city_picker

到此这篇关于flutter 动手撸一个城市选择citypicker的文章就介绍到这了,更多相关flutter 城市选择citypicker内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: flutter 动手撸一个城市选择citypicker功能

本文链接: https://lsjlt.com/news/133446.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • flutter 动手撸一个城市选择citypicker功能
    城市选择器在项目开发中一般都会用到,基于flutter版本的也有一个city_pickers但是已经很久没有人维护了,项目中之前也用的是这个,最近升级到flutter1.17.x后,...
    99+
    2024-04-02
  • jQuery如何模拟12306城市选择框功能
    这篇文章主要介绍jQuery如何模拟12306城市选择框功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体如下:<!DOCTYPE html> <ht...
    99+
    2024-04-02
  • JavaScript中怎么实现一个城市选择控件
    JavaScript中怎么实现一个城市选择控件,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。实现的步骤:一、先用一定的格式罗列...
    99+
    2024-04-02
  • Ajax如何实现弹出式无刷新城市选择功能
    这篇文章给大家分享的是有关Ajax如何实现弹出式无刷新城市选择功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。具体如下:这是一款很棒的全国城市选择效果,添加城市时先添加组:找到...
    99+
    2024-04-02
  • 微信小程序如何实现城市选择及搜索功能
    这篇文章给大家分享的是有关微信小程序如何实现城市选择及搜索功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。实现搜索城市功能js文件// pages/address/a...
    99+
    2024-04-02
  • 如何实现jquery手机触屏滑动拼音字母城市选择器
    这篇文章将为大家详细讲解有关如何实现jquery手机触屏滑动拼音字母城市选择器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。用到城市选择,直接用拼音滑动方式来选择,用的时...
    99+
    2024-04-02
  • jquery如何实现省市区联动的选择功能
    本篇内容主要讲解“jquery如何实现省市区联动的选择功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“jquery如何实现省市区联动的选择功能”吧!一、需求分析需要三个下拉框,分别代表省、市、...
    99+
    2023-07-06
  • Jetpack Compose 实现一个图片选择框架功能
    目录获取图片拍照策略NothingCaptureStrategyFileProviderCaptureStrategyMediaStoreCaptureStrategy总结拍照权限取...
    99+
    2024-04-02
  • 怎么在Android中实现一个双重选择框功能
    这期内容当中小编将会给大家带来有关怎么在Android中实现一个双重选择框功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。原理:定义四个RadioGroup,通过第一个RadioGroup的选择来控制其...
    99+
    2023-05-30
    android
  • 怎么在java项目中实现一个选择排序功能
    本篇文章为大家展示了怎么在java项目中实现一个选择排序功能,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。一、基本概念      每趟从待排序的记录...
    99+
    2023-05-31
    java 选择排序 ava
  • 如何利用Android组件实现一个列表选择框功能
    如何利用Android组件实现一个列表选择框功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。android提供的列表选择框(Spinner)相当于web端用户...
    99+
    2023-05-31
    android roi
  • Android应用中怎么实现一个手机震动功能
    本篇文章给大家分享的是有关Android应用中怎么实现一个手机震动功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。实现方法如下:import android.app.Acti...
    99+
    2023-05-31
    android roi
  • Android中调用另一个Activity并返回结果(选择头像功能为例)
    场景 Android中点击按钮启动另一个Activity以及Activity之间传值: https://www.jb51.net/article/178218.htm 在上面...
    99+
    2022-06-06
    选择 调用 activity Android
  • 如何在Android应用中利用ImageView实现一个选择本地图片功能
    这期内容当中小编将会给大家带来有关如何在Android应用中利用ImageView实现一个选择本地图片功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。布局文件:<RelativeLayout xm...
    99+
    2023-05-31
    android imageview age
  • Android开发中怎么实现一个从相册选择图片进行上传功能
    这期内容当中小编将会给大家带来有关Android开发中怎么实现一个从相册选择图片进行上传功能,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。从Android系统相册选择一张图片getImageFromAlb...
    99+
    2023-05-31
    android roi
  • 如何在微信小程序中实现一个手动埋点和自动埋点功能
    如何在微信小程序中实现一个手动埋点和自动埋点功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。一、手动埋点手动埋点就是在每一处需要的地方,都加一段上报埋点的代码。影响代码的...
    99+
    2023-06-06
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作