引言
最近項(xiàng)目有在用高德地圖,順便記錄下一些知識髓介。項(xiàng)目需要做地圖上顯示一個(gè)車輛位置惕鼓,這個(gè)位置需要波紋擴(kuò)散效果,這個(gè)高德地圖也提供了demo唐础,但是看著效果不算很棒箱歧,比起iOS平臺的要差老遠(yuǎn)了。
Android平臺下載了例子瞅了一眼一膨,原理就是AMap.addCircle(CircleOptions options)呀邢,加上圓形之后,在一定的時(shí)間范圍內(nèi)動態(tài)改變圓的半徑豹绪,說白了也就是動畫价淌,官方demo使用Timer+TimerTask來實(shí)現(xiàn)的動畫。因?yàn)椴荒軡M足設(shè)計(jì)師的需求瞒津,而且不帶漸變色蝉衣,因此我決定用屬性動畫做了。
動態(tài)效果圖:
實(shí)現(xiàn)原理:添加了三個(gè)圓形巷蚪,每個(gè)圓形一開始設(shè)置透明病毡,每個(gè)圓形開始執(zhí)行動畫有個(gè)時(shí)間間隔,動態(tài)改變每個(gè)圓形半徑及填充顏色的透明度即可屁柏。_
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.amap.api.maps2d.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_marginBottom="30dp"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/zoom_in"
android:onClick="click"
android:layout_width="30dp"
android:src="@mipmap/zoom_in_72px_1180653_easyicon"
android:layout_height="30dp" />
<ImageView
android:id="@+id/zoom_out"
android:layout_width="30dp"
android:onClick="click"
android:layout_marginTop="10dp"
android:src="@mipmap/zoom_out_72px_1180654_easyicon"
android:layout_height="30dp" />
</LinearLayout>
<ImageView
android:id="@+id/location"
android:layout_width="30dp"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:onClick="click"
android:layout_marginBottom="30dp"
android:layout_marginTop="10dp"
android:src="@mipmap/location_searching_72px_1182025_easyicon"
android:layout_height="30dp" />
</RelativeLayout>
此處剪验,設(shè)計(jì)師還說了,放大縮小及定位圖標(biāo)都要用他設(shè)計(jì)的前联,所以都是自定義一個(gè)圖標(biāo)功戚。(這個(gè)例子幾個(gè)圖標(biāo)是我自己找的,有點(diǎn)辣雞)
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps2d.AMap;
import com.amap.api.maps2d.AMapOptions;
import com.amap.api.maps2d.CameraUpdate;
import com.amap.api.maps2d.CameraUpdateFactory;
import com.amap.api.maps2d.LocationSource;
import com.amap.api.maps2d.MapView;
import com.amap.api.maps2d.model.BitmapDescriptor;
import com.amap.api.maps2d.model.BitmapDescriptorFactory;
import com.amap.api.maps2d.model.Circle;
import com.amap.api.maps2d.model.CircleOptions;
import com.amap.api.maps2d.model.LatLng;
import com.amap.api.maps2d.model.Marker;
import com.amap.api.maps2d.model.MarkerOptions;
import com.amap.api.maps2d.model.MyLocationStyle;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends FragmentActivity implements AMap.OnMapLoadedListener, AMap.OnMapClickListener, LocationSource, AMapLocationListener {
private AMap aMap;
private MapView mapView;
private AMapLocationClient mLocationClient;
private AMapLocationClientOption mLocationOption;
private OnLocationChangedListener mListener;
private Marker locMarker;
private Circle ac;
private Circle c,d;
private TimerTask mTimerTask;
private Timer mTimer = new Timer();
public static final int zoomLevel = 15 ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.map);
mapView.onCreate(savedInstanceState);// 此方法必須重寫
init();
}
private void init() {
if (aMap == null) {
aMap = mapView.getMap();
}
aMap.setOnMapLoadedListener(this);
aMap.setOnMapClickListener(this);
aMap.setLocationSource(this);// 設(shè)置定位監(jiān)聽
aMap.getUiSettings().setZoomControlsEnabled(false);
aMap.getUiSettings().setMyLocationButtonEnabled(false);// 設(shè)置默認(rèn)定位按鈕是否顯示
aMap.setMyLocationEnabled(true);// 設(shè)置為true表示顯示定位層并可觸發(fā)定位似嗤,false表示隱藏定位層并不可觸發(fā)定位啸臀,默認(rèn)是false
// 設(shè)置定位的類型為定位模式 ,可以由定位烁落、跟隨或地圖根據(jù)面向方向旋轉(zhuǎn)幾種
aMap.setMyLocationStyle(new MyLocationStyle().myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE));
aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT);
}
public void click(View view){
int id =view.getId() ;
if (id==R.id.location){
startlocation();
}else if (id==R.id.zoom_in){
changeCamera(CameraUpdateFactory.zoomIn(), null);
}else if (id==R.id.zoom_out){
changeCamera(CameraUpdateFactory.zoomOut(), null);
}
}
/**
* 根據(jù)動畫按鈕狀態(tài)乘粒,調(diào)用函數(shù)animateCamera或moveCamera來改變可視區(qū)域
*/
private void changeCamera(CameraUpdate update, AMap.CancelableCallback callback) {
aMap.animateCamera(update, 300, callback);
// aMap.moveCamera(update); //無動畫的時(shí)候調(diào)用
}
private Marker addMarker(LatLng point) {
Bitmap bMap = BitmapFactory.decodeResource(this.getResources(),
R.mipmap.icon_bus_position);
BitmapDescriptor des = BitmapDescriptorFactory.fromBitmap(bMap);
Marker marker = aMap.addMarker(new MarkerOptions().position(point).icon(des)
.anchor(0.5f, 0.5f));
return marker;
}
/**
* 方法必須重寫
*/
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
/**
* 方法必須重寫
*/
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
/**
* 方法必須重寫
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
/**
* 方法必須重寫
*/
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
try {
mTimer.cancel();
} catch (Throwable e) {
e.printStackTrace();
}
deactivate();
}
@Override
public void onMapLoaded() {
aMap.moveCamera(CameraUpdateFactory.zoomTo(zoomLevel));
}
@Override
public void onMapClick(LatLng latLng) {
}
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
startlocation();
}
@Override
public void deactivate() {
mListener = null;
if (mLocationClient != null) {
mLocationClient.stopLocation();
mLocationClient.onDestroy();
}
mLocationClient = null;
}
/**
* 開始定位。
*/
private void startlocation() {
if (mLocationClient == null) {
mLocationClient = new AMapLocationClient(this);
mLocationOption = new AMapLocationClientOption();
// 設(shè)置定位監(jiān)聽
mLocationClient.setLocationListener(this);
// 設(shè)置為高精度定位模式
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//設(shè)置為單次定位
mLocationOption.setOnceLocation(true);
// 設(shè)置定位參數(shù)
mLocationClient.setLocationOption(mLocationOption);
mLocationClient.startLocation();
} else {
mLocationClient.startLocation();
}
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (mListener != null && aMapLocation != null) {
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
if (aMapLocation != null && aMapLocation.getErrorCode() == 0) {
LatLng mylocation = new LatLng(aMapLocation.getLatitude(),
aMapLocation.getLongitude());
changeCamera(CameraUpdateFactory.newLatLngZoom(mylocation,zoomLevel),null);
if (locMarker==null){
addLocationMarker(mylocation);
}else {
locMarker.setPosition(mylocation);
}
if (ac!=null){
ac.setCenter(mylocation);
}
if (c!=null){
c.setCenter(mylocation);
}
if (d!=null){
d.setCenter(mylocation);
}
} else {
String errText = "定位失敗," + aMapLocation.getErrorCode() + ": "
+ aMapLocation.getErrorInfo();
Log.e("AmapErr", errText);
}
}
}
/**
* 添加坐標(biāo)點(diǎn)伤塌,這里可以添加任意坐標(biāo)點(diǎn)位置
* @param mylocation
*/
private void addLocationMarker(LatLng mylocation) {
float accuracy = (float) ((mylocation.longitude/mylocation.latitude )*100);
if (locMarker == null) {
locMarker = addMarker(mylocation);
if (ac==null){
ac = aMap.addCircle(new CircleOptions().center(mylocation)
.fillColor(Color.argb(0, 98 ,189, 255)).radius(accuracy)
.strokeColor(Color.argb(0, 98, 198, 255)).strokeWidth(0));
}
if (c==null){
c = aMap.addCircle(new CircleOptions().center(mylocation)
.fillColor(Color.argb(0, 98, 198, 255))
.radius(accuracy).strokeColor(Color.argb(0,98, 198, 255))
.strokeWidth(0));
}
if (d==null){
d = aMap.addCircle(new CircleOptions().center(mylocation)
.fillColor(Color.argb(0, 98, 198, 255))
.radius(accuracy).strokeColor(Color.argb(0,98, 198, 255))
.strokeWidth(0));
}
} else {
locMarker.setPosition(mylocation);
ac.setCenter(mylocation);
ac.setRadius(accuracy);
c.setCenter(mylocation);
c.setRadius(accuracy);
d.setCenter(mylocation);
d.setRadius(accuracy);
}
handle.postDelayed(rb,0);
handle1.postDelayed(rb1,800);
handle2.postDelayed(rb2,1600);
}
/**
* 位置波紋擴(kuò)散動畫
* @param ac
*/
private void Scalecircle1(final Circle ac) {
ValueAnimator vm = ValueAnimator.ofFloat(0,(float)ac.getRadius());
vm.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float curent = (float) animation.getAnimatedValue();
ac.setRadius(curent);
aMap.invalidate();
}
});
ValueAnimator vm1 = ValueAnimator.ofInt(160,0);
vm1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int color = (int) animation.getAnimatedValue();
ac.setFillColor(Color.argb(color, 98, 198, 255));
aMap.invalidate();
}
});
vm.setRepeatCount(Integer.MAX_VALUE);
vm.setRepeatMode(ValueAnimator.RESTART);
vm1.setRepeatCount(Integer.MAX_VALUE);
vm1.setRepeatMode(ValueAnimator.RESTART);
AnimatorSet set = new AnimatorSet();
set.play(vm).with(vm1);
set.setDuration(2500);
set.setInterpolator(interpolator1);
set.start();
}
private final Interpolator interpolator1 = new LinearInterpolator();
Runnable rb = new Runnable() {
@Override
public void run() {
Scalecircle1(ac);
}
};
Handler handle =new Handler();
Runnable rb1 = new Runnable() {
@Override
public void run() {
Scalecircle1(c);
}
};
Handler handle1 =new Handler();
Runnable rb2 = new Runnable() {
@Override
public void run() {
Scalecircle1(d);
}
};
Handler handle2 =new Handler();
}
大部分代碼都是高德demo的灯萍,我改的是部分代碼。
需要注意的:
1每聪、需要用Handler+Runable延遲執(zhí)行動畫時(shí)間旦棉;
2齿风、每次定位成功只需要改變Marker的坐標(biāo)及Circle中心點(diǎn)就行;
3绑洛、圓的半徑例子是:float accuracy = aMapLocation.getAccuracy()救斑;但是地圖放大之后變得很小,打印出來看看發(fā)現(xiàn)這個(gè)值跟 :longitude/mylocation * 10差不多真屯,所以我這里直接用這個(gè)值脸候,并且還擴(kuò)大10倍了,如果放很大地圖的話绑蔫,會有大波O(∩_∩)O哈哈
4运沦、aMap.animateCamera(update, 300, callback); 自定義縮放及定位按鈕的關(guān)鍵代碼,這種是帶動畫的配深,當(dāng)放大縮小携添,或者定位都會帶動畫平滑移動地圖中心點(diǎn)。不用動畫的時(shí)候調(diào)用:aMap.moveCamera(update); 即可凉馆。
有不對的或者更好的方式,歡迎告知亡资,謝謝~