动画开发
动画是组件的基础特性之一,精心设计的动画使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;
}
});
}
}
点击图片开始动画,动画集合的效果图如下: