Flutter劫富济贫计划(三)——flutter布局实战

地图导航搜索页面布局


整个页面共使用的插件有

  • amap_location_fluttify: 高德定位控件
  • amap_search_fluttify: 高德搜索控件
  • permission_handler: 权限请求
  • azlistview: 城市列表选择
  • shared_preferences: 保持历史记录(本地存储)
  • lpinyin: 汉字转拼音
  • provide: 状态管理
  • rxdart: 搜索插件用到

其中城市列表插件,状态管理,我就不详细介绍了,如果有需要的话,可以自己去Pub上面搜一下,下载个实例工程,就知道怎么用了, 如果有什么问题,请给我留言,我看到后会给立刻您回复

引入的包

Plugins.dart 是我封装的计算经纬度距离的方法,在下面我会给出代码的

ScreenAdapter.dart 是我之前封装的屏幕适配类,如果有需要可以看我另一篇文章跳转地址

PublicStorage.dart 是我之前封装的本地存储类,如果有需要可以看我另一篇文章跳转地址·

rxdart.dart不太重要,是一个函数Dart类,本来想要使用其中的循环呢,后来直接用for循环代替了,可以不用引入

search_model.dart 是我写的一个model类,主要用来转换数据用的,下面会给出代码

页面代码

import 'package:flutter/material.dart';
import 'package:amap_search_fluttify/amap_search_fluttify.dart';
import 'package:project/plugins/Plugins.dart';

import 'package:project/plugins/ScreenAdapter.dart';
import 'package:project/plugins/PublicStorage.dart';
import 'package:rxdart/rxdart.dart';

import 'package:project/pages/model/search_model.dart';

class SearchMap extends StatefulWidget {
  @override
  _SearchMapState createState() => _SearchMapState();
}

class _SearchMapState extends State<SearchMap> {
  var city, address, latlng;
  final _addressController = TextEditingController();
  List<LocationSearch> _poiTitleList = [];

  @override
  void initState() {
    super.initState();
    _getLocation();
  }
  // 获取本地存储的定位
  _getLocation() async {
    var a = await PublicStorage.getHistoryList('LocationCity');
    var b = await PublicStorage.getHistoryList('LocationAddress');
    // var c = await PublicStorage.getHistoryList('LocationLatLng');
    setState(() {
      city = a[0];
      address = b[0];
      // latlng = c[0];
    });
    print(city);
    print(address);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('选择地址'),
      ),
      body: ListView(
        children: <Widget>[
          searchMap(),
          searchList()
        ],
      ),
    );
  }

  // 选择地址顶部搜索
  Widget searchMap() {
    return Container(
      padding: EdgeInsets.all(ScreenAdapter.setWidth(20)),
      child: Row(
        children: <Widget>[
          InkWell(
            child: Padding(
              padding: EdgeInsets.all(ScreenAdapter.setWidth(20)),
              child: Row(
                children: <Widget>[
                  Text('${city}'),
                  Icon(Icons.arrow_drop_down)
                ],
              ),
            ),
            onTap: () async {
              Navigator.pushNamed(context, '/city_select').then((data) {
                setState(() {
                  city = data;
                });
              });
            },
          ),
          Expanded(
            flex: 1,
            child: Container(
              decoration: BoxDecoration(
                  color: Color.fromRGBO(200, 200, 200, 0.3),
                  border: Border.all(
                      width: 1, color: Color.fromRGBO(150, 150, 150, 0.3))),
              child: TextField(
                controller: _addressController,
                decoration: InputDecoration(border: InputBorder.none),
              ),
            ),
          ),
          InkWell(
            child: Padding(
              padding: EdgeInsets.all(ScreenAdapter.setWidth(20)),
              child: Text(
                '搜索',
                style: TextStyle(color: Color.fromRGBO(150, 150, 150, 0.9)),
              ),
            ),
            onTap: () async {
              _poiTitleList = [];
              final poiList = await AmapSearch.searchKeyword(
                _addressController.text,
                city: city,
              );
              for (int i = 0; i < poiList.length; i++) {
                LocationSearch bean = LocationSearch();
                bean.title = await poiList[i].title;
                bean.address = await poiList[i].address;
                bean.latLng = await poiList[i].latLng;
                bean.distance = await Plugins.getdistance(context, bean.latLng);
                setState(() {
                  _poiTitleList.add(bean);
                });
              }
            },
          )
        ],
      ),
    );
  }

  // 周边地理建筑列表
  Widget searchList() {
    return Container(
      padding: EdgeInsets.all(ScreenAdapter.setWidth(20)),
      color: Color.fromRGBO(200, 200, 200, 0.3),
      child: Container(
          decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(ScreenAdapter.setWidth(10))),
          child: Column(
              children: _poiTitleList.map((val) {
            return Column(
              children: <Widget>[
                ListTile(
                  title: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Text(val.title),
                      Text(
                        val.distance != null ? val.distance : 0,
                        // '18千米',
                        style: TextStyle(
                            fontSize: ScreenAdapter.size(25),
                            color: Color.fromRGBO(150, 150, 150, 0.9),
                            fontWeight: FontWeight.w400),
                      )
                    ],
                  ),
                  subtitle: Text(val.address),
                ),
                Divider(
                  height: ScreenAdapter.setHeight(0.5),
                )
              ],
            );
          }).toList())),
    );
  }
}

