前言
前文介绍了腾讯地图Marker
支持多种动画类型:
- 帧动画;
-
Animation
动画(包括平移、旋转、透明、缩放和组合动画)。
本文重点介绍Marker
动画相关的类和接口,以及示例代码。
动画相关的类和接口
帧动画
Marke支持轮播的功能。BitmapDescriptorFactory.fromBitmaps(Bitmap... bitmaps)
可创建多图BitmapDescriptor
对象,通过icon
方法传入多图,并通过iconLooper
设定轮播模式。
类型 |
方法 |
说明 |
MarkerOptions |
icon (BitmapDescriptor icon) |
设置标注的样式 |
MarkerOptions |
iconLooper (boolean enable) |
设置图标轮播模式。默认周期时长为300ms |
MarkerOptions |
iconLooper (boolean enable, int duration) |
设置图标轮播模式 |
-
BitmapDescriptorFactory
类
类型 |
方法 |
说明 |
static BitmapDescriptor |
fromBitmaps (Bitmap... bitmaps) |
创建多图BitmapDescriptor对象。 |
static BitmapDescriptor |
fromBitmaps (TencentMapContext context, Bitmap... bitmaps) |
创建多图BitmapDescriptor对象。 |
Animation动画
Marker
还支持Animation
动画,目前支持平移、缩放、旋转、渐变和组合动画。通过Marker
的setAnimation
方法设置。
Marker接口继承关系
-
Marker
继承自多个接口类。
- 其中
Animationable
包括动画相关的方法。
类型 |
方法 |
说明 |
void |
setAnimation (animation); |
设置 Marker 覆盖物的动画 |
boolean |
startAnimation (); |
开启 Marker 覆盖物的动画 |
void |
startAnimation (animation); |
设置并开启 Marker 覆盖物的动画 |
- 注意:平移动画若要恢复起始位置时,可在动画开始前后,分别调用
Marker
类下面两个方法:
类型 |
方法 |
说明 |
void |
setFixingPoint (int x, int y) |
设置这个Marker固定在屏幕上的坐标点。 |
void |
setFixingPointEnable (boolean bFix) |
设置这个Marker是否可以固定在屏幕上不动 |
Animation 接口类及其子接口类
动画类别 |
接口类 |
说明 |
接口 |
Animation |
地图Overlay的动画基类 |
平移动画 |
ITranslateAnimation |
创建动画使用 TencentMapComponent.createTranslateAnimation(LatLng)
|
旋转动画 |
IRotateAnimation |
创建动画使用
TencentMapComponent.createRotateAnimation(float, float, float, float, float)
|
渐变动画 |
IAlphaAnimationAlpha |
创建动画使用 TencentMapComponent.createAlphaAnimation(float, float)
|
缩放动画 |
IScaleAnimation |
创建动画使用 TencentMapComponent.createScaleAnimation(float, float, float, float)
|
一组动画 |
IAnimationSet |
创建动画使用
TencentMapComponent.createAnimationSet(boolean)
|
|
IEmergeAnimation |
这个动画最初是给Polyline出现时用的 创建动画使用 TencentMapComponent.createEmergeAnimation(LatLng) |
-
TencentMap
地图接口和TencentMapComponent
地图组件接口关系如下图:
Animationable
类型 |
方法 |
说明 |
AnimationListener |
getAnimationListener () |
获取动画监听 |
long |
getDuration () |
获取动画时长 |
Interpolator |
getInterpolator () |
获取拦截器 |
void |
setAnimationListener (AnimationListener listener) |
设置动画的状态回调 |
void |
setDuration (long duration) |
设置动画的持续时间 |
void |
setInterpolator (Interpolator interpolator) |
设置动画播放进度的拦截器 |
// 动画播放的状态监听器
public interface AnimationListener {
// 动画开始播放回调函数
void onAnimationStart();
// 动画结束播放回调
void onAnimationEnd();
}
IAnimationSet
类型 |
方法 |
说明 |
boolean |
addAnimation (Animation animation) |
添加一个动画 |
void |
cleanAnimation () |
清除所有动画 |
TencentMapComponent 地图组件接口类
类型 |
方法 |
说明 |
ITranslateAnimation |
createTranslateAnimation (LatLng target) |
创建平移动画 |
IRotateAnimation |
createRotateAnimation (float fromdegree, float todegree, float pivotx, float pivoty, float pivotz) |
创建旋转动画 |
IAlphaAnimation |
createAlphaAnimation (float fromAlpha, float toAlpha) |
创建渐变动画 |
IScaleAnimation |
createScaleAnimation (float fromX, float toX, float fromY, float toY) |
创建缩放动画 |
IAnimationSet |
createAnimationSet (boolean shareInterpolator) |
创建动画集合 |
IEmergeAnimation |
createEmergeAnimation(LatLng startPoint) |
创建动画从哪点开始然后向两端扩展,当然也可以设置为起点或是终点。 |
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.tencent.tencentmap.mapsdk.maps.TextureMapView
android:id="@+id/mapview"
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/mapview">
<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" />
</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"; // 单边缩放动画 X或Y方向
public final static String ANIMATION_SET = "AnimationSet"; // 组合动画
成员变量
// 覆盖物列表
List<Removable> 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));
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;
default:
addAnimation(point, bitmaps.get(i), flag);
break;
}
}
}
创建Marker(帧动画)
private void addFrameAnimation(LatLng point, ArrayList<BitmapDescriptor> bitmaps) {
Bitmap[] icons = new Bitmap[bitmaps.size()];
for (int i = 0; i < bitmaps.size(); ++i) {
icons[i] = bitmaps.get(i).getBitmap(context);
}
// 创建多图BitmapDescriptor对象。
BitmapDescriptor icon = BitmapDescriptorFactory.fromBitmaps(icons);
boolean enable = true;// 是否轮播
int duration = 1000; // 轮播时间(ms)
MarkerOptions option = new MarkerOptions(point)
.icon(icon)
.iconLooper(enable, duration) // 设置图标轮播模式
.anchor(0.5f, 1.0f); // 设置标注的锚点。默认值为 0.5f, 0.5f
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(point)
.icon(bitmap)
.anchor(0.5f, 1.0f); // 设置标注的锚点。默认值为 0.5f, 0.5f
Marker marker = map.addMarker(option);
overlays.add(marker);
if (TRANSFORMATION_ANIMATION.equals(flag)) {
Point screenPoint = map.getProjection().toScreenLocation(point);
// 设置这个Marker固定在屏幕上的坐标点。
marker.setFixingPoint(screenPoint.x, screenPoint.y);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart() {
// 动画开始播放回调函数
}
@Override
public void onAnimationEnd() {
// 动画结束播放回调
// 设置这个Marker是否可以固定在屏幕上不动
marker.setFixingPointEnable(false);
}
});
}
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);
TencentMapContext mapContext = map.getMapContext();
// 创建平移动画
ITranslateAnimation animation = mapContext.createTranslateAnimation(toPoint);
// 设置动画的持续时间
animation.setDuration(500);
// 动画播放的状态监听器
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart() {
// 动画开始播放回调函数
}
@Override
public void onAnimationEnd() {
// 动画结束播放回调
}
});
return animation;
}
// 创建旋转动画
Animation getRotateAnimation() {
float fromdegree = 0; // 开始角度 [0-360]
float todegree = 360; // 结束角度 [0-360]
float pivotx = 0; // 轴心x坐标
float pivoty = 0; // 轴心y坐标
float pivotz = 0; // 轴心z坐标
// 创建旋转动画
TencentMapContext mapContext = map.getMapContext();
IRotateAnimation animation = mapContext.createRotateAnimation(fromdegree, todegree,
pivotx, pivoty, pivotz);
// 设置动画的持续时间
animation.setDuration(1000);
return animation;
}
// 创建透明度动画
Animation getAlphaAnimation() {
float fromAlpha = 0.0f; // 开始alpha通道值 [0,1]
float toAlpha = 1.0f; // 结束alpha通道值 [0,1]
TencentMapContext mapContext = map.getMapContext();
// 创建渐变动画
IAlphaAnimation animation = mapContext.createAlphaAnimation(fromAlpha, toAlpha);
// 设置动画的持续时间
animation.setDuration(3000);
return animation;
}
// 创建缩放动画
Animation getScaleAnimation() {
float fromX = 0.0f; // 相对于X方向宽度的开始倍率
float toX = 1.0f; // 相对于X方向宽度的结束倍率
float fromY = 0.0f; // 相对于Y方向长度的开始倍率
float toY = 1.0f; // 相对于Y方向长度的结束倍率
TencentMapContext mapContext = map.getMapContext();
// 创建缩放动画
IScaleAnimation animation = mapContext.createScaleAnimation(fromX, toX, fromY, toY);
// 设置动画的持续时间
animation.setDuration(2000);
return animation;
}
// 单边缩放动画
Animation getSingleScaleAnimation() {
float fromX = 0.0f; // 相对于X方向宽度的开始倍率
float toX = 1.0f; // 相对于X方向宽度的结束倍率
float fromY = 1.0f; // 相对于Y方向长度的开始倍率
float toY = 1.0f; // 相对于Y方向长度的结束倍率
TencentMapContext mapContext = map.getMapContext();
// 创建缩放动画
IScaleAnimation animation = mapContext.createScaleAnimation(fromX, toX, fromY, toY);
// 设置动画的持续时间
animation.setDuration(1000);
return animation;
}
// 添加组合动画
Animation getAnimationSet() {
boolean shareInterpolator = true; // 是否使用相同的插值器
TencentMapContext mapContext = map.getMapContext();
// 创建缩放动画
IAnimationSet animation = mapContext.createAnimationSet(shareInterpolator);
// 添加一个动画
animation.addAnimation(getAlphaAnimation(map));
animation.addAnimation(getRotateAnimation(map));
animation.addAnimation(getSingleScaleAnimation(map));
animation.addAnimation(getScaleAnimation(map));
return animation;
}
移除覆盖物
public void removeOverlay() {
// 清除地图上所有的标注类(Marker、Polyline、Polygon,TileOverlay除外)
// map.clearAllOverlays();
// 从地图移除覆盖物
for (Removable overlay : overlays) {
if (!overlay.isRemoved())
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.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);
}
运行效果图