地圖導航搜索頁面佈局
整個頁面共使用的插件有
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'];
}
}