美文网首页Flutter
Flutter仿京东地址选择器

Flutter仿京东地址选择器

作者: 黎明第一束光 | 来源:发表于2018-12-18 16:44 被阅读0次
    1.jpg
    2.jpg
    3.jpg

    样式如图


    贴代码


    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_app/common/Constant.dart';
    import 'package:flutter_app/common/http/Api.dart';
    import 'package:flutter_app/common/http/ApiUrl.dart';
    import 'package:flutter_app/model/user_center/HHSRegion.dart';
    import 'package:flutter_app/model/user_center/LocalQueryBean.dart';
    
    
    ///地址选择器
    class SelectAddressWidget extends StatefulWidget {
    
      SelectAddressWidget({Key key, @required this.valueCb}) :super(key: key);
    
      ///回调函数
      final Function valueCb;
    
      @override
      _SelectAddressWidgetState createState() => new _SelectAddressWidgetState();
    }
    
    class _SelectAddressWidgetState extends State<SelectAddressWidget>
        with SingleTickerProviderStateMixin {
    
      ///区域信息列表
      List<HHSRegion> localList;
    
      ///TabBarController
      TabController _tabController;
    
      ///选择的省市县的名字
      String selectProvinceStr = '省份';
      String selectCityStr = '城市';
      String selectDistrictStr = '区/县';
    
      ///选择的省市县Id
      int selectProvinceId = -1;
      int selectCityId = -1;
      int selectDistrictId = -1;
    
      ///当前Tab位置
      int currentTabPos = 0;
    
      Map<String, int> selectMap = new Map();
    
      ///Tab Text样式
      TextStyle tabTvStyle = new TextStyle(
          color: Colors.black, fontSize: 18.0, fontWeight: FontWeight.w300);
    
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
    
        ///给区域Id Map一个初始值
        selectMap['selectProvinceId'] = -1;
        selectMap['selectCityId'] = -1;
        selectMap['selectDistrictId'] = -1;
    
        ///初始化控制器
        _tabController = new TabController(length: 3, vsync: this);
        _tabController.addListener(() {
          ///获取tab当前点击位置
          currentTabPos = _tabController.index;
          ///切换Tab重新请求列表数据
          if (_checkTabCanSelect(currentTabPos)) {
            _queryLocal(currentTabPos == 0 ? 1 : currentTabPos == 1
                ? selectProvinceId
                : selectCityId);
          }
    
          print(currentTabPos);
        });
    
        ///第一次进来 这里调用我自己的接口 查询全国的所有省 可以替换成其他
        _queryLocal(1);
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
    
            ///去掉左箭头
            automaticallyImplyLeading: false,
            title: new Text(
              '配送至', style: new TextStyle(color: const Color(0xff666666)),),
            centerTitle: true,
            elevation: 0.5,
            backgroundColor: Colors.white,
            actions: <Widget>[
              new IconButton(
                  icon: new Icon(Icons.close, color: const Color(0xff666666),),
                  onPressed: () => Navigator.pop(context))
            ],
          ),
          body: _getBody(),
        );
      }
    
      ///构建底部视图
      Widget _getBody() {
        if (_showLoadingDialog()) {
          return new Center(child: new CircularProgressIndicator(),);
        } else {
          return _buildContent();
        }
      }
    
      ///根据数据是否有返回显示加载条或者列表
      bool _showLoadingDialog() {
        if (localList == null || localList.length == 0) {
          return true;
        } else {
          return false;
        }
      }
    
      ///有数据时构建tab和区域列表
      Widget _buildContent() {
        return new Container(
          child: new Column(
            children: <Widget>[
              new Padding(padding: const EdgeInsets.only(top: 18.0)),
              new TabBar(
                indicatorColor: Colors.black,
                controller: _tabController,
                tabs: <Widget>[
                  new Text('$selectProvinceStr', style: tabTvStyle, maxLines: 1,),
                  new Text('$selectCityStr', style: tabTvStyle, maxLines: 1,),
                  new Text('$selectDistrictStr', style: tabTvStyle, maxLines: 1,),
                ],
              ),
              new Padding(padding: const EdgeInsets.only(top: 18.0)),
    
              _buildListView(),
            ],
          ),
          color: Colors.white,
        );
      }
    
      ///构建列表
      Widget _buildListView() {
        return new Expanded(
            child: new ListView.builder(
              shrinkWrap: true,
              itemCount: localList.length,
              itemBuilder: (BuildContext context, int position) {
                return _buildListRow(position);
              },
            )
        );
      }
    
      ///构建子项
      Widget _buildListRow(int position) {
        return new ListTile(
          title: new Text('${localList[position].regionName}',
            style: new TextStyle(color: const Color(0xff666666), fontSize: 15.0),),
          onTap: () => _onLocalSelect(position),);
      }
    
      ///区域位置选择
      _onLocalSelect(int position) {
        _setSelectData(position);
        if (currentTabPos != 2) {
          _queryLocal(localList[position].regionId);
        }
      }
    
      ///设置选择的数据
      ///根据当前选择的列表项的position 和 Tab的currentTabPos
      ///@params position 当前列表选择的省或市或县的position
      _setSelectData(position) {
        if (currentTabPos == 0) {
          selectProvinceId = localList[position].regionId;
          selectProvinceStr = localList[position].regionName;
          selectMap['provinceId'] = selectProvinceId;
          setState(() {
            selectCityStr = '城市';
            selectDistrictStr = '区/县';
          });
          selectCityId = -1;
          selectDistrictId = -1;
        }
    
        if (currentTabPos == 1) {
          selectCityId = localList[position].regionId;
          selectCityStr = localList[position].regionName;
          selectMap['selectCityId'] = selectCityId;
          setState(() {
            selectDistrictStr = '区/县';
          });
          selectDistrictId = -1;
        }
        if (currentTabPos == 2) {
          selectDistrictId = localList[position].regionId;
          selectDistrictStr = localList[position].regionName;
          selectMap['selectDistrictId'] = selectDistrictId;
    
          ///拼接区域字符串 回调给上个页面 关闭弹窗
          String localStr = selectProvinceStr + ' ' + selectCityStr + ' ' +
              selectDistrictStr;
          widget.valueCb(selectMap, localStr);
          Navigator.pop(context);
        }
        currentTabPos++;
        _tabController.animateTo(currentTabPos);
      }
    
      ///检查是否可以选择下级Tab
      bool _checkTabCanSelect(int position) {
        if (position == 0) {
          return true;
        }
        if (position == 1) {
          if (selectProvinceId == -1) {
            _tabController.animateTo(0);
            _showSnack();
            return false;
          }
          return true;
        }
    
        if (position == 2) {
          if (selectProvinceId == -1 && selectCityId == -1) {
            _tabController.animateTo(0);
            _showSnack();
            return false;
          }
          if (selectProvinceId != -1 && selectCityId == -1) {
            _tabController.animateTo(1);
            _showSnack();
            return false;
          }
          return true;
        }
      }
    
      ///显示错误信息
      _showSnack() {
        Scaffold.of(context).showSnackBar(
            new SnackBar(content: new Text('请先选择上级地区')));
      }
    
      ///查询区域信息
      _queryLocal(int parentId) {
        String url = Constant.HOST + ApiUrl.LOCAL_QUERY;
        Map<String, dynamic> params = new Map();
        params['parentId'] = parentId;
        Api.post(url, (Response response) {
          LocalQueryBean localQueryBean = LocalQueryBean.fromJSON(response.data);
    
          ///这里防止没有区的城市查询不到还不会关闭对话框回调到地址页面 例如三亚市
          ///写的有点乱
          if (currentTabPos == 2 && localQueryBean.regionList == null) {
            String localStr = selectProvinceStr + ' ' + selectCityStr;
            widget.valueCb(selectMap, localStr);
            Navigator.pop(context);
          }
    
          setState(() {
            localList = localQueryBean.regionList;
          });
        },
            errorCallBack: (errMsg) {
    
            },
            params: params);
      }
    
      @override
      void dispose() {
        // TODO: implement dispose
        _tabController.dispose();
        super.dispose();
      }
    }
    
    

    HHSRegion类

    import 'package:json_annotation/json_annotation.dart';
    
    part 'HHSRegion.g.dart';
    
    @JsonSerializable()
    class HHSRegion {
      int regionId; // 当前区域ID
      int parentId; // 当前区域父ID
      String regionName; // 区域名字
      int regionType; // 区域类型(0:国;1:省;2:市;3:区)
      int agencyId;
    
      HHSRegion(this.regionId, this.parentId, this.regionName, this.regionType,
          this.agencyId); // 不知道是啥
    
      //反序列化
      factory HHSRegion.fromJson(Map<String, dynamic> json)=>
          _$HHSRegionFromJson(json);
    
      //序列化
      Map<String, dynamic> toJson() => _$HHSRegionToJson(this);
    
    
    }
    

    需要将 _queryLocal(int parentId)这个方法替换成你自己的请求地址列表 或者加载本地JSON

    做的不完善 而且灵活度非常低 对于选择地址应该够了 再变态也改不到哪去了

    使用方法

    ///显示选择所在地址弹窗
      _showSelectAddrDialog() {
        ///显示一个BottomSheet
        showModalBottomSheet(
          context: context,
          ///_handleLocal是被回调页面的方法 用于接收选择的地址
          builder: (context) => new SelectAddressWidget(valueCb: _handleLocal,),
        );
      }
    

    相关文章

      网友评论

        本文标题:Flutter仿京东地址选择器

        本文链接:https://www.haomeiwen.com/subject/ojulkqtx.html