Plugins.dart

// 公用 的方法
import 'dart:convert';

import 'package:permission_handler/permission_handler.dart'; // 权限申请
import 'package:fluttertoast/fluttertoast.dart';
import 'package:amap_map_fluttify/amap_map_fluttify.dart';    // 获取距离

import 'package:provide/provide.dart';
import 'package:project/provide/userinformation.dart';        // 用户地理信息

import 'package:project/plugins/PublicStorage.dart';

class Plugins {
  ///大陆手机号码11位数,匹配格式:前三位固定格式+后8位任意数
  /// 此方法中前三位格式有:
  /// 13+任意数 * 15+除4的任意数 * 18+除1和4的任意数 * 17+除9的任意数 * 147
  static bool isChinaPhoneLegal(String str) {
    return new RegExp(
            '^((13[0-9])|(15[^4])|(166)|(17[0-8])|(18[0-9])|(19[8-9])|(147,145))\\d{8}\$')
        .hasMatch(str);
  }

  static getdistance(context, str) async {

    var mylatlng = await PublicStorage.getHistoryList('LocationLatLng');
    var city = await PublicStorage.getHistoryList('LocationCity');
    List searchList = [];

    searchList = str.toString().substring(7, str.toString().lastIndexOf('}')).split(',');
    

    final result = await AmapService.calculateDistance(
      LatLng(
        double.parse(mylatlng[0][0].toString().substring(5)),
        double.parse(mylatlng[0][1].toString().substring(5)),
      ),
      LatLng(
        double.parse(searchList[0].toString().substring(5)),
        double.parse(searchList[1].toString().substring(5)),
      ),
    );

    return result.round().toString()+'米';
  }
}

userinformation.dart

import 'package:flutter/material.dart';
import 'package:project/plugins/PublicStorage.dart';

class UserInfomation with ChangeNotifier{
  var city = '';
  var address = '';
  var select_city = '';         // 用户经过城市选择之后选择到的城市
  var latlng = null;             // 经纬度

  setCity(val) async{
    print(val);
    this.city = val;
    notifyListeners();
  }

  setAddress(val) async {
    this.address = val;
    notifyListeners();
  }
  setLatLng(val) async {
    this.latlng = val;
    notifyListeners();
  }

  setSelectCity(val) async {
    this.select_city = val;
    notifyListeners();
  }
}

search_model.dart



import 'package:amap_search_fluttify/amap_search_fluttify.dart';

class LocationSearch {
  String title;
  String address;
  LatLng latLng;
  String distance;

  LocationSearch({this.title, this.address, this.distance, this.latLng});

  LocationSearch.fromJson(Map json){
    this.title = json['title'];
    this.address = json['price'];
    this.distance = json['distance'];
    this.latLng = json['latLng'];
  }
}


你可能感兴趣的:(Flutter)