高德地图SDK Android版开发 8 覆盖物示例2动画
- 前言
- 动画相关的类和接口
-
- 帧动画
-
- Animation动画
-
- Animation类及其子类
-
- Animation
- TranslateAnimation
- RotateAnimation
- AlphaAnimation
- ScaleAnimation
- AnimationSet
- Marker动画示例
-
- 界面布局
- MapMarkAnimate类
-
- 常量
- 成员变量
- 初始值
- 创建覆盖物
-
- 创建Marker(帧动画)
- 创建Marker(Animation动画)
- 创建Marker(Demo动画)
- 创建Animation
- 移除覆盖物
- 设置属性
- 加载地图和释放地图
- MapMarkerAnimationActivity类
-
- 运行效果图
前言
前文介绍了高德地图Marker
支持多种动画类型:
- 帧动画;
Animation
动画(包括平移、旋转、透明、缩放和组合动画)。
本文重点介绍Marker
动画相关的类和接口,以及示例代码。
动画相关的类和接口
帧动画
帧动画的功能通过MarkerOptions
类来设置,一次传入一个Icon列表,通过period
设定刷新的帧间隔。
MarkerOptions
类型 |
方法 |
说明 |
MarkerOptions |
icons (ArrayList< BitmapDescriptor > icons) |
设置Marker覆盖物的动画帧图标列表,多张图片模拟gif的效果。 |
MarkerOptions |
period (int period) |
设置多少帧刷新一次图片资源,Marker动画的间隔时间,值越小动画越快。 |
Animation动画
Marker还支持设置旋转、缩放、平移、透明和组合动画效果。通过Marker类setAnimation方法设置。
类 |
说明 |
说明 |
void |
setAnimation (Animation animation) |
设置动画。动画包含,旋转,缩放,消失,平移以及它们的组合动画 |
boolean |
startAnimation () |
开始动画 |
Animation类及其子类
动画类别 |
类 |
说明 |
抽象类 |
Animation |
动画,可用于支持动画的覆盖物。使用方法如同Android系统自带的Animation |
移动动画 |
TranslateAnimation |
控制移动的动画类 |
旋转动画 |
RotateAnimation |
控制旋转的动画类 |
透明度动画 |
AlphaAnimation |
控制透明度的动画类 |
缩放动画 |
ScaleAnimation |
控制缩放的动画类 |
组合动画 |
AnimationSet |
动画集合 |
TranslateAnimation
+TranslateAnimation(latLng)
#String getAnimationType()
Animation
+int getFillMode()
+int getRepeatCount()
+int getRepeatMode()
+void setAnimationListener(listener)
+void setDuration(duration)
+void setFillMode(fillMode)
+void setInterpolator(interpolator)
+void setRepeatCount(repeatCount)
+void setRepeatMode(repeatMode)
RotateAnimation
+RotateAnimation(fromdegree, todegree)
#String getAnimationType()
AlphaAnimation
+AlphaAnimation(fromAlpha, toAlpha)
#String getAnimationType()
ScaleAnimation
+ScaleAnimation(fromX, toX, fromY, toY)
#String getAnimationType()
AnimationSet
+AnimationSet(shareInterpolator)
+void addAnimation(animation)
+void cleanAnimation()
#String getAnimationType()
Animation
类 |
说明 |
说明 |
int |
getFillMode () |
获取动画执行完成后的状态 |
int |
getRepeatCount () |
获取动画重复执行的次数 |
int |
getRepeatMode () |
重复执行的模式 |
void |
setAnimationListener (Animation.AnimationListener listener) |
设置动画监听器 |
void |
setDuration (long duration) |
设置动画持续时间。如果设置为负数,会修正为0 |
void |
setFillMode (int fillMode) |
设置动画执行完成后的状态。默认FILL_MODE_FORWARDS |
void |
setInterpolator (Interpolator interpolator) |
设置插值器。默认是线性插值器 |
void |
setRepeatCount (int repeatCount) |
设置动画重复执行的次数。默认为0 |
void |
setRepeatMode (int repeatMode) |
重复执行的模式。默认RESTART |
类型 |
常量 |
说明 |
static int |
FILL_MODE_BACKWARDS |
动画执行后保持在第一帧 |
static int |
FILL_MODE_FORWARDS |
动画执行后保持在最后一帧 |
static int |
INFINITE |
无限期地重复动画 |
static int |
RESTART |
动画结束后从头播放,最大重复次数受Animation.setRepeatCount(int) 限制 |
static int |
REVERSE |
动画结束后从尾倒放,最大重复次数受Animation.setRepeatCount(int) 限制 |
animation.setRepeatMode(Animation.RESTART);
animation.setFillMode(Animation.FILL_MODE_BACKWARDS);
animation.setRepeatCount(Animation.INFINITE);
public interface AnimationListener {
void onAnimationStart();
void onAnimationEnd();
}
TranslateAnimation
类 |
说明 |
说明 |
|
TranslateAnimation (LatLng target) |
控制移动的动画类 |
protected String |
getAnimationType () |
|
RotateAnimation
类 |
说明 |
说明 |
|
RotateAnimation (float fromdegree, float todegree) |
控制旋转的动画类 |
protected String |
getAnimationType () |
|
AlphaAnimation
类 |
说明 |
说明 |
|
AlphaAnimation (float fromAlpha, float toAlpha) |
控制透明度的动画类。 透明度范围[0,1], 1为不透明 |
protected String |
getAnimationType () |
|
ScaleAnimation
类 |
说明 |
说明 |
|
ScaleAnimation (float fromX, float toX, float fromY, float toY) |
控制缩放的动画类。 比如要实现一个Marker生长动画,可以使用 (0,1,0,1) |
protected String |
getAnimationType () |
|
AnimationSet
类 |
说明 |
说明 |
|
AnimationSet (boolean shareInterpolator) |
动画集合 |
void |
addAnimation (Animation animation) |
添加动画 |
void |
cleanAnimation () |
清除动画 |
protected String |
getAnimationType () |
|
Marker动画示例
本示例包括帧动画、Animation动画,以及官方Demo中的生长、跳跃和呼吸动画。
界面布局
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MapMarkerAnimationActivity">
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/bottomView"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/bottomView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/map">
<RadioGroup
android:id="@+id/RadioGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/background_dark"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingHorizontal="10dp">
<RadioButton
android:id="@+id/frameAnimation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:checked="true"
android:onClick="setAnimationFlag"
android:text="帧动画"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/animation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="setAnimationFlag"
android:text="Animation动画"
android:textColor="@color/white"
android:textStyle="bold" />
<RadioButton
android:id="@+id/demoAnimation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="setAnimationFlag"
android:text="Demo动画"
android:textColor="@color/white"
android:textStyle="bold" />
RadioGroup>
androidx.appcompat.widget.LinearLayoutCompat>
androidx.constraintlayout.widget.ConstraintLayout>
MapMarkAnimate类
常量
public final static String FRAME_ANIMATION = "Frame";
public final static String TRANSFORMATION_ANIMATION = "Transformation";
public final static String ROTATE_ANIMATION = "Rotate";
public final static String ALPHA_ANIMATION = "Alpha";
public final static String SCALE_ANIMATION = "Scale";
public final static String SINGLE_SCALE_ANIMATION = "SingleScale";
public final static String ANIMATION_SET = "AnimationSet";
public final static String DEMO_GROW_ANIMATION = "Grow";
public final static String DEMO_JUMP_ANIMATION = "Jump";
public final static String DEMO_BREATHE_ANIMATION = "Breathe";
成员变量
List<BaseOverlay> overlays = new ArrayList<>();
List<String> selectedFlags = new ArrayList<>();
List<LatLng> points = new ArrayList<>();
ArrayList<BitmapDescriptor> bitmaps = new ArrayList<>();
BitmapDescriptor circleBitmap;
初始值
selectedFlags.add(FRAME_ANIMATION);
selectedFlags.add(FRAME_ANIMATION);
selectedFlags.add(FRAME_ANIMATION);
points.add(new LatLng(39.97923, 116.357428));
points.add(new LatLng(39.94923, 116.397428));
points.add(new LatLng(39.97923, 116.437428));
points.add(new LatLng(39.92353, 116.490705));
points.add(new LatLng(40.023537, 116.289429));
points.add(new LatLng(40.022211, 116.406137));
int[] drawableIds = BubbleIcons.Number;
for (int drawableId : drawableIds) {
BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(drawableId);
bitmaps.add(bitmap);
}
circleBitmap = BitmapDescriptorFactory.fromResource(R.drawable.marker_circle_64);
创建覆盖物
public void addMarkers() {
if (selectedFlags.isEmpty())
return;
int markerSize = selectedFlags.size();
for (int i = 0; i < markerSize; ++i) {
LatLng point = points.get(i);
String flag = selectedFlags.get(i);
switch (flag) {
case FRAME_ANIMATION:
addFrameAnimation(point, bitmaps);
break;
case DEMO_GROW_ANIMATION:
case DEMO_JUMP_ANIMATION:
addSampleAnimation(point, bitmaps.get(i), flag);
break;
case DEMO_BREATHE_ANIMATION:
addBreatheAnimation(point);
break;
default:
addAnimation(point, bitmaps.get(i), flag);
break;
}
}
}
创建Marker(帧动画)
private void addFrameAnimation(LatLng point, ArrayList<BitmapDescriptor> bitmaps) {
MarkerOptions option = new MarkerOptions()
.position(point)
.icons(bitmaps)
.period(10);
Marker marker = map.addMarker(option);
overlays.add(marker);
}
创建Marker(Animation动画)
private void addAnimation(LatLng point, BitmapDescriptor bitmap, String flag) {
Animation animation = null;
switch (flag) {
case TRANSFORMATION_ANIMATION:
animation = getTransformation(point);
break;
case ROTATE_ANIMATION:
animation = getRotateAnimation();
break;
case ALPHA_ANIMATION:
animation = getAlphaAnimation();
break;
case SCALE_ANIMATION:
animation = getScaleAnimation();
break;
case SINGLE_SCALE_ANIMATION:
animation = getSingleScaleAnimation();
break;
case ANIMATION_SET:
animation = getAnimationSet();
break;
}
if (animation == null)
return;
MarkerOptions option = new MarkerOptions()
.position(point)
.icon(bitmap);
Marker marker = map.addMarker(option);
overlays.add(marker);
marker.setAnimation(animation);
marker.startAnimation();
}
创建Marker(Demo动画)
private void addSampleAnimation(LatLng point, BitmapDescriptor bitmap, String flag) {
Animation animation = null;
switch (flag) {
case DEMO_GROW_ANIMATION:
animation = getGrowAnimation();
break;
case DEMO_JUMP_ANIMATION:
animation = getJumpAnimation(point);
break;
}
if (animation == null)
return;
MarkerOptions option = new MarkerOptions()
.position(point)
.icon(bitmap);
Marker marker = map.addMarker(option);
overlays.add(marker);
marker.setAnimation(animation);
marker.startAnimation();
}
private void addBreatheAnimation(LatLng point) {
MarkerOptions option = new MarkerOptions()
.position(point)
.icon(circleBitmap)
.anchor(0.5f, 0.5f)
.zIndex(1);
Marker breatheMarker = map.addMarker(option);
overlays.add(breatheMarker);
MarkerOptions centerOption = new MarkerOptions()
.position(point)
.icon(circleBitmap)
.anchor(0.5f, 0.5f)
.zIndex(2);
Marker centerMarker = map.addMarker(centerOption);
overlays.add(centerMarker);
Animation animation = AnimationFactory.getBreatheAnimation();
breatheMarker.setAnimation(animation);
breatheMarker.startAnimation();
}
创建Animation
- 创建平移动画、旋转动画、透明度动画、缩放动画、单边缩放动画、创建组合动画、生长动画、跳跃动画、呼吸动画。
Animation getTransformation(LatLng point) {
Point pt1 = map.getProjection().toScreenLocation(point);
Point pt2 = new Point(pt1.x, pt1.y - 100);
LatLng toPoint = map.getProjection().fromScreenLocation(pt2);
TranslateAnimation animation = new TranslateAnimation(toPoint);
animation.setDuration(500);
animation.setRepeatMode(Animation.RESTART);
animation.setRepeatCount(1);
animation.setFillMode(Animation.FILL_MODE_BACKWARDS);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart() {
}
@Override
public void onAnimationEnd() {
}
});
return animation;
}
Animation getRotateAnimation() {
RotateAnimation animation = new RotateAnimation(0f, 360f);
animation.setDuration(1000);
animation.setRepeatMode(Animation.RESTART);
animation.setRepeatCount(1);
animation.setFillMode(Animation.FILL_MODE_BACKWARDS);
return animation;
}
Animation getAlphaAnimation() {
float fromAlpha = 1.0f;
float toAlpha = 0.5f;
AlphaAnimation animation = new AlphaAnimation(fromAlpha, toAlpha);
animation.setDuration(3000);
animation.setRepeatMode(Animation.RESTART);
animation.setRepeatCount(1);
animation.setFillMode(Animation.FILL_MODE_BACKWARDS);
return animation;
}
Animation getScaleAnimation() {
float fromX = 1.0f;
float toX = 2.0f;
float fromY = 1.0f;
float toY = 2.0f;
ScaleAnimation animation = new ScaleAnimation(fromX, toX, fromY, toY);
animation.setDuration(2000);
animation.setRepeatMode(Animation.RESTART);
animation.setRepeatCount(1);
animation.setFillMode(Animation.FILL_MODE_BACKWARDS);
return animation;
}
Animation getSingleScaleAnimation() {
float fromX = 1.0f;
float toX = 2.0f;
float fromY = 1.0f;
float toY = 1.0f;
ScaleAnimation animation = new ScaleAnimation(fromX, toX, fromY, toY);
animation.setDuration(1000);
animation.setRepeatMode(Animation.RESTART);
animation.setRepeatCount(1);
animation.setFillMode(Animation.FILL_MODE_BACKWARDS);
return animation;
}
Animation getAnimationSet() {
boolean shareInterpolator = true;
AnimationSet animation = new AnimationSet(shareInterpolator);
animation.addAnimation(getAlphaAnimation());
animation.addAnimation(getRotateAnimation());
animation.addAnimation(getScaleAnimation());
animation.setInterpolator(new LinearInterpolator());
return animation;
}
Animation getGrowAnimation() {
float fromX = 0.0f;
float toX = 1.0f;
float fromY = 0.0f;
float toY = 1.0f;
ScaleAnimation animation = new ScaleAnimation(fromX, toX, fromY, toY);
animation.setInterpolator(new LinearInterpolator());
animation.setDuration(1000);
return animation;
}
Animation getJumpAnimation(LatLng point) {
Point pt1 = map.getProjection().toScreenLocation(point);
Point pt2 = new Point(pt1.x, pt1.y - 100);
LatLng toPoint = map.getProjection().fromScreenLocation(pt2);
Animation animation = new TranslateAnimation(toPoint);
animation.setInterpolator(new Interpolator() {
@Override
public float getInterpolation(float input) {
if (input <= 0.5) {
return (float) (0.5f - 2 * (0.5 - input) * (0.5 - input));
} else {
return (float) (0.5f - Math.sqrt((input - 0.5f) * (1.5f - input)));
}
}
});
animation.setDuration(600);
return animation;
}
Animation getBreatheAnimation() {
boolean shareInterpolator = true;
AnimationSet animationSet = new AnimationSet(shareInterpolator);
float fromAlpha = 0.5f;
float toAlpha = 0f;
AlphaAnimation alphaAnimation = new AlphaAnimation(fromAlpha, toAlpha);
alphaAnimation.setDuration(2000);
alphaAnimation.setRepeatCount(Animation.INFINITE);
float fromX = 1.0f;
float toX = 3.5f;
float fromY = 1.0f;
float toY = 3.5f;
ScaleAnimation scaleAnimation = new ScaleAnimation(fromX, toX, fromY, toY);
scaleAnimation.setDuration(2000);
scaleAnimation.setRepeatCount(Animation.INFINITE);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.setInterpolator(new LinearInterpolator());
return animationSet;
}
移除覆盖物
public void removeOverlay() {
for (BaseOverlay overlay : overlays) {
if (overlay instanceof Marker) {
Marker marker = (Marker) overlay;
marker.remove();
}
}
overlays.clear();
}
设置属性
public void setFlags(List<String> flags) {
selectedFlags.clear();
selectedFlags.addAll(flags);
removeOverlay();
addMarkers();
}
加载地图和释放地图
public void onMapLoaded() {
addMarkers();
}
public void onMapDestroy() {
removeOverlay();
for (BitmapDescriptor bitmap : bitmaps) {
bitmap.recycle();
}
bitmaps = null;
if (circleBitmap != null)
circleBitmap.recycle();
circleBitmap = null;
}
MapMarkerAnimationActivity类
- 以下是
MapMarkerAnimationActivity
类部分代码
控件响应事件
public void setAnimationFlag(View view) {
boolean checked = ((RadioButton) view).isChecked();
int id = view.getId();
if (!checked)
return;
List<String> flags;
if (id == R.id.frameAnimation) {
flags = Arrays.asList(
MapMarkerAnimation.FRAME_ANIMATION,
MapMarkerAnimation.FRAME_ANIMATION,
MapMarkerAnimation.FRAME_ANIMATION);
} else if (id == R.id.animation) {
flags = Arrays.asList(
MapMarkerAnimation.TRANSFORMATION_ANIMATION,
MapMarkerAnimation.ROTATE_ANIMATION,
MapMarkerAnimation.ALPHA_ANIMATION,
MapMarkerAnimation.SCALE_ANIMATION,
MapMarkerAnimation.SINGLE_SCALE_ANIMATION,
MapMarkerAnimation.ANIMATION_SET);
} else if (id == R.id.demoAnimation) {
flags = Arrays.asList(
MapMarkerAnimation.DEMO_GROW_ANIMATION,
MapMarkerAnimation.DEMO_JUMP_ANIMATION,
MapMarkerAnimation.DEMO_BREATHE_ANIMATION);
} else {
return;
}
mapMarkerAnimation.setFlags(flags);
}
运行效果图