前言
前文介绍了百度地图Marker支持多种动画类型:
- 帧动画;
- 加载动画(包括从天上掉下、从地下生长和跳跃动画);
-
Animation动画(包括平移、旋转、透明、缩放、单边缩放和组合动画)。
本文重点介绍Marker动画相关的类和接口,以及示例代码。
动画相关的类和接口
帧动画
帧动画的功能通过MarkerOptions类来设置,一次传入一个Icon列表,通过period设定刷新的帧间隔。
MarkerOptions
| 类型 |
方法 |
说明 |
| MarkerOptions |
icons(ArrayList< BitmapDescriptor > icons) |
设置 Marker 覆盖物的图标,相同图案的 icon 的 marker 最好使用同一个 BitmapDescriptor 对象以节省内存空间。 |
| MarkerOptions |
period(int period) |
设置多少帧刷新一次图片资源,Marker动画的间隔时间,值越小动画越快。 |
| MarkerOptions |
interval(int mInterval) |
v7.6.0新增接口。设置marker多帧图片播放时间间隔(ms)。 地图绘制方式升级为overlay2.0时,该接口生效。 |
加载动画
自v3.6.0版本起,SDK提供了加载Marker时的动画效果,通过animateType设置动画类型。
MarkerOptions
| 类型 |
方法 |
说明 |
| MarkerOptions |
animateType(MarkerOptions.MarkerAnimateType type) |
设置marker动画类型,见 MarkerAnimateType(从天上掉下,从地下生长,跳跃),默认无动画 |
MarkerOptions.MarkerAnimateType 动画类型
| 位置 |
说明 |
MarkerOptions.MarkerAnimateType.none |
没效果 |
MarkerOptions.MarkerAnimateType.drop |
从天上掉下 |
MarkerOptions.MarkerAnimateType.grow |
从地面生长 |
MarkerOptions.MarkerAnimateType.jump |
跳动 |
Animation动画
Marker还支持设置旋转、缩放、平移、透明和组合动画效果。通过Marker类setAnimation方法设置。
Marker
| 类型 |
方法 |
说明 |
| void |
setAnimation(Animation animation) |
设置 Marker 覆盖物的动画 |
| void |
setAnimation(Animation animation, TypeEvaluator typeEvaluator) |
设置 Marker 覆盖物的动画与估值器 |
| void |
startAnimation() |
开启 Marker 覆盖物的动画 |
| void |
cancelAnimation() |
取消 Marker 覆盖物的动画 |
Animation类及其子类
| 动画类别 |
类 |
说明 |
| 抽象类 |
Animation |
Marker 动画接口类 |
| 平移动画 |
Transformation |
Marker 平移动画接口类 |
| 旋转动画 |
RotateAnimation |
Marker 旋转动画接口类 |
| 透明度动画 |
AlphaAnimation |
Marker 透明动画接口类 |
| 缩放动画 |
ScaleAnimation |
Marker 缩放动画接口类 |
| 单边缩放动画(X或Y方向) |
SingleScaleAnimation |
Marker X或Y方向单独缩放动画类 |
| 组合动画 |
AnimationSet |
Marker 动画集合接口类 |
Animation
| 类型 |
方法 |
说明 |
| long |
getDuration() |
获取设置动画持续时间 |
| int |
getRepeatCount() |
获取动画重复执行的次数。默认为0 |
| Animation.RepeatMode |
getRepeatMode() |
重复模式 |
| abstract void |
setAnimationListener(Animation.AnimationListener animationListener) |
设置 Marker 动画监听 |
| abstract void |
setDuration(long duration) |
设置 Marker 动画执行时间 |
| abstract void |
setInterpolator(Interpolator interpolator) |
设置 Marker 动画插值器 |
| abstract void |
cancel() |
取消 Marker 动画 |
-
Animation.RepeatMode 重复执行模式
| 枚举常量 |
说明 |
Animation.RepeatMode.RESTART |
动画结束后从头播放,最大重复次数受RepeatCount限制 |
Animation.RepeatMode.REVERSE |
动画结束后从尾倒放,最大重复次数受RepeatCount限制 |
// 动画侦听
public interface AnimationListener {
// 动画开始回调
void onAnimationStart();
// 动画结束回调
void onAnimationEnd();
// 动画取消回调
void onAnimationCancel();
// 动画重复回调
void onAnimationRepeat();
}
Transformation
| 类型 |
方法 |
说明 |
|
Transformation(LatLng... values) |
构造 |
|
Transformation(Point... values) |
构造 |
| void |
setRepeatCount(int repeatCount) |
设置 Marker 动画重复次数 |
| void |
setRepeatMode(Animation.RepeatMode repeatMode) |
设置 Marker 动画重复模式 |
RotateAnimation
| 类型 |
方法 |
说明 |
|
RotateAnimation(float fromDegrees, float toDegrees) |
构造 |
| float |
getFromDegrees() |
|
| float |
getToDegrees() |
|
| void |
setRepeatCount(int repeatCount) |
设置 Marker 动画重复次数 |
| void |
setRepeatMode(Animation.RepeatMode repeatMode) |
设置 Marker 动画重复模式 |
AlphaAnimation
| 类型 |
方法 |
说明 |
|
AlphaAnimation(float... alpha) |
|
| float[] |
getAlpha() |
|
| void |
setRepeatCount(int repeatCount) |
设置 Marker 动画重复次数 |
| void |
setRepeatMode(Animation.RepeatMode repeatMode) |
设置 Marker 动画重复模式 |
ScaleAnimation
| 类型 |
方法 |
说明 |
|
ScaleAnimation(float... scale) |
|
| float[] |
getScale() |
|
| void |
setRepeatCount(int repeatCount) |
设置 Marker 动画重复次数 |
| void |
setRepeatMode(Animation.RepeatMode repeatMode) |
设置 Marker 动画重复模式 |
SingleScaleAnimation
| 类型 |
方法 |
说明 |
|
SingleScaleAnimation(SingleScaleAnimation.ScaleType scaleType, float... scale) |
|
| float[] |
getScale() |
|
| SingleScaleAnimation.ScaleType |
getScaleType() |
|
| void |
setRepeatCount(int repeatCount) |
设置 Marker 动画重复次数 |
| void |
setRepeatMode(Animation.RepeatMode repeatMode) |
设置 Marker 动画重复模式 |
-
SingleScaleAnimation.ScaleType 单边缩放类型
| 枚举常量 |
说明 |
SingleScaleAnimation.ScaleType.SCALE_X |
Marker X方向单独缩放动画 |
SingleScaleAnimation.ScaleType.SCALE_Y |
Marker Y方向单独缩放动画 |
AnimationSet
| 类型 |
方法 |
说明 |
|
AnimationSet() |
构造 |
| void |
addAnimation(Animation animation) |
向 Marker 动画集合中添加动画 |
| void |
setAnimatorSetMode(int combinationMode) |
设置 Marker 集合动画播放模式 0:组合播放 1:顺序播放 |
Marker动画示例
界面布局
<?xml version="1.0" encoding="utf-8"?>
<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.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clickable="true"
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/bmapView">
<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/loadAnimation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
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" />
</RadioGroup>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
MapMarkAnimate类
常量
public final static String FRAME_ANIMATION = "Frame"; // 帧动画
public final static String DROP_ANIMATION = "Drop"; // 加载动画 从天上掉下
public final static String GROW_ANIMATION = "Grow"; // 加载动画 从地下生长
public final static String JUMP_ANIMATION = "Jump"; // 加载动画 跳跃
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"; // 单边缩放动画 X或Y方向
public final static String ANIMATION_SET = "AnimationSet"; // 组合动画
成员变量
// 覆盖物列表
List<Overlay> overlays = new ArrayList<>();
// 选中的状态
List<String> selectedFlags = new ArrayList<>();
// 坐标点集
List<LatLng> points = new ArrayList<>();
ArrayList<BitmapDescriptor> bitmaps = new ArrayList<>();
初始值
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));
// 相同图案的 icon 的 marker 最好使用同一个 BitmapDescriptor 对象以节省内存空间。
int[] drawableIds = BubbleIcons.Number;
for (int drawableId : drawableIds) {
BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(drawableId);
bitmaps.add(bitmap);
}
创建覆盖物
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 DROP_ANIMATION:
case GROW_ANIMATION:
case JUMP_ANIMATION:
addLoadAnimation(point, bitmaps.get(i), flag);
break;
default:
addAnimation(point, bitmaps.get(i), flag);
break;
}
}
}
创建Marker(帧动画)
MarkerOptions option = new MarkerOptions()
.position(point)
.icons(bitmaps) // 设置覆盖物的图标
.period(10); // 设置多少帧刷新一次图片资源,值越小动画越快 默认为20,最小为1
Marker marker = (Marker) map.addOverlay(option);
overlays.add(marker);
创建Marker(加载动画)
private void addLoadAnimation(LatLng point, BitmapDescriptor bitmap, String flag) {
MarkerOptions.MarkerAnimateType type = MarkerOptions.MarkerAnimateType.none;
switch (flag) {
case DROP_ANIMATION:
type = MarkerOptions.MarkerAnimateType.drop;
break;
case GROW_ANIMATION:
type = MarkerOptions.MarkerAnimateType.grow;
break;
case JUMP_ANIMATION:
type = MarkerOptions.MarkerAnimateType.jump;
break;
}
if (type == MarkerOptions.MarkerAnimateType.none)
return;
MarkerOptions option = new MarkerOptions()
.position(point) // 设置覆盖物的位置坐标
.icon(bitmap) // 设置覆盖物的图标,
.animateType(type); // 设置动画类型
Marker marker = (Marker) map.addOverlay(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 = (Marker) map.addOverlay(option);
overlays.add(marker);
marker.setAnimation(animation);
marker.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);
Transformation animation = new Transformation(point, toPoint, point);
// 设置动画执行时间
animation.setDuration(500);
// 设置动画重复模式
animation.setRepeatMode(Animation.RepeatMode.RESTART);
// 设置动画重复次数
animation.setRepeatCount(1);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart() {
}
@Override
public void onAnimationEnd() {
}
@Override
public void onAnimationCancel() {
}
@Override
public void onAnimationRepeat() {
}
});
return animation;
}
// 创建旋转动画
Animation getRotateAnimation() {
RotateAnimation animation = new RotateAnimation(0f, 360f);
// 设置动画执行时间
animation.setDuration(1000);
// 设置动画重复模式
animation.setRepeatMode(Animation.RepeatMode.RESTART);
// 设置动画重复次数
animation.setRepeatCount(1);
return animation;
}
// 创建透明度动画
Animation getAlphaAnimation() {
AlphaAnimation animation = new AlphaAnimation(1f, 0f, 1f);
// 设置动画执行时间
animation.setDuration(3000);
// 设置动画重复模式
animation.setRepeatMode(Animation.RepeatMode.RESTART);
// 设置动画重复次数
animation.setRepeatCount(1);
return animation;
}
// 创建缩放动画
Animation getScaleAnimation() {
float scale1 = 1.0f;
float scale2 = 2.0f;
ScaleAnimation animation = new ScaleAnimation(scale1, scale2, scale1);
// 设置动画执行时间
animation.setDuration(2000);
// 设置动画重复模式
animation.setRepeatMode(Animation.RepeatMode.RESTART);
// 设置动画重复次数
animation.setRepeatCount(1);
return animation;
}
// 创建单边缩放动画
Animation getSingleScaleAnimation() {
SingleScaleAnimation.ScaleType scaleType = SingleScaleAnimation.ScaleType.SCALE_X;
float scale1 = 1.0f;
float scale2 = 2.0f;
SingleScaleAnimation animation = new SingleScaleAnimation(scaleType,
scale1, scale2, scale1);
// 设置动画执行时间
animation.setDuration(1000);
// 设置动画重复模式
animation.setRepeatMode(Animation.RepeatMode.RESTART);
// 设置动画重复次数
animation.setRepeatCount(1);
return animation;
}
// 创建组合动画
Animation getAnimationSet() {
// 动画集合接口类
AnimationSet animation = new AnimationSet();
// 向动画集合中添加动画
animation.addAnimation(getAlphaAnimation());
animation.addAnimation(getRotateAnimation());
animation.addAnimation(getSingleScaleAnimation());
animation.addAnimation(getScaleAnimation());
// 设置集合动画播放模式 0:组合播放 1:顺序播放
animation.setAnimatorSetMode(0);
// 设置动画插值器
animation.setInterpolator(new LinearInterpolator());
return animation;
}
移除覆盖物
public void removeOverlay() {
//map.removeOverLays(overlays);
for (Overlay overlay : overlays) {
if (overlay instanceof Marker) {
((Marker) overlay).cancelAnimation();
}
overlay.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;
}
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.loadAnimation) {
flags = Arrays.asList(
MapMarkerAnimation.DROP_ANIMATION,
MapMarkerAnimation.GROW_ANIMATION,
MapMarkerAnimation.JUMP_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 {
return;
}
mapMarkerAnimation.setFlags(flags);
}
运行效果图