使用百度地图仿滴滴定位
SDK版本:Android SDK v4.0.0
先上图看下效果:
最终效果图.png
嘿嘿,还不错吧,中间也算踩了不少坑,想了很多,在这里记录吧,也希望能够给大家带来点参考。如有不足,欢迎指正。
先说下需求:
1、显示自己的位置;
2、可以手动选择位置;
按照百度给的介绍,通过添加markerOptions
的方法简单的实现了下(参照OverlayDemo
),
效果如下:
感觉有以下的几点不足:
a、
marker
跟随地图拖拽移动,通过拖拽或者长按的方法选择位置不准确,体验不好;b、添加的
marker
图层在定位图层(蓝点)的下面;改进:
a、
marker
固定在中间,通过移动地图选择位置;b、改变
marker
的层级;
尝试方法:
方法一:(不可取)
通过监听地图的状态,每次更改就把marker
的位置重新设置下。起初只是在onMapStatusChangeFinish
的时候设置下,但是marker
还是会随地图移动,结束的时候会突然跳到中间。后来改为onMapStatusChange
中设置,但是还是感觉不流畅。
mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
@Override
public void onMapStatusChangeStart(MapStatus mapStatus) {}
@Override
public void onMapStatusChange(MapStatus mapStatus) {
marker.setPosition(mapStatus.target);
}
@Override
public void onMapStatusChangeFinish(MapStatus mapStatus) {}
});
另外,本以为可以通过中的zIndex
设置marker
的图层,然并卵,所以这种方法就不可用了。
final MarkerOptions markerOptions = new MarkerOptions()
.position(mBaiduMap.getMapStatus().target)
//.draggable(true)//可拖拽
.icon(bitmap)
.zIndex(12);
final Marker marker = (Marker) mBaiduMap.addOverlay(markerOptions);
//长按定位(改变marker的位置)
mBaiduMap.setOnMapLongClickListener(new BaiduMap.OnMapLongClickListener() {
@Override
public void onMapLongClick(LatLng latLng) {
marker.setPosition(latLng);
Toast.makeText(BaseMapDemo.this, "定位成功", Toast.LENGTH_SHORT).show();
}
});
方法二:
既然要使marker
的位置在MapView
中间(初始和我的位置重叠),那么我们是否可以和获取我的位置 按钮一样,直接在布局文件中写死呢?这样岂不是不会卡顿,并且层级肯定是在定位层级的上面。事实证明这种方法是可以行的通的,但需要注意的一点是,我们需要处理marker
的OnClick
事件,避免在该区域无法移动底部的地图,另外对于其位置也要进行下处理(我们要使其底部位于MapView的中间),在这里,我起初想法是增大MarginBottom
。 后来我想到了另外一种方法,然后就没有对这个做具体的demo。下面我放一个朋友的处理方法(使用Vector处理图片,话说我还是第一次见(⊙﹏⊙)b),大家可以参考下:
方法三:
通过不断观察滴滴的样式,我觉得肯定有什么是我没有发现的,果然,当我在看文档的时候这么一段话引起了我的注意:
百度地图SDK为广大开发者提供的基础地图和上面的各种覆盖物元素,具有一定的层级压盖关系,具体如下(从下至上的顺序):
1、基础底图(包括底图、底图道路、卫星图、室内图等);
2、瓦片图层(TileOverlay);
3、地形图图层(GroundOverlay);
4、热力图图层(HeatMap);
5、实时路况图图层(BaiduMap.setTrafficEnabled(true););
6、百度城市热力图(BaiduMap.setBaiduHeatMapEnabled(true););
7、底图标注(指的是底图上面自带的那些POI元素);
8、几何图形图层(点、折线、弧线、圆、多边形);
9、标注图层(Marker),文字绘制图层(Text);
10、指南针图层(当地图发生旋转和视角变化时,默认出现在左上角的指南针);
11、定位图层(BaiduMap.setMyLocationEnabled(true););
12、弹出窗图层(InfoWindow);
13、自定义View(MapView.addView(View););
没错,就是自定义View,MapView.addView(View);
,看到这个更加坚定了我的想法。通过AddView的方法。
关键是怎么使自定义的View添加到指定的位置呢,让我们一起来看下这个方法:
说的很明白了,必须是一个
MapViewParams
,那这就好办了,我们接着看文档:
class MapViewLayoutParams.png
public static final class MapViewLayoutParams.Builder.png
接下来上代码:
Point point = new Point(mMapView.getWidth() / 2, mMapView.getHeight() /2);//这里指定的是屏幕的坐标
//align 默认垂直下对齐,这样我们就不用自己处理了
MapViewLayoutParams params = new MapViewLayoutParams.Builder()
.layoutMode(MapViewLayoutParams.ELayoutMode.absoluteMode)
.height(DensityUtils.dp2px(this, 36))
.width(DensityUtils.dp2px(this, 16))
.point(point)
.build();
mMapView.addView(markLocation, params);
mMapView.refreshDrawableState();
OK,到这里基本上就完事儿了,剩下的就是一些细节的处理,例如为Marker
添加Animation
和InfoWindow
Animator animUp = ObjectAnimator.ofFloat(markLocation, "translationY", 0f, -30f);
animUp.setDuration(ANIMATION_DURATION);
Animator animDown = ObjectAnimator.ofFloat(markLocation, "translationY", - 30f, 0f);
animDown.setDuration(ANIMATION_DURATION);
final AnimatorSet animatorSet = new AnimatorSet();animatorSet.playSequentially(animUp, animDown);
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) { }
@Override
public void onAnimationEnd(Animator animation) {
mInfoWindow = new InfoWindow(BitmapDescriptorFactory.fromView(infoWindow), mBaiduMap.getMapStatus().target, - (markLocation.getHeight() + 14), listener);//第三个参数调整infoWindow距离中心点的高度
mBaiduMap.showInfoWindow(mInfoWindow);
}
@Override
public void onAnimationCancel(Animator animation) { }
@Override
public void onAnimationRepeat(Animator animation) { }
});
//添加InfoWindow
final ImageView infoWindow= new ImageView(getApplicationContext());
infoWindow.setImageResource(R.drawable.icon_position_tips);
infoWindow.setMinimumHeight(DensityUtils.dp2px(this, 42));
infoWindow.setMinimumWidth(DensityUtils.dp2px(this, 91));
final InfoWindow.OnInfoWindowClickListener listener = new InfoWindow.OnInfoWindowClickListener() {
public void onInfoWindowClick() {
mBaiduMap.hideInfoWindow();
Toast.makeText(BaseMapDemo.this,
"定位成功" + mBaiduMap.getMapStatus().target.longitude +", " + mBaiduMap.getMapStatus().target.latitude,
Toast.LENGTH_LONG).show();
}
};
大功告成!在这里还要感谢群里的那位朋友Jin丶破的交流。
源码稍后会放到我的github上。
<strong>------------------------- 补充 -------------------------
使用小米手机发现无法定位,即onReceiveLocation
没有执行,纠结了大半天,在此提醒大家,一定要添加
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote" >
</service>
感谢:http://m.blog.csdn.net/article/details?id=50499795
补充----------------------------
Native method not found:
com.baidu.platform.comjni.engine.JNIEngine.initClass.
该问题是由于.so的没引入导致的。
为了调试方便,减少等待时间,编译时去掉了全部的so文件
buildTypes {
debug {
signingConfig signingConfigs.release
// 需要测趣拍注释掉这里然后rebuild !!
// 去掉全部的so文件!! 解决debug启动等太久(含lib so的apk有27MB)问题
//ndk { abiFilters "armeabi" }
}
release {
signingConfig signingConfigs.release
//开启混淆
minifyEnabled true
zipAlignEnabled true
// 移除无用的resource文件
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
跳转:百度论坛