前言
地图、定位对于移动开发来说不可或缺,下面尝试封装高德地图作为 React-Native组件。我只写了android部分,ios如有需求请移驾我公司大神发布的组件https://github.com/react-native-component/react-native-smart-amap
账号与Key的申请
注册成为高德开发者需要分三步:
第一步,注册高德开发者;第二步,去控制台创建应用;第三步,获取Key。
具体步骤:
1、注册高德开发者
2、创建应用
3、获取API key
申请地址:http://lbs.amap.com/
配置AndroidManifest.xml
//地图包、搜索包需要的基础权限
<!--允许程序打开网络套接字-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允许程序设置内置sd卡的写权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--允许程序获取网络状态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允许程序访问WiFi网络信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--允许程序读写手机状态和身份-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--允许程序访问CellID或WiFi热点来获取粗略的位置-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
设置高德Key
gradle文件中添加
defaultConfig {
minSdkVersion 19
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [
AMAP_KEY:"你的 Appkey"
]
}
在application标签中加入:
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="${AMAP_KEY}"/>
Android部分
使用AS创建Library项目,右键点击项目并选择Open Module Settings,选中Dependencies,点击下面等➕号选择Library dependency,搜索AMap添加导入就可以使用sdk了。
dependencies {
...
compile 'com.amap.api:map2d:2.9.1'
compile 'com.amap.api:location:3.1.0'
compile 'com.amap.api:search:3.5.0'
}
原生UI
AMap动画比较卡,期间还造成定位不准确,建议不使用动画,定位后加图标,Poi搜索都在回调事件中处理,以下是RCTAMapView代码,定位功能,poi搜索功能,看个人需求也可以封装到原生模块中
public class RCTAMapView extends FrameLayout implements LocationSource, AMapLocationListener,
PoiSearch.OnPoiSearchListener, AMap.OnCameraChangeListener {
...
//定义一堆成员变量
...
/**
* 初始化View
* @param context
*/
public RCTAMapView(ThemedReactContext context) {
super(context);
this.CONTEXT = context;
CenterView = new ImageView(context);//空间中间显示到图标
Resources resources =context.getCurrentActivity().getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
this.density = dm.density;
// SCROLL_BY_PX=(int)(SCROLL_BY_PX*density+0.5);
PARAM = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
/**
* 初始化控件,定位位置
*/
private void init() {
mSensorHelper = new SensorEventHelper(CONTEXT);
if (mSensorHelper != null) {
mSensorHelper.registerSensorListener();
}
MAPVIEW = new MapView(CONTEXT);
MAPVIEW.setLayoutParams(PARAM);
this.addView(MAPVIEW);
MAPVIEW.onCreate(CONTEXT.getCurrentActivity().getIntent().getExtras());
CenterView.setLayoutParams(new ViewGroup.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT));
// CenterView.setImageResource(R.drawable.poi_marker);
CenterView.setImageResource(getSplashId(CENTERMARKER));
this.addView(CenterView, 1);
setUpMap();
poiSearch = new PoiSearch(CONTEXT, query);
}
/**
* 设置一些amap的属性
*/
private void setUpMap() {
AMAP = MAPVIEW.getMap();
AMAP.setMapType(AMap.MAP_TYPE_NORMAL);// 矢量地图模式
mUiSettings = AMAP.getUiSettings();//实例化UiSettings类
mUiSettings.setZoomControlsEnabled(ZOOMCONTROLS);//显示缩放按钮
mUiSettings.setZoomPosition(ZOOM_POSITION_RIGHT_CENTER);//缩放按钮 右边界中部:ZOOM_POSITION_RIGHT_CENTER 右下:ZOOM_POSITION_RIGHT_BUTTOM。
mUiSettings.setLogoPosition(LOGO_POSITION_BOTTOM_RIGHT);//Logo的位置 左下:LOGO_POSITION_BOTTOM_LEFT 底部居中:LOGO_POSITION_BOTTOM_CENTER 右下:LOGO_POSITION_BOTTOM_RIGHT
mUiSettings.setCompassEnabled(COMPASSENABLE);//指南针
mUiSettings.setZoomGesturesEnabled(ZOOMGESTURES);//手势缩放
mUiSettings.setScaleControlsEnabled(SCALECONTROLS);//比例尺
changeCamera(
CameraUpdateFactory.newCameraPosition(new CameraPosition(
latLng, ZOOMLEVEL, 30, 0)));//创建view时候传入之前定位到当前坐标位置把地图中心移动过去
mFirstFix = true;
addLocationMarker(latLng, RADIUS, mLocMarker);
AMAP.setLocationSource(this);// 设置定位监听
AMAP.setOnCameraChangeListener(this);// 对amap添加移动地图事件监听器
mUiSettings.setMyLocationButtonEnabled(false);// 设置默认定位按钮是否显示
AMAP.setMyLocationEnabled(true);// 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false
}
/**
* Activity onResume后调用view的onAttachedToWindow
*/
@Override
protected void onAttachedToWindow() {
init();
super.onAttachedToWindow();
}
/**
* Activity onResume后调用view的onAttachedToWindow
*/
@Override
protected void onAttachedToWindow() {
init();
super.onAttachedToWindow();
}
/**
* view生命周期onDetachedFromWindow
*/
@Override
protected void onDetachedFromWindow() {
this.removeView(MAPVIEW);
MAPVIEW.onDestroy();
super.onDetachedFromWindow();
}
/**
* 对应onResume、对应onPause
*
* @param hasWindowFocus
*/
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
// 对应onResume
MAPVIEW.onResume();
} else {
//对应onPause
MAPVIEW.onPause();
}
}
重写onLayout处理中心点图标位置
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
/**
* 处理中心点控件位置
*/
HEIGHT = getHeight();//在这里才可以拿到控件到高低
WIDTH = getWidth();
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) CenterView.getLayoutParams();
viewWidth = CenterView.getMeasuredWidth();
viewHeight = CenterView.getMeasuredHeight();
params.setMargins(WIDTH / 2 - viewWidth / 2, HEIGHT / 2 - viewHeight, 0, 0);
CenterView.setLayoutParams(params);
// CenterView.invalidate();
super.onLayout(changed, left, top, right, bottom);
}
发起定位,发起poi搜索以及回调方法:
/**
* 定位到设备定位位置
*/
public void startLocation() {
startTime = System.currentTimeMillis();
Log.i("Test", "startTime:" + startTime);
if (mlocationClient == null) {
Log.i("Test", "mlocationClient = null");
mlocationClient = new AMapLocationClient(CONTEXT);
mLocationOption = new AMapLocationClientOption();
//设置定位监听
mlocationClient.setLocationListener(this);
//设置为高精度定位模式
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
mLocationOption.setOnceLocation(ONCELOCATION);
// mLocationOption.setOnceLocationLatest(true);
mLocationOption.setLocationCacheEnable(true);//定位缓存策略
// mLocationOption.setInterval(10);
// mLocationOption.setInterval(3*60*1000);
//设置定位参数
mlocationClient.setLocationOption(mLocationOption);
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
// 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
// 在定位结束后,在合适的生命周期调用onDestroy()方法
// 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
}
mlocationClient.startLocation();
}
public void poiSearch(String keyWord, String cityCode, int currentPage) {
query = new PoiSearch.Query(keyWord, QUERYTYPE, cityCode);
//keyWord表示搜索字符串,
//第二个参数表示POI搜索类型,二者选填其一,
//POI搜索类型共分为以下20种:汽车服务|汽车销售|
//汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|医疗保健服务|
//住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|交通设施服务|
//金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施
//cityCode表示POI搜索区域,可以是城市编码也可以是城市名称,也可以传空字符串,空字符串代表全国在全国范围内进行搜索
query.setPageSize(PAGESIZE);// 设置每页最多返回多少条poiitem
query.setPageNum(currentPage);//设置查询页码
poiSearch.setQuery(query);
poiSearch.setOnPoiSearchListener(this);
poiSearch.searchPOIAsyn();
}
public void poiSearchRound(LatLonPoint latlng, String cityCode, int currentPage) {
if (cityCode == null || "".equals(
cityCode)) {
cityCode = DEFAULTCITY;
}
query = new PoiSearch.Query("", QUERYTYPE, cityCode);
query.setPageSize(PAGESIZE);// 设置每页最多返回多少条poiitem
query.setPageNum(currentPage);//设置查询页码
poiSearch.setQuery(query);
poiSearch.setOnPoiSearchListener(this);
poiSearch.setBound(new PoiSearch.SearchBound(latlng, 1000));//设置周边搜索的中心点以及半径
poiSearch.searchPOIAsyn();
}
private void addCircle(LatLng latlng, float RADIUS) {
CircleOptions options = new CircleOptions();
options.strokeWidth(1f);
options.fillColor(FILL_COLOR);
options.strokeColor(STROKE_COLOR);
options.center(latlng);
options.radius(RADIUS);
mCircle = AMAP.addCircle(options);
/* ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(mCircle, "radius", radius,0.0f,radius);
radiusAnim.setDuration(1000);
radiusAnim.setRepeatCount(ValueAnimator.INFINITE);//无限循环
// translationYAnim.setRepeatMode(ValueAnimator.INFINITE);
radiusAnim.start();*/
}
private void addMarker(LatLng latlng) {
if (mLocMarker != null) {
return;
}
// Bitmap bMap = BitmapFactory.decodeResource(this.getResources(),
// R.drawable.navi_map_gps_locked);
Bitmap bMap = BitmapFactory.decodeResource(this.getResources(),
getSplashId(LOCATIONMARKER));
BitmapDescriptor des = BitmapDescriptorFactory.fromBitmap(bMap);
// BitmapDescriptor des = BitmapDescriptorFactory.fromResource(R.drawable.navi_map_gps_locked);
MarkerOptions options = new MarkerOptions();
options.icon(des);
options.anchor(0.5f, 0.5f);
options.position(latlng);
// 将Marker设置为贴地显示,可以双指下拉看效果
mLocMarker = AMAP.addMarker(options);
}
@Override
public void activate(OnLocationChangedListener listener) {
mListener = listener;
// startLocation();
}
@Override
public void deactivate() {
mListener = null;
if (mlocationClient != null) {
mlocationClient.stopLocation();
mlocationClient.onDestroy();
}
mlocationClient = null;
}
/**
* poi搜索回调
* @param result
* @param rCode
*/
@Override
public void onPoiSearched(PoiResult result, int rCode) {
List<PoiItem> poiItems = new ArrayList<>();
if (rCode == 1000) {
if (result != null && result.getQuery() != null) {// 搜索poi的结果
if (result.getQuery().equals(query)) {// 是否是同一条
poiResult = result;
// 取得搜索到的poiitems有多少页
poiItems = poiResult.getPois();// 取得第一页的poiitem数据,页数从数字0开始
/* List<SuggestionCity> suggestionCities = poiResult
.getSearchSuggestionCitys();// 当搜索不到poiitem数据时,会返回含有搜索关键字的城市信息*/
/* if (poiItems != null && poiItems.size() > 0) {
for (PoiItem poi : poiItems) {
//event发送
Log.i("Test", "PoiItem:" + poi.getCityName() + "," + poi.getAdName() + "," + poi.getTitle() + "," + poi.getSnippet() + "," + poi.getLatLonPoint().getLongitude());
}
}*/
}
}
}
// onEvChangeListener.getPoiItem(poiItems);
sendPoi2RN(poiItems);
}
/**
* 获得对应module 发送数据到RN
*
* @param poiItems
*/
private void sendPoi2RN(List<PoiItem> poiItems) {
WritableMap event = Arguments.createMap();
WritableArray array = Arguments.createArray();
for (PoiItem poi : poiItems) {
WritableMap data = Arguments.createMap();
data.putString("uid", poi.getPoiId());
data.putString("name", poi.getTitle());
data.putString("type", poi.getTypeDes());
data.putDouble("Longitude", poi.getLatLonPoint().getLongitude());
data.putDouble("Latitude", poi.getLatLonPoint().getLatitude());
data.putString("address", poi.getSnippet());
data.putString("tel", poi.getTel());
data.putInt("distance", poi.getDistance());
array.pushMap(data);
}
event.putArray("searchResultList", array);
CONTEXT.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("PoiEvent", event);
}
@Override
public void onPoiItemSearched(PoiItem poiItem, int i) {
}
/**
* 定位回调
* @param amapLocation
*/
@Override
public void onLocationChanged(AMapLocation amapLocation) {
if (!ISFIRSTMOVE) {
ISFIRSTMOVE = true;
}
if (mListener != null && amapLocation != null) {
if (amapLocation != null
&& amapLocation.getErrorCode() == 0) {
location = new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude());
// Log.i("TEST", "getLatitude:"+amapLocation.getLatitude()+"getLongitude:"+amapLocation.getLongitude());
DEFAULTCITY = amapLocation.getCity();
if (!mFirstFix) {
mFirstFix = true;
addLocationMarker(location, RADIUS, mLocMarker);
// 首次定位到点location
// AMAP.moveCamera(CameraUpdateFactory.newLatLngZoom(location, ZOOMLEVEL));
} else {
mCircle.setCenter(location);
mCircle.setRadius(RADIUS);
mLocMarker.setPosition(location);
}
//移动镜头定位到点location
/*AMAP.moveCamera(CameraUpdateFactory.newLatLngZoom(location, ZOOMLEVEL));*/
changeCamera(
CameraUpdateFactory.newCameraPosition(new CameraPosition(
location, ZOOMLEVEL, 30, 0)));
/* animateCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition(
location, ZOOMLEVEL, 30, 0)),null);*/
changeCamera(CameraUpdateFactory.scrollBy(0, -SCROLL_BY_PX));
} else {
String errText = "定位失败," + amapLocation.getErrorCode() + ": " + amapLocation.getErrorInfo();
Log.i("TEST", errText);
}
}
}
RCTAMapManager代码如下:
public class RCTAMapManager extends ViewGroupManager<RCTAMapView> {
public static final LatLng SHANGHAI = new LatLng(31.238068, 121.501654);// 上海市经纬度
@Override
public String getName() {
return "RCTAMapView";
}
@Override
protected RCTAMapView createViewInstance(ThemedReactContext reactContext) {
// SDKInitializer.initialize(reactContext.getApplicationContext());
RCTAMapView map=new RCTAMapView(reactContext);
// map.startLocation();
return map;
}
@ReactProp(name = "LatLng")
public void setLatLng(RCTAMapView view,ReadableMap Map) {
if (Map == null) {
view.setLatLng(SHANGHAI);
return;
}
view.setLatLng(new LatLng(Map.getDouble("latitude"),Map.getDouble("longitude")));
}
/**
* 查询poi每页显示多少行
* @param view
* @param pagesize
*/
@ReactProp(name = "PAGESIZE",defaultInt = 10)
public void setPAGESIZE(RCTAMapView view,int pagesize) {
view.setPAGESIZE(pagesize);
}
/**
* 定位光圈半径
* @param view
* @param RADIUS
*/
@ReactProp(name = "RADIUS",defaultInt = 10)
public void setRADIUS(RCTAMapView view,int RADIUS) {
view.setRADIUS(RADIUS);
}
/**
* 定位光圈半径
* @param view
* @param ZOOMLEVEL
*/
@ReactProp(name = "ZOOMLEVEL",defaultInt = 18)
public void setZOOMLEVEL(RCTAMapView view,int ZOOMLEVEL) {
view.setZOOMLEVEL(ZOOMLEVEL);
}
/**
* poi查询类型
* //POI搜索类型共分为以下20种:汽车服务|汽车销售|
//汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|医疗保健服务|
//住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|交通设施服务|
//金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施
* @param view
* @param QUERYTYPE
*/
@ReactProp(name = "QUERYTYPE")
public void setQUERYTYPE(RCTAMapView view,String QUERYTYPE) {
if(QUERYTYPE!=null) {
view.setQUERYTYPE(QUERYTYPE);
}
}
/**
* uisetting 初始化地图参数
*
ZOOMCONTROLS 显示缩放按钮
ZOOMGESTURES 手势缩放
SCALECONTROLS 显示比例尺
COMPASSENABLE 显示指南针
ONCELOCATION 是否一次定位
LOCATIONMARKER 定位图片资源名称
CENTERMARKER 中心点图片资源名称
* @param view
* @param Map
*/
@ReactProp(name = "UISETTING")
public void setUISETTING(RCTAMapView view,ReadableMap Map) {
if(Map!=null) {
if( Map.hasKey("ZOOMCONTROLS"))
view.setZOOMCONTROLS(Map.getBoolean("ZOOMCONTROLS"));
if( Map.hasKey("ZOOMGESTURES"))
view.setZOOMGESTURES(Map.getBoolean("ZOOMGESTURES"));
if( Map.hasKey("SCALECONTROLS"))
view.setSCALECONTROLS(Map.getBoolean("SCALECONTROLS"));
if( Map.hasKey("COMPASSENABLE"))
view.setCOMPASSENABLE(Map.getBoolean("COMPASSENABLE"));
if( Map.hasKey("ONCELOCATION"))
view.setCOMPASSENABLE(Map.getBoolean("ONCELOCATION"));
if( Map.hasKey("CENTERMARKER"))
view.setCENTERMARKER(Map.getString("CENTERMARKER"));
if( Map.hasKey("LOCATIONMARKER"))
view.setLOCATIONMARKER(Map.getString("LOCATIONMARKER"));
}
}
@Override
protected void addEventEmitters(
final ThemedReactContext reactContext,
final RCTAMapView view) {
view.setOnEvChangeListener(
new RCTAMapView.OnEvChangeListener() {
@Override
public void getPoiItem(List<PoiItem> poiItem) {
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher()
.dispatchEvent(new PoiEvent(view.getId(),poiItem));
}
});
}
@Override
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
return MapBuilder.<String, Object>builder()
.put("PoiItemEvent", MapBuilder.of("registrationName", "onPoiSearch"))//registrationName 后的名字,RN中方法也要是这个名字否则不执行
.put("onViewCenterChangeFinish", MapBuilder.of("registrationName", "onMapViewCenterChangeFinish"))//registrationName 后的名字,RN中方法也要是这个名字否则不执行
.build();
}
}
原生模块
RCTLBSModule代码如下:
public class RCTLBSModule extends ReactContextBaseJavaModule {
ReactApplicationContext mContext;
private AMapLocationClient locationClient = null;
private AMapLocationClientOption locationOption = new AMapLocationClientOption();
boolean ADDRESSCHECK,GPSCHECK,CACHECHECK,LATESTCHECK,SENSORCHECK;
long STRINTERVAL=2000;
long TIMEOUT =30000;
public RCTLBSModule(ReactApplicationContext reactContext) {
super(reactContext);
mContext = reactContext;
LATESTCHECK=true;
}
@Override
public String getName() {
return "LBSModule";
}
/**
* 开启定位服务
*/
@ReactMethod
public void startLocationService() {
/**
* 创建定位请求
*/
mContext.getCurrentActivity().runOnUiThread(new Runnable() {
public void run() {
// if(mLocationClient==null) {
// initLocation();
// }
// mLocationClient.start();
if (locationClient == null) {
initLocation();
}
startLocation();
}
});
}
/* @ReactMethod
public void getCenterLocation(final int tag){
mContext.getCurrentActivity().runOnUiThread(new Runnable() {
public void run() {
final RCTAMapView Map = ((RCTAMapView) mContext.getCurrentActivity().findViewById(tag));
Map.getCenterLocation();
}
});
}*/
@ReactMethod
public void setCenterLocation(final int tag,final double latitude,final double longitude){
mContext.getCurrentActivity().runOnUiThread(new Runnable() {
public void run() {
final RCTAMapView Map = ((RCTAMapView) mContext.getCurrentActivity().findViewById(tag));
Map.setCenterLocation(latitude,longitude);
}
});
}
@ReactMethod
public void startLocation(int tag){
final RCTAMapView Map = ((RCTAMapView) mContext.getCurrentActivity().findViewById(tag));
Map.startLocation();
}
@ReactMethod
public void poiSearch(int tag,String keyWord,String cityCode,int currentPage){
final RCTAMapView Map = ((RCTAMapView) mContext.getCurrentActivity().findViewById(tag));
Map.poiSearch(keyWord,cityCode,currentPage);
}
@ReactMethod
public void poiSearchRound(int tag,final double latitude,final double longitude,String cityCode,int currentPage){
final RCTAMapView Map = ((RCTAMapView) mContext.getCurrentActivity().findViewById(tag));
Map.poiSearchRound(new LatLonPoint(latitude,longitude),cityCode,currentPage);
}
/**
* 初始化定位
*
* @author hongming.wang
* @since 2.8.0
*/
private void initLocation() {
//初始化client
locationClient = new AMapLocationClient(mContext.getApplicationContext());
//设置定位参数
locationClient.setLocationOption(getDefaultOption());
// 设置定位监听
locationClient.setLocationListener(locationListener);
}
/**
* 默认的定位参数
*
* @author hongming.wang
* @since 2.8.0
*/
private AMapLocationClientOption getDefaultOption() {
AMapLocationClientOption mOption = new AMapLocationClientOption();
mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式
mOption.setGpsFirst(false);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭
mOption.setHttpTimeOut(TIMEOUT);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效
mOption.setInterval(STRINTERVAL);//可选,设置定位间隔。默认为2秒
mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true
mOption.setOnceLocation(false);//可选,设置是否单次定位。默认是false
mOption.setOnceLocationLatest(true);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用
AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
mOption.setSensorEnable(false);//可选,设置是否使用传感器。默认是false
return mOption;
}
/**
* 定位监听
*/
AMapLocationListener locationListener = new AMapLocationListener() {
@Override
public void onLocationChanged(AMapLocation loc) {
if (null != loc) {
//解析定位结果
String LocationData = Utils.getLocationStr(loc);
WritableMap params = Arguments.createMap();
params.putString("AMapLocation", LocationData);
sendEvent(mContext, "onAMAPLocationResult", params);
} else {
}
}
};
// 根据控件的选择,重新设置定位参数
private void resetOption() {
// 设置是否需要显示地址信息
locationOption.setNeedAddress(ADDRESSCHECK);
/**
* 设置是否优先返回GPS定位结果,如果30秒内GPS没有返回定位结果则进行网络定位
* 注意:只有在高精度模式下的单次定位有效,其他方式无效
*/
locationOption.setGpsFirst(GPSCHECK);
// 设置是否开启缓存
locationOption.setLocationCacheEnable(CACHECHECK);
//设置是否等待设备wifi刷新,如果设置为true,会自动变为单次定位,持续定位时不要使用
locationOption.setOnceLocationLatest(LATESTCHECK);
//设置是否使用传感器
locationOption.setSensorEnable(SENSORCHECK);
try {
// 设置发送定位请求的时间间隔,最小值为1000,如果小于1000,按照1000算
locationOption.setInterval(STRINTERVAL);
} catch (Throwable e) {
e.printStackTrace();
}
try {
// 设置网络请求超时时间
locationOption.setHttpTimeOut(TIMEOUT);
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 开始定位
*
* @author hongming.wang
* @since 2.8.0
*/
private void startLocation() {
//根据控件的选择,重新设置定位参数
resetOption();
// 设置定位参数
locationClient.setLocationOption(locationOption);
// 启动定位
locationClient.startLocation();
}
/**
* 停止定位
*
* @author hongming.wang
* @since 2.8.0
*/
private void stopLocation() {
// 停止定位
locationClient.stopLocation();
}
/**
* 销毁定位
*
* @author hongming.wang
* @since 2.8.0
*/
@ReactMethod
private void destroyLocation() {
if (null != locationClient) {
/**
* 如果AMapLocationClient是在当前Activity实例化的,
* 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy
*/
locationClient.onDestroy();
locationClient = null;
locationOption = null;
}
}
@ReactMethod
public void stopLocationService() {
stopLocation();
}
private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
JS部分
组件部分封装到这里就结束啦 amap.js如下
import React, { Component, PropTypes } from 'react';
import {
NativeAppEventEmitter,
NativeModules,
Platform,
StyleSheet,
requireNativeComponent,
View,
findNodeHandle,
} from 'react-native';
const MapManager = NativeModules.LBSModule;
const MapView = requireNativeComponent('RCTAMapView', AMapView);
export default class AMapView extends Component {
static defaultProps = {}
static propTypes = {
...View.propTypes, // 包含默认的View的属性
LatLng:PropTypes.object,
PAGESIZE:PropTypes.number,
RADIUS:PropTypes.number,
QUERYTYPE:PropTypes.string,
UISETTING:PropTypes.object,
onPoiSearch: PropTypes.func.isRequired,
onMapViewCenterChangeFinish:PropTypes.func,
}
render() {
return (
<MapView
{...this.props}
/>
);
}
//findNodeHandle(this) 传递View Id给RN module
getCenterLocation() {
MapManager.getCenterLocation(findNodeHandle(this))
}
startLocation() {
MapManager.startLocation(findNodeHandle(this))
}
poisearch(keyWord, i,page) {
MapManager.poiSearch(findNodeHandle(this), keyWord, i, page)
}
poiSearchRound(latitude,longitude, i,page) {
MapManager.poiSearchRound(findNodeHandle(this), latitude,longitude ,i, page)
}
}
RN中使用amap
import React, {
Component,
} from 'react'
import {
View,
Text,
StyleSheet,
Alert,
ScrollView,
ListView,
TextInput,
Image,
ActivityIndicator,
ProgressBarAndroid,
ActivityIndicatorIOS,
TouchableHighlight,
Platform,
DeviceEventEmitter,
} from 'react-native'
import AMapView from './aMap'
import TimerEnhance from 'react-native-smart-timer-enhance'
let componentData = {}
let dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => {
return r1 !== r2
},
sectionHeaderHasChanged: (s1, s2) => {
return s1 !== s2
},
})
let FirstEdit=0;//判断输入时间
class MapView extends Component {
constructor(props) {
super(props);
// 初始状态
this.state = {
value: '',
componentDataSource: dataSource.cloneWithRows(componentData),
};
}
componentDidMount() {
DeviceEventEmitter.addListener('PoiEvent', this.handleAndroidMessage);
}
componentWillUnMount() {
//移除监听返回键
DeviceEventEmitter.removeListener('PoiEvent');
//关闭定位
//NativeModules.LBSModule.destroyLocation()
}
handleAndroidMessage = (e)=> {
let array=e.searchResultList;
if(this.refs.TextInput.value!='') {
this.setState({componentDataSource: this.state.componentDataSource.cloneWithRows(array)});
}
}
/*<Text onPress={this._getCenterLocation}
style={{position: 'absolute', bottom: 0, right: 0, padding: 20, fontSize: 24,}}>中心</Text>*/
render() {
return (
<View style={{flex:1,flexDirection:'column',justifyContent:'center'}}>
<View style={{flex:1}}>
<AMapView style={{flex:1}}
LatLng={{latitude:31.239201,longitude:121.431598}}
ref={ component => this._MapView = component }
onPoiSearch={this._onPoiSearch}
onMapViewCenterChangeFinish={this._onMapViewCenterChangeFinish}
UISETTING={{CENTERMARKER:'poi_marker'}}
/>
<TouchableHighlight underlayColor={'#ccc'} style={{position: 'absolute', bottom: 10, left: 10,
padding: 10, backgroundColor: '#fff',}}
onPress={this._startLocation}>
<Text style={{flex:1,fontSize: 20,}}
>定位</Text>
</TouchableHighlight>
</View>
<View style={{flex:1,flexDirection:'column',justifyContent:'center'}}>
<TextInput
ref="TextInput"
style={[styles.input]}
placeholder="请输入名称"
maxLength={20}
clearButtonMode="while-editing"
value={this.state.value}
onChangeText={this._changeText.bind(this)}
underlineColorAndroid="transparent"//删除下划线
//onSubmitEditing={this._onSubmitEditing.bind(this)}
/>
<ListView
dataSource={this.state.componentDataSource}
enableEmptySections={true}
renderRow={this._renderRow}
style={{flex:1}}/>
</View>
</View>
)
}
_renderRow = (rowData) => {
return (
<Text style={styles.item}>{rowData.name+','+rowData.address+','+rowData.distance }</Text>
)
}
_startLocation = (e)=> {
this._MapView.startLocation()
}
_getCenterLocation = (e)=> {
this._MapView.getCenterLocation()
}
/* _onSubmitEditing = ()=> {
if (value === '') {
this.setState({componentDataSource: this.state.componentDataSource.cloneWithRows(componentData)});
}
else {
this._MapView.poisearch(value, '上海')
}
}*/
_changeText = (e)=> {
let timestamp = (new Date()).valueOf();
if (timestamp - FirstEdit > 1000) {
FirstEdit = timestamp;
if (e === '') {
this.setState({componentDataSource: this.state.componentDataSource.cloneWithRows(componentData)});
} else {
this._MapView.poisearch(e, '',0)
}
}
if (e === '') {
this.setState({componentDataSource: this.state.componentDataSource.cloneWithRows(componentData)});
}
this.setState({value: e});
}
_onPoiSearch=(e)=>{
let array=e.nativeEvent.searchResultList;
if(this.refs.TextInput.value!='') {
this.setState({componentDataSource: this.state.componentDataSource.cloneWithRows(array)});
}
}
_onMapViewCenterChangeFinish=(e)=>{
this._MapView.poiSearchRound(e.nativeEvent.latitude, e.nativeEvent.longitude,'',0)
}
}
let styles = StyleSheet.create({
header: {
height: 40,
flexDirection: 'row',
justifyContent: 'flex-start',
backgroundColor: '#F0F0FF',
alignItems: 'stretch',
top: 20,
},
flex: {
flex: 1
},
item: {
height: 30,
//borderBottomWidth: StyleSheet.hairlineWidth,
//borderBottomColor: '#ccc',
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'flex-start',
},
search: {
flex: 1,
height: 30,
backgroundColor: '#fff',
alignItems: 'stretch',
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 4,
flexDirection: 'row',
},
input: {
height: 40,
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 4,
backgroundColor: '#ffff'
},
result: {
flex: 1,
backgroundColor: '#fff',
},
border: {
borderWidth: 1,
borderTopWidth: 0,
borderColor: '#ccc',
borderRadius: 4,
},
height30: {
height: 30,
},
marginTop5: {
marginTop: 5,
},
search_view: {
top: 5,
right: 0,
width: 300,
marginRight: 5,
justifyContent: 'flex-start',
alignItems: 'stretch',
position: 'absolute',
flexDirection: 'column',
},
});
export default TimerEnhance(MapView)
因为是模拟器演示,定位的时候没有触发,效果如下: