HarmonyOS学习路之开发篇—Java UI框架(动画开发)

动画开发

动画是组件的基础特性之一,精心设计的动画使UI变化更直观,有助于改进应用程序的外观并改善用户体验。Java UI框架提供了帧动画、数值动画和属性动画,并提供了将多个动画同时操作的动画集合。

帧动画

帧动画是利用视觉暂留现象,将一系列静止的图片按序播放,给用户产生动画的效果。

1. 在Project窗口,打开“entry > src > main > resources > base > media”,添加一系列图片至media目录下。

2. 在graphic目录下,新建“animation_element.xml”文件,在XML文件中使用animation-list标签来配置图片资源,duration用来设置显示时长,单位为毫秒。oneshot表示是否只播放一次。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:ohos="http://schemas.huawei.com/res/ohos"
                ohos:oneshot="false">
    <item ohos:element="$media:01" ohos:duration="100"/>
    <item ohos:element="$media:02" ohos:duration="100"/>
    <item ohos:element="$media:03" ohos:duration="100"/>
    <item ohos:element="$media:04" ohos:duration="100"/>
    <item ohos:element="$media:05" ohos:duration="100"/>
    <item ohos:element="$media:06" ohos:duration="100"/>
    <item ohos:element="$media:07" ohos:duration="100"/>
    <item ohos:element="$media:08" ohos:duration="100"/>
    <item ohos:element="$media:09" ohos:duration="100"/>
    <item ohos:element="$media:10" ohos:duration="100"/>
    <item ohos:element="$media:11" ohos:duration="100"/>
    <item ohos:element="$media:12" ohos:duration="100"/>
</animation-list>

3. 在MainAbilitySlice.java中实现动画播放的相关功能。

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.element.FrameAnimationElement;

public class MainAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //加载动画资源,生成动画对象。
        FrameAnimationElement frameAnimationElement = new FrameAnimationElement(getContext(), ResourceTable.Graphic_animation_element);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(500, 500));
        image.setBackground(frameAnimationElement);
        DirectionalLayout directionalLayout = new DirectionalLayout(getContext());
        directionalLayout.addComponent(image);
        super.setUIContent(directionalLayout);
        //开始播放动画
        frameAnimationElement.start();
    }
}

动画效果如图所示:

数值动画

AnimatorValue数值从0到1变化,本身与Component无关。开发者可以设置0到1变化过程的属性,例如:时长、变化曲线、重复次数等,并通过值的变化改变组件的属性,实现组件的动画效果。

  • Java代码方式

MainAbilitySlice.java的示例代码如下:

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;

public class MainAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setPixelMap(ResourceTable.Media_icon);
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(200, 200));
        DirectionalLayout layout = new DirectionalLayout(getContext());
        layout.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT
        ));
        layout.addComponent(image);
        super.setUIContent(layout);
        //创建数值动画对象
        AnimatorValue animatorValue = new AnimatorValue();
        //动画时长
        animatorValue.setDuration(3000);
        //播放前的延迟时间
        animatorValue.setDelay(1000);
        //循环次数
        animatorValue.setLoopedCount(AnimatorValue.INFINITE);
        //动画的播放类型
        animatorValue.setCurveType(Animator.CurveType.BOUNCE);
        //设置动画过程
        animatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                image.setContentPosition((int) (800 * value), image.getContentPositionY());
            }
        });
        //开始启动动画
        animatorValue.start();
    }
}
  • XML方式

在resources/base/animation目录下创建名为“animator_value.xml”XML文件。目前XML方式只支持delay和duration属性。

animator_value.xml的示例代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<animator xmlns:ohos="http://schemas.huawei.com/res/ohos"
          ohos:delay="1000"
          ohos:duration="3000"/>

MainAbilitySlice.java的示例代码如下:

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorScatter;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;

public class MainAbilitySlice extends AbilitySlice {
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setPixelMap(ResourceTable.Media_icon);
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(200, 200));
        DirectionalLayout layout = new DirectionalLayout(getContext());
        layout.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT
        ));
        layout.addComponent(image);
        super.setUIContent(layout);
        //创建数值动画对象
        AnimatorScatter scatter = AnimatorScatter.getInstance(getContext());
        Animator animator = scatter.parse(ResourceTable.Animation_animator_value);
        if (animator instanceof AnimatorValue) {
            AnimatorValue animatorValue = (AnimatorValue) animator;
            //循环次数
            animatorValue.setLoopedCount(AnimatorValue.INFINITE);
            //动画的播放类型
            animatorValue.setCurveType(Animator.CurveType.BOUNCE);
            //设置动画过程
            animatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                @Override
                public void onUpdate(AnimatorValue animatorValue, float value) {
                    image.setContentPosition((int) (800 * value), image.getContentPositionY());
                }
            });
            //开始启动动画
            animatorValue.start();
        }
    }
}

动画效果如图所示:

属性动画

为Component的属性设置动画是常见的需求,Java UI框架可以为Component设置某个属性或多个属性的动画。

  • Java方式

MainAbilitySlice.java的示例代码如下

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;

public class MainAbilitySlice extends AbilitySlice {
    private boolean started = false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setPixelMap(ResourceTable.Media_icon);
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(200, 200));
        DirectionalLayout layout = new DirectionalLayout(getContext());
        layout.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT
        ));
        layout.addComponent(image);
        super.setUIContent(layout);
        //创建属性动画对象
        AnimatorProperty animatorProperty = new AnimatorProperty();
        animatorProperty.setTarget(image);
        animatorProperty
                //x轴从100移动到800位置
                .moveFromX(100).moveToX(800)
                //透明度从0.5变化到1.0
                .alphaFrom(0.5f).alpha(1.0f)
                //旋转720度
                .rotate(720)
                //时长3秒
                .setDuration(3000)
                //延迟1秒
                .setDelay(1000)
                //无限循环
                .setLoopedCount(AnimatorValue.INFINITE)
                //反弹力效果
                .setCurveType(Animator.CurveType.BOUNCE);
        //点击图片开始/停止动画
        image.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (!started) {
                    //开始动画
                    animatorProperty.start();
                } else {
                    //停止动画
                    animatorProperty.stop();
                }
                started = !started;
            }
        });
    }
}
  • XML方式

在resources/base/animation文件夹下创建名为“animator_property.xml”的XML文件。目前XML方式只支持delay和duration属性。

animator_property.xml的示例代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<animatorProperty xmlns:ohos="http://schemas.huawei.com/res/ohos"
                  ohos:delay="1000"
                  ohos:duration="3000"/>

MainAbilitySlice.java的示例代码如下:

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorScatter;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;

public class MainAbilitySlice extends AbilitySlice {
    private boolean started = false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setPixelMap(ResourceTable.Media_icon);
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(200, 200));
        DirectionalLayout layout = new DirectionalLayout(getContext());
        layout.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT
        ));
        layout.addComponent(image);
        super.setUIContent(layout);
        //创建属性动画对象
        AnimatorScatter scatter = AnimatorScatter.getInstance(getContext());
        Animator animator = scatter.parse(ResourceTable.Animation_animator_property);
        if (animator instanceof AnimatorProperty) {
            AnimatorProperty animatorProperty = (AnimatorProperty) animator;
            animatorProperty.setTarget(image);
            animatorProperty
                    //x轴从100移动到800位置
                    .moveFromX(100).moveToX(800)
                    //透明度从0.5变化到1.0
                    .alphaFrom(0.5f).alpha(1.0f)
                    //旋转720度
                    .rotate(720)
                    //无限循环
                    .setLoopedCount(AnimatorValue.INFINITE)
                    //反弹力效果
                    .setCurveType(Animator.CurveType.BOUNCE);
            //点击图片开始/停止动画
            image.setClickedListener(new Component.ClickedListener() {
                @Override
                public void onClick(Component component) {
                    if (!started) {
                        //开始动画
                        animatorProperty.start();
                    } else {
                        //停止动画
                        animatorProperty.stop();
                    }
                    started = !started;
                }
            });
        }
    }
}

点击图片开始动画,效果如图所示:

动画集合

如果需要使用一个组合动画,可以把多个动画对象进行组合,并添加到使用AnimatorGroup中。AnimatorGroup提供了两个方法:runSerially() 和 runParallel(),分别表示动画按顺序开始和动画同时开始。

说明:

动画集合暂不支持使用XML方式。

多个动画同时开始

同时执行动画1和动画2。

  • 动画1:沿x轴从100移动到800位置。
  • 动画2:沿y轴从100移动到800位置。

MainAbilitySlice.java的示例代码如下:

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;

public class MainAbilitySlice extends AbilitySlice {
    private boolean started =false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setPixelMap(ResourceTable.Media_icon);
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(200, 200));
        DirectionalLayout layout = new DirectionalLayout(getContext());
        layout.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT
        ));
        layout.addComponent(image);
        super.setUIContent(layout);
        //创建动画组对象
        AnimatorGroup animatorGroup = new AnimatorGroup();
        //动画1 - 沿x轴从100移动到800位置
        AnimatorProperty action1 = new AnimatorProperty();
        action1.setTarget(image);
        action1.moveFromX(0).moveToX(800);
        //动画2 - 沿y轴从100移动到800位置
        AnimatorProperty action2 = new AnimatorProperty();
        action2.setTarget(image);
        action2.moveFromY(0).moveToY(800);
        //同时执行动画1和动画2
        animatorGroup.runParallel(action1, action2);
        //无限循环
        animatorGroup.setLoopedCount(Animator.INFINITE);
        //时长
        animatorGroup.setDuration(1500);
        //点击图片开始/停止动画
        image.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (!started) {
                    //启动动画组
                    animatorGroup.start();
                } else {
                    //停止动画组
                    animatorGroup.stop();
                }
                started = !started;
            }
        });
    }
}

点击图片开始动画,多个动画同时开始的效果图如下:

多个动画按顺序逐个执行

先执行动画1,然后执行动画2。

  • 动画1:沿x轴从100移动到800位置。
  • 动画2:沿y轴从100移动到800位置。

MainAbilitySlice.java的示例代码如下:

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;

public class MainAbilitySlice extends AbilitySlice {
    private boolean started =false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setPixelMap(ResourceTable.Media_icon);
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(200, 200));
        DirectionalLayout layout = new DirectionalLayout(getContext());
        layout.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT
        ));
        layout.addComponent(image);
        super.setUIContent(layout);
        //创建动画组对象
        AnimatorGroup animatorGroup = new AnimatorGroup();
        //动画1 - 沿x轴从100移动到800位置
        AnimatorProperty action1 = new AnimatorProperty();
        action1.setTarget(image);
        action1.moveFromX(0).moveToX(800);
        //动画2 - 沿y轴从100移动到800位置
        AnimatorProperty action2 = new AnimatorProperty();
        action2.setTarget(image);
        action2.moveFromY(0).moveToY(800);
        //先动画1后动画2
        animatorGroup.runSerially(action1, action2);
        //无限循环
        animatorGroup.setLoopedCount(Animator.INFINITE);
        //时长
        animatorGroup.setDuration(1500);
        //点击图片开始/停止动画
        image.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (!started) {
                    //启动动画组
                    animatorGroup.start();
                } else {
                    //停止动画组
                    animatorGroup.stop();
                }
                started = !started;
            }
        });
    }
}

点击图片开始动画,多个动画按顺序逐个执行的效果图如下:

多个动画顺序执行和同时执行并存

为了更加灵活处理多个动画的播放顺序,例如一些动画顺序播放、一些动画同时播放,Java UI框架提供了更方便的动画Builder接口。

先同时执行动画1和动画2,然后同时执行动画3和动画4。

  • 动画1:沿x轴从100移动到800位置。
  • 动画2:沿y轴从100移动到800位置。
  • 动画3:沿y轴从0.3放大到1.0。
  • 动画4:沿x轴从0.3放大到1.0。

MainAbilitySlice.java的示例代码如下:

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;

public class MainAbilitySlice extends AbilitySlice {
    private boolean started =false;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        //创建播放动画的组件
        Image image = new Image(getContext());
        image.setPixelMap(ResourceTable.Media_icon);
        image.setLayoutConfig(new ComponentContainer.LayoutConfig(200, 200));
        DirectionalLayout layout = new DirectionalLayout(getContext());
        layout.setLayoutConfig(new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT
        ));
        layout.addComponent(image);
        super.setUIContent(layout);
        //创建动画组对象
        AnimatorGroup animatorGroup = new AnimatorGroup();
        //动画1 - 沿x轴从100移动到800位置
        AnimatorProperty action1 = new AnimatorProperty();
        action1.setTarget(image);
        action1.moveFromX(0).moveToX(800);
        //动画2 - 沿y轴从100移动到800位置
        AnimatorProperty action2 = new AnimatorProperty();
        action2.setTarget(image);
        action2.moveFromY(0).moveToY(800);
        //动画3 - 沿y轴从0.3放大到1.0
        AnimatorProperty action3 = new AnimatorProperty();
        action3.setTarget(image);
        action3.scaleYFrom(0.3f).scaleY(1.0f);
        //动画4 - 沿x轴从0.3放大到1.0
        AnimatorProperty action4 = new AnimatorProperty();
        action4.setTarget(image);
        action4.scaleXFrom(0.3f).scaleX(1.0f);

        //先同时执行动画1和动画2,然后同时执行动画3和动画4
        AnimatorGroup.Builder builder = animatorGroup.build();
        builder.addAnimators(action1,action2).addAnimators(action3,action4);
        //无限循环
        animatorGroup.setLoopedCount(Animator.INFINITE);
        //时长
        animatorGroup.setDuration(1500);
        //点击图片开始/停止动画
        image.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (!started) {
                    //启动动画组
                    animatorGroup.start();
                } else {
                    //停止动画组
                    animatorGroup.stop();
                }
                started = !started;
            }
        });
    }
}

点击图片开始动画,动画集合的效果图如下:

猜你喜欢

转载自blog.csdn.net/weixin_47094733/article/details/131249232