tim_ui_kit_lbs_plugin 1.0.1
tim_ui_kit_lbs_plugin: ^1.0.1 copied to clipboard
LBS Plugin for Tencent IM Flutter UIKit.
腾讯云IM Flutter UIKit LBS位置消息能力插件 #
使用本插件,开发者可方便地在其腾讯云IM Flutter项目中,引入发送接收展示位置消息能力。
本插件提供三个组件:位置选择器(LocationPicker)/位置消息完整展示器(LocationShow)/位置消息列表展示器(LocationMsgElement)。并提供为其配套业务逻辑能力,除与地图底层SDK交互部分外。
为方便开发者快速接入,我们还提供基于百度地图的完整Example代码。具体请查看腾讯云IM Flutter或本Plugin的example。
术语介绍 #
POI: Point of interesting。即地图上任何非地理意义的有意义的点,每个POI均有特定坐标/名称/各级地址/ID。 例如:深圳腾讯大厦,大梅沙海滨公园。
开发接入 #
整体流程: #
- 选定底层地图SDK
- 继承三个抽象类,完成本插件业务代码与地图SDK间交互
- 将继承后的抽象类实例化,传入本插件提供的三个组件中
选定底层地图SDK #
本插件大部分业务逻辑接口基于百度地图设计,选用百度地图可较快完成项目。但不限制具体使用哪一块地图SDK,常用地图Flutter SDK如下:
百度地图:国内+国外(五万/年)数据。https://lbsyun.baidu.com/index.php?title=flutter/loc
高德地图:仅国内数据。https://lbs.amap.com/api/flutter/summary
Google Map:含全球数据。https://codelabs.developers.google.com/codelabs/google-maps-in-flutter#0
数据交互数据结构 #
本插件使用一系列数据结构来定义SDK与插件间传递的信息,包含如下:
class LocationMessage {
final String desc;
final double longitude;
final double latitude;
}
/// 代表经纬度
class TIMCoordinate implements TIMLocationBaseModel {
/// 纬度
late double latitude;
/// 经度
late double longitude;
Map<String, Object> toMap();
fromMap(Map map);
}
/// POI信息类
class TIMPoiInfo implements TIMLocationBaseModel {
/// POI名称
String? name;
/// POI坐标
TIMCoordinate? pt;
/// POI地址信息
String? address;
/// POI唯一标识符uid
String? uid;
/// POI所在省份
String? province;
/// POI所在城市
String? city;
fromMap(Map map);
Map<String, Object?> toMap();
}
/// 根据地理坐标反向查询结果类
class TIMReverseGeoCodeSearchResult implements TIMLocationBaseModel {
/// 地址坐标
TIMCoordinate? location;
/// 地址名称
String? address;
/// 层次化地址信息
TIMAddressComponent? addressDetail;
/// 地址周边POI信息,成员类型为BMKPoiInfo
List<TIMPoiInfo>? poiList;
/// 结合当前位置POI的语义化结果描述
String? sematicDescription;
fromMap(Map map);
Map<String, Object?> toMap();
}
/// 地址结果的层次化信息
class TIMAddressComponent implements TIMLocationBaseModel {
/// 国家
String? country;
/// 省份名称
String? province;
/// 城市名称
String? city;
/// 区县名称
String? district;
/// 乡镇
String? town;
fromMap(Map map);
Map<String, Object?> toMap()
}
/// 枚举:地图区域改变原因
enum TIMRegionChangeReason {
///<手势触发导致地图区域变化,如双击、拖拽、滑动地图
Gesture,
///<地图上控件事件,如点击指南针返回2D地图。
Event,
///<开发者调用接口、设置地图参数等导致地图区域变化
APIs,
}
继承抽象类,连接地图SDK与插件业务逻辑 #
若选用百度地图,可直接使用我们的完整example代码,快速完成项目。
请根据选定的地图SDK,继承以下三个类。
TIMMapService
地图定位及POI搜索能力Service。需要根据地图SDK完成交互并将数据提供给插件业务代码。
/// 需做到根据地图SDK提供的定位能力定位再将地图挪过去,
/// 并返回含根据新的地图中心查询附近POI的结果及是否出错参数的方法
void moveToCurrentLocationActionWithSearchPOIByMapSDK({
required void Function(TIMCoordinate coordinate) moveMapCenter,
void Function(TIMReverseGeoCodeSearchResult, bool)?
onGetReverseGeoCodeSearchResult,
});
/// 根据关键词搜索POI,优先返回在当前city内的结果,但同时也可以搜到其他city的POI
void poiCitySearch({
required void Function(List<TIMPoiInfo>?, bool)
onGetPoiCitySearchResult,
required String keyword,
required String city,
});
/// 根据地理坐标查询附近的POI,并返回包含TIMReverseGeoCodeSearchResult及是否报错参数的方法
void searchPOIByCoordinate(
{required TIMCoordinate coordinate,
required void Function(TIMReverseGeoCodeSearchResult, bool)
onGetReverseGeoCodeSearchResult});
TIMMapWidget
渲染地图的基类,对外暴露地图事件。是StatefulWidget,需要继承TIMMapState。 包含地图加载完成回调及地图拖动结束回调。
final Function? onMapLoadDone;
final Function(TIMCoordinate? targetGeoPt, TIMRegionChangeReason regionChangeReason)? onMapMoveEnd;
TIMMapState
渲染地图基类的State,提供完成一系列地图交互能力,并对外返回可直接使用的地图实例。
/// 地图创建完成回调
void onMapLoadDone(){}
/// 地图移动结束
void onMapMoveEnd(TIMCoordinate? targetGeoPt, TIMRegionChangeReason regionChangeReason){}
/// 移动地图视角
void moveMapCenter(TIMCoordinate pt){}
/// 禁用地图交互
void forbiddenMapFromInteract() {}
/// 在地图上添加图钉
void addMarkOnMap(TIMCoordinate pt, String title){}
/// 此处实例化地图
@override
Widget build(BuildContext context) {
return Container(
child: 某地图的Widget(
onBMFMapCreated: onMapCreated,
mapOptions: initMapOptions(),
),
);
}
使用组件 #
位置选择器(LocationPicker)
该组件以类似微信的位置选择器页面呈现,允许用户定位当前位置/地图选点/搜索特定POI/展示选定POI周边其他POI。
/// 地理位置选择完成后的onChange事件,返回一个LocationMessage,可用于发送消息。
/// 【特别说明】由于腾讯云IM位置消息仅支持传递一个desc字符串,因此此处的LocationMessage.desc将名称及地址拼接传递,格式:"腾讯大厦/////深圳市南山区深南大道10000号"。
/// 该拼接格式可被本插件所需地方解析,请放心使用。
final ValueChanged<LocationMessage> onChange;
/// 传入根据选定地图SDK实例化后的LocationUtils
final LocationUtils locationUtils;
/// 用于还未加载出来定位时,打开页面后,默认的中心点。
final TIMCoordinate? initCoordinate;
/// 传入根据选定地图SDK实例化后的地图组件TIMMapWidget
final TIMMapWidget Function(
VoidCallback onMapLoadDone,
Key mapKey,
Function(TIMCoordinate? targetGeoPt,
TIMRegionChangeReason regionChangeReason)
onMapMoveEnd) mapBuilder;
位置消息完整展示器(LocationShow)
该组件以类似微信的位置详情展示页面呈现,使用大地图配上图标,展示接收到的位置。底部显示位置名称/地址,及拉起跳转导航软件的按钮。
/// 位置名称标题
final String addressName;
/// 位置地址
final String? addressLocation;
///位置latitude
final double latitude;
///位置longitude
final double longitude;
/// 传入根据选定地图SDK实例化后的LocationUtils
final LocationUtils locationUtils;
/// 传入根据选定地图SDK实例化后的地图组件TIMMapWidget
final TIMMapWidget Function(
VoidCallback onMapLoadDone,
Key mapKey) mapBuilder;
位置消息列表展示器(LocationMsgElement)
此组件用于在历史消息列表中,展示位置消息。效果类似微信。 提供小地图展示/位置名称及地址展示。
/// 消息ID
final String? messageID;
/// V2TimLocationElem消息
final V2TimLocationElem locationElem;
/// 是否自己发送
final bool isFromSelf;
/// 是否显示被跳转样式
final bool? isShowJump;
/// 清除跳转方法
final VoidCallback? clearJump;
/// 传入根据选定地图SDK实例化后的LocationUtils
final LocationUtils locationUtils;
/// 传入根据选定地图SDK实例化后的地图组件TIMMapWidget
final TIMMapWidget Function(VoidCallback onMapLoadDone, Key mapKey)
mapBuilder;
配合UIKit使用接入 #
此部分完整代码可在IM Flutter Demo中得到。
历史消息列表渲染小地图(LocationMsgElement)
请在TIMUIKitChat中新增如下字段。该小地图可以自动点击跳转至完整版详细地图(LocationShow)。
TIMMapWidget和TIMMapService需要替换为自己的实例化对象。
locationMessageItemBuilder:
(locationElem, isFromSelf, isShowJump, clearJump, messageID) =>
LocationMsgElement(
messageID: messageID,
locationElem: locationElem,
isFromSelf: isFromSelf,
isShowJump: isShowJump,
clearJump: clearJump,
mapBuilder: (onMapLoadDone, mapKey) => TIMMapWidget(
onMapLoadDone: onMapLoadDone,
key: mapKey,
),
locationUtils: LocationUtils(TIMMapService()),
),
加号面板增加位置item并跳转至位置选择器(LocationMsgElement)
请在TIMUIKitChat中新增如下字段。该extraAction可跳转至位置选择器,并发送消息。
TIMMapWidget和TIMMapService需要替换为自己的实例化对象。
morePanelConfig: MorePanelConfig(
extraAction: [
MorePanelItem(
id: "location",
title: ("位置"),
onTap: (c) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LocationPicker(
onChange: (LocationMessage location) async {
// 此处消息发送逻辑需要根据业务框架适当修改
final locationMessageInfo = await sdkInstance.v2TIMMessageManager.createLocationMessage(
desc: location.desc, longitude: location.longitude, latitude: location.latitude);
final messageInfo = locationMessageInfo.data!.messageInfo;
_timuiKitChatController.sendMessage(
convID: _getConvID()!,
convType: _getConvType(),
messageInfo: messageInfo
);
},
mapBuilder: (onMapLoadDone, mapKey, onMapMoveEnd) => TIMMapWidget(
onMapMoveEnd: onMapMoveEnd,
onMapLoadDone: onMapLoadDone,
key: mapKey,
),
locationUtils: LocationUtils(TIMMapService()),
),
));
},
icon: Container(
height: 64,
width: 64,
margin: const EdgeInsets.only(bottom: 4),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5))),
child: Icon(
Icons.location_on,
color: hexToColor("5c6168"),
size: 32,
),
))
],
),