高德地图SDK Android版开发 8 覆盖物示例2动画

高德地图SDK Android版开发 8 覆盖物示例2动画

  • 前言
  • 动画相关的类和接口
    • 帧动画
      • MarkerOptions
    • 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);
  • AnimationListener 动画侦听
// 动画监听,包含动画开始和结束时的回调
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中的生长、跳跃和呼吸动画。

界面布局

高德地图SDK Android版开发 8 覆盖物示例2动画_第1张图片

  • 布局文件

<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类

  • 以下是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"; // 组合动画

public final static String DEMO_GROW_ANIMATION = "Grow"; // Demo1 从地下生长
public final static String DEMO_JUMP_ANIMATION = "Jump"; // Demo2 跳跃
public final static String DEMO_BREATHE_ANIMATION = "Breathe"; // Demo3 呼吸

成员变量

// 覆盖物列表
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) // 当前MarkerOptions对象的经纬度
            .icons(bitmaps) // Marker的动画帧列表
            .period(10); // 帧数, 刷新周期,值越小速度越快。默认为20,最小为1

    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) {
    // breathe marker
    MarkerOptions option = new MarkerOptions()
            .position(point)
            .icon(circleBitmap)
            .anchor(0.5f, 0.5f)
            .zIndex(1);
    Marker breatheMarker = map.addMarker(option);
    overlays.add(breatheMarker);

    // center marker
    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);

    // 使用TranslateAnimation,填写一个需要移动的目标点
    Animation animation = new TranslateAnimation(toPoint);
    animation.setInterpolator(new Interpolator() {
        @Override
        public float getInterpolation(float input) {
            // 模拟重加速度的interpolator
            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);

    // 1. 透明度动画
    float fromAlpha = 0.5f;
    float toAlpha = 0f;
    AlphaAnimation alphaAnimation = new AlphaAnimation(fromAlpha, toAlpha);
    alphaAnimation.setDuration(2000);
    // 设置不断重复
    alphaAnimation.setRepeatCount(Animation.INFINITE);

    // 2. 缩放动画
    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() {
    // 从地图上删除所有的覆盖物(marker,circle,polyline 等对象),
    // 但myLocationOverlay(内置定位覆盖物)除外。
//    boolean isKeepMyLocationOverlay = true;
//    map.clear(isKeepMyLocationOverlay);

    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);
}

运行效果图

你可能感兴趣的:(高德地图Android开发,android,高德地图)