import 'dart:ui';
|
|
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/material.dart';
|
import 'package:flutter/rendering.dart';
|
import 'package:flutter/services.dart';
|
import 'package:flutter_baidu_mapapi_base/flutter_baidu_mapapi_base.dart';
|
import 'package:flutter_baidu_mapapi_map/flutter_baidu_mapapi_map.dart';
|
import 'package:flutter_baidu_mapapi_search/flutter_baidu_mapapi_search.dart';
|
import 'package:locations/utils/ad_util.dart';
|
import 'package:locations/utils/global.dart';
|
import 'package:locations/utils/location_util.dart';
|
import 'package:locations/utils/map_util.dart';
|
import 'package:locations/utils/search_util.dart';
|
import 'package:locations/utils/string_util.dart';
|
import 'package:locations/utils/ui_constant.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
|
//控件阴影
|
List<BoxShadow> getViewShadow() {
|
return [
|
BoxShadow(
|
blurRadius: 6.5,
|
spreadRadius: 1,
|
color: Color(0x4D0E96FF),
|
)
|
];
|
}
|
|
/********************POI搜索********************/
|
class LocationSearchPage extends StatefulWidget {
|
@override
|
_LocationSearchPageState createState() => _LocationSearchPageState();
|
}
|
|
class _LocationSearchPageState extends State<LocationSearchPage>
|
with SingleTickerProviderStateMixin {
|
BMFMapController? _mapController;
|
BMFMapOptions mapOptions = BMFMapOptions(
|
showMapScaleBar: false,
|
mapType: BMFMapType.Standard,
|
center: Global.currentPosition != null
|
? Global.currentPosition
|
: BMFCoordinate(39.917215, 116.380341),
|
mapScaleBarPosition: BMFPoint(0, 200),
|
zoomLevel: 12,
|
mapPadding: BMFEdgeInsets(left: 30, top: 0, right: 30, bottom: 200));
|
|
//1-搜索页面 2-建议搜索页面 3-结果展示页面
|
int state = 1;
|
|
Widget? expressAd;
|
|
TextEditingController? editingController;
|
List<BMFPoiInfo>? suggestList;
|
List<BMFPoiInfo>? recordList;
|
BMFCoordinate? currentPosition;
|
|
//选中位置信息
|
BMFPoiInfo? selectedPoiInfo;
|
|
BMFMarker? selectedPoiInfoMarker;
|
|
bool deleteAd = false;
|
|
@override
|
void initState() {
|
super.initState();
|
editingController = TextEditingController();
|
loadRecord();
|
}
|
|
void loadAd() async {
|
if (deleteAd && expressAd == null) {
|
return;
|
}
|
Widget? ad = AdUtil.loadExpress(
|
await AdUtil.getAdInfo(AdPosition.searchExpress),
|
MediaQuery.of(context).size.width - 20,
|
190, (success, msg) {
|
setState(() {
|
expressAd = null;
|
deleteAd = true;
|
});
|
});
|
setState(() {
|
expressAd = ad;
|
});
|
}
|
|
//加载记录页面
|
void loadRecord() {
|
SearchUtil.getRecordList().then((value) {
|
setState(() {
|
recordList = value;
|
});
|
});
|
}
|
|
//获取地图视图
|
Widget getMapView() {
|
return Container(
|
child: BMFMapWidget(
|
onBMFMapCreated: (controller) {
|
_mapController = controller;
|
LocationUtil.startLocation(0, (state, map) {
|
if (state == LocationState.success) {
|
currentPosition = BMFCoordinate.fromMap(map!);
|
_mapController!.setCenterCoordinate(currentPosition!, true);
|
}
|
});
|
},
|
mapOptions: mapOptions,
|
),
|
);
|
}
|
|
@override
|
Widget build(BuildContext context) {
|
loadAd();
|
return Scaffold(
|
resizeToAvoidBottomInset: false,
|
backgroundColor: Colors.white,
|
body: Stack(children: [
|
getMapView(),
|
Flex(direction: Axis.vertical, children: [
|
//搜索框
|
Container(
|
margin: const EdgeInsets.fromLTRB(10, 35, 10, 11),
|
alignment: Alignment.center,
|
padding: const EdgeInsets.fromLTRB(8, 0, 8, 0),
|
height: 45,
|
decoration: BoxDecoration(
|
color: Colors.white,
|
borderRadius: BorderRadius.circular(10),
|
boxShadow: getViewShadow()),
|
child: Row(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
children: [
|
InkWell(
|
onTap: () {
|
Navigator.of(context).pop();
|
},
|
child: Image.asset(
|
"assets/images/map/icon_location_back.png",
|
height: 30,
|
)),
|
Container(
|
width: 10,
|
),
|
Expanded(
|
child: state == 3
|
? Text(
|
selectedPoiInfo!.name!,
|
overflow: TextOverflow.ellipsis,
|
style: const TextStyle(
|
fontSize: 14, color: ColorConstant.title),
|
)
|
: TextField(
|
autofocus: false,
|
controller: editingController,
|
onChanged: (text) {
|
print(text);
|
// setState(() {
|
// if (text.isNotEmpty)
|
// state = 2;
|
// else
|
// state = 1;
|
// });
|
startPOISearch(text);
|
},
|
decoration: const InputDecoration(
|
focusedBorder: InputBorder.none,
|
border: InputBorder.none,
|
hintText: "地图上找位置",
|
hintStyle: TextStyle(
|
fontSize: 14, color: Color(0xFFC4CDD1))),
|
)),
|
InkWell(
|
onTap: () {
|
// selectedPoiInfo.detailInfo.
|
if (state == 3) {
|
if (selectedPoiInfoMarker != null) {
|
MapUtil.removeMarker(
|
_mapController, selectedPoiInfoMarker!);
|
selectedPoiInfoMarker = null;
|
}
|
setState(() {
|
state = 2;
|
});
|
}
|
},
|
child: Container(
|
padding: const EdgeInsets.only(right: 10),
|
child: Text(
|
state == 3 ? "取消" : "搜索",
|
style: TextStyle(
|
color: ColorConstant.theme, fontSize: 15),
|
)),
|
)
|
],
|
),
|
),
|
|
Expanded(child: getContentView())
|
])
|
]));
|
}
|
|
//banner广告
|
Widget? _banner;
|
|
loadBanner() async {
|
if (_banner != null) {
|
return;
|
}
|
Widget? ad = AdUtil.loadBanner(
|
await AdUtil.getAdInfo(AdPosition.searchResultBanner),
|
MediaQuery.of(context).size.width,
|
MediaQuery.of(context).size.width / 4, (success, msg) {
|
setState(() {
|
_banner = null;
|
});
|
});
|
setState(() {
|
_banner = ad;
|
});
|
}
|
|
Widget getContentView() {
|
loadBanner();
|
if (state == 1)
|
return getNotSearchView();
|
else if (state == 2) {
|
return getSearchSuggestView();
|
} else {
|
String? phone = selectedPoiInfo!.phone;
|
return Stack(
|
alignment: Alignment.bottomCenter,
|
children: [
|
Container(
|
padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
|
height: 97,
|
decoration: BoxDecoration(
|
boxShadow: getViewShadow(),
|
color: Colors.white,
|
borderRadius: const BorderRadius.only(
|
topLeft: Radius.circular(15),
|
topRight: Radius.circular(15))),
|
child: Column(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
Row(children: [
|
Expanded(
|
child: Text(
|
"${selectedPoiInfo!.name!}",
|
maxLines: 1,
|
overflow: TextOverflow.ellipsis,
|
style: const TextStyle(
|
color: ColorConstant.title, fontSize: 20),
|
)),
|
const SizedBox(
|
width: 4,
|
),
|
StringUtil.isNullOrEmpty(phone)
|
? Container()
|
: InkWell(
|
onTap: () {
|
launch("tel:" + phone!);
|
},
|
child: Column(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
children: [
|
Image.asset(
|
"assets/images/common/icon_phone.png",
|
width: 14,
|
),
|
const SizedBox(
|
height: 4,
|
),
|
const Text(
|
"电话",
|
style: TextStyle(
|
color: Color(0xFF393939), fontSize: 9),
|
)
|
],
|
))
|
]),
|
Expanded(child: Container()),
|
Text(
|
"${MapUtil.getDistanceDesc(selectedPoiInfo!.distance!)} |${selectedPoiInfo!.address!}",
|
maxLines: 1,
|
overflow: TextOverflow.ellipsis,
|
style:
|
const TextStyle(color: Color(0xFF666666), fontSize: 12),
|
)
|
],
|
),
|
),
|
Container(
|
margin: const EdgeInsets.only(bottom: 100),
|
height: MediaQuery.of(context).size.width / 4,
|
child: _banner ?? Container(),
|
)
|
],
|
);
|
}
|
}
|
|
Widget getNotSearchView() {
|
return Column(
|
children: [
|
Container(
|
padding: const EdgeInsets.only(left: 7, right: 7, bottom: 7, top: 7),
|
decoration: BoxDecoration(
|
color: Colors.white,
|
borderRadius: const BorderRadius.only(
|
topRight: Radius.circular(15), topLeft: Radius.circular(15)),
|
boxShadow: getViewShadow(),
|
),
|
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
//分类
|
Container(
|
padding: const EdgeInsets.only(
|
left: 20, right: 20, bottom: 15, top: 9),
|
child: Row(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
children: [
|
getSugguestSearchType(
|
"酒店",
|
Image.asset(
|
"assets/images/map/icon_location_search_type_hotel.png",
|
height: 34,
|
), () {
|
setSearchKey("酒店");
|
}),
|
getSugguestSearchType(
|
"餐馆",
|
Image.asset(
|
"assets/images/map/icon_location_search_type_eat.png",
|
height: 34,
|
), () {
|
setSearchKey("餐馆");
|
}),
|
getSugguestSearchType(
|
"外卖",
|
Image.asset(
|
"assets/images/map/icon_location_search_type_waimai.png",
|
height: 34,
|
), () {
|
setSearchKey("外卖");
|
}),
|
getSugguestSearchType(
|
"电影院",
|
Image.asset(
|
"assets/images/map/icon_location_search_type_movie.png",
|
height: 34,
|
), () {
|
setSearchKey("电影院");
|
}),
|
getSugguestSearchType(
|
"景点",
|
Image.asset(
|
"assets/images/map/icon_location_search_type_sense.png",
|
height: 34,
|
), () {
|
setSearchKey("景点");
|
}),
|
],
|
)),
|
//广告
|
Container(
|
child: expressAd ?? Container(),
|
),
|
]),
|
),
|
//分隔线
|
Container(
|
height: 10,
|
color: const Color(0xFFF0F0F0),
|
),
|
Expanded(
|
child: Container(
|
color: Colors.white,
|
padding: const EdgeInsets.only(left: 20, right: 20),
|
child: ListView.builder(
|
itemBuilder: (BuildContext context, int index) {
|
return getHistoryItem(recordList![index].name!,
|
recordList![index].address!, recordList![index]);
|
},
|
itemCount: recordList == null ? 0 : recordList!.length,
|
),
|
))
|
],
|
);
|
}
|
|
setSearchKey(String key) {
|
editingController!.text = key;
|
editingController!.selection = TextSelection(
|
baseOffset: key.length, extentOffset: editingController!.text.length);
|
startPOISearch(key);
|
}
|
|
// static const messageChannel =
|
// const BasicMessageChannel('POISearch', StandardMessageCodec());
|
//
|
// void searchPOI() async {
|
// Map value = await messageChannel.send({"method": "searchNearBy"}) as Map;
|
// if (value["code"] == 0) {
|
// print("返回结果为:$value");
|
// }
|
// }
|
|
startPOISearch(String key) async {
|
setState(() {
|
suggestList = null;
|
if (key.isNotEmpty)
|
state = 2;
|
else
|
state = 1;
|
});
|
|
BMFPoiNearbySearchOption poiNearbySearchOption = BMFPoiNearbySearchOption(
|
keywords: <String>[key],
|
location: currentPosition != null
|
? currentPosition
|
: BMFCoordinate(29.674509, 106.517571),
|
radius: 10000,
|
isRadiusLimit: true);
|
|
BMFPoiNearbySearch nearbySearch = BMFPoiNearbySearch();
|
nearbySearch.onGetPoiNearbySearchResult(
|
callback: (BMFPoiSearchResult result, BMFSearchErrorCode errorCode) {
|
print("搜索结果回调:$result");
|
setState(() {
|
suggestList = result.poiInfoList;
|
});
|
});
|
bool flag = await nearbySearch.poiNearbySearch(poiNearbySearchOption);
|
|
// BMFSuggestionSearchOption suggestionSearchOption =
|
// BMFSuggestionSearchOption(keyword: key,cityLimit: false);
|
// BMFSuggestionSearch suggestionSearch = BMFSuggestionSearch();
|
// suggestionSearch.onGetSuggestSearchResult(callback:
|
// (BMFSuggestionSearchResult result, BMFSearchErrorCode errorCode) {
|
// print("result:$result errorCode:$errorCode");
|
// setState(() {
|
// suggestList = result.suggestionList;
|
// });
|
// });
|
// bool flag = await suggestionSearch.suggestionSearch(suggestionSearchOption);
|
|
print("结束$flag");
|
}
|
|
//建议搜索视图
|
Widget getSearchSuggestView() {
|
return Container(
|
decoration: BoxDecoration(
|
color: Colors.white,
|
borderRadius: BorderRadius.only(
|
topLeft: Radius.circular(15), topRight: Radius.circular(15)),
|
boxShadow: getViewShadow()),
|
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
|
child: ListView.builder(
|
itemBuilder: (BuildContext context, int index) {
|
if (suggestList == null) {
|
return Container(
|
margin: EdgeInsets.only(top: 50),
|
alignment: Alignment.center,
|
height: 50,
|
width: 50,
|
child: const CircularProgressIndicator(strokeWidth: 3.0));
|
} else if (suggestList!.isEmpty) {
|
return Container(
|
alignment: Alignment.center, child: const Text("暂无数据"));
|
} else {
|
return getHistoryItem(suggestList![index].name!,
|
suggestList![index].address!, suggestList![index]);
|
}
|
},
|
itemCount: suggestList != null ? suggestList!.length : 1,
|
padding: const EdgeInsets.all(0),
|
));
|
}
|
|
void _showPOIDetail(BMFPoiInfo info) async {
|
double? distance;
|
if (Global.currentPosition != null) {
|
distance = await MapUtil.getDistance(
|
Global.currentPosition!, BMFCoordinate.fromMap(info.pt!.toMap()));
|
}
|
distance ??= 0;
|
info.distance = distance.toInt();
|
//显示地址详情
|
SearchUtil.addSearchRecord(info);
|
setState(() {
|
state = 3;
|
selectedPoiInfo = info;
|
});
|
|
//添加marker
|
if (selectedPoiInfoMarker == null) {
|
MapUtil.addMarker(_mapController, BMFCoordinate.fromMap(info.pt!.toMap()),
|
"assets/images/common/icon_location_marker.png")
|
.then((value) {
|
selectedPoiInfoMarker = value;
|
});
|
} else {
|
selectedPoiInfoMarker!
|
.updatePosition(BMFCoordinate.fromMap(info.pt!.toMap()));
|
}
|
_mapController!
|
.setCenterCoordinate(BMFCoordinate.fromMap(info.pt!.toMap()), true);
|
}
|
|
//历史记录项目
|
Widget getHistoryItem(String title, String content, BMFPoiInfo info,
|
{bool showDistance = false}) {
|
return InkWell(
|
onTap: () {
|
_showPOIDetail(info);
|
},
|
child: Container(
|
height: 67,
|
decoration: const BoxDecoration(
|
color: Colors.white,
|
border: Border(
|
bottom: BorderSide(
|
// 设置单侧边框的样式
|
color: Color(0xFFF1F2F3),
|
width: 1,
|
style: BorderStyle.solid))),
|
child: Row(
|
crossAxisAlignment: CrossAxisAlignment.center,
|
children: [
|
Container(
|
padding: EdgeInsets.only(top: 12, right: 9),
|
alignment: Alignment.topCenter,
|
child: Image.asset(
|
"assets/images/map/icon_location_location.png",
|
height: 16,
|
)),
|
Expanded(
|
child: Column(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.center,
|
children: [
|
Text(
|
title,
|
softWrap: false,
|
overflow: TextOverflow.ellipsis,
|
style:
|
const TextStyle(color: Color(0xFF333333), fontSize: 13),
|
),
|
Container(
|
height: 5,
|
),
|
Text(
|
content,
|
style:
|
const TextStyle(color: Color(0xFF9DAAB3), fontSize: 11),
|
),
|
],
|
)),
|
Image.asset(
|
"assets/images/map/icon_location_position_input.png",
|
height: 20,
|
)
|
],
|
),
|
));
|
}
|
|
Widget getSugguestSearchType(
|
String title, Image icon, GestureTapCallback _onClick) {
|
return InkWell(
|
onTap: () {
|
_onClick();
|
},
|
child: Flex(
|
direction: Axis.vertical,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
children: [
|
icon,
|
Container(
|
height: 5,
|
),
|
Text(
|
title,
|
style: const TextStyle(color: Color(0xFF333333), fontSize: 11),
|
)
|
],
|
));
|
}
|
}
|
|
/********************位置详情********************/
|
class PositionDetailPage extends StatefulWidget {
|
@override
|
_PositionDetailPageState createState() => _PositionDetailPageState();
|
}
|
|
class _PositionDetailPageState extends State<PositionDetailPage>
|
with SingleTickerProviderStateMixin {
|
@override
|
Widget build(BuildContext context) {
|
return Container();
|
}
|
}
|