一、概述
动画是应用开发中必不可少的部分,它可以使应用程序更加生动和易于互动,一方面可以提升用户体验、增强视觉吸引力,另一方面可以引导用户操作、提高信息传达效率。应用程序中,页面层级间的转场、点击交互、手势操控都可以添加动画。合理使用动画可以通过以下两个方面考虑:
- 提升动画感知流畅度:使用合适的动画能力将UX设计视角转换为开发实现视角,并将设计师提供的动效转化为具体的代码实现。这样可以确保应用在实际使用中达到设计的预期效果,提升动画感知流畅度并提供良好的用户体验。
- 提升动画运行流畅度:优化动画资源的加载和释放,避免内存泄漏和资源浪费;合理使用动画缓存和复用,减少不必要的重复绘制,提高动画的运行效率。
在使用动画时,需要根据具体场景和用户需求进行合理的设计和运用,并且需要注意动画的性能影响,及时采取相应的优化措施。通过合理使用动画,可以提升动画的感知流畅度和运行流畅度,从而提升应用程序的用户体验和性能。
动效要始终围绕操作符合用户心理预期,物体运动符合真实世界,元素表现形态凸显产品的品牌与调性,从用户感知角度提升流畅度。HarmonyOS系统为开发者提供了丰富的动画能力,在实际开发过程中,我们需要把上述UX设计视角转换为开发实现视角。
二、动效场景设计
在设计动效过程中,要清楚地理解动效在系统中承载的作用,动效能体现页面的流畅过渡、对象的明确提示、元素的层级关系、产品的品牌印象等。
1、特征动效
特征动效主要打造 “天体拟物感知”,提供一种天体拟物的品牌效应和宇宙空间感的交互体验,它将力赋予元素,更直观地传递出形象化、拟物化、动态化的设计理念,在不同场景上表达新颖个性的同时又凸显了独特的产品调性。它可以广泛应用于开场动画、加载动画、下载动画等场景。
特征动效是指在用户界面中突出某个特定元素的动画效果。通过特征动效,可以吸引用户的注意力,提升用户体验。例如,在一个应用程序中,当用户点击”下载”按钮时,渐变显示出进度条并动态加载(如下图所示)。
2、转场动效
转场动效是指在不同页面或视图之间切换时使用的动画效果。通过转场动效,可以平滑地过渡到下一个页面或视图,增加界面间的连贯性和流畅性。
HarmonyOS系统为开发者提供了丰富的转场动效库,使开发者能够轻松实现各种转场动画效果。开发者可以根据具体需求,在应用的不同场景中应用这些转场动效,以提升用户体验和界面的吸引力。需要注意的是,为了最佳的用户体验,开发者应根据界面的功能和特点,合理选择转场动效,并遵循动效的使用准则,以确保转场动效在视觉和交互上的一致性。
3、手势动效
手势动效指根据用户的手势操作而产生的动画效果。通过手势动效,可以增强用户与设备之间的互动体验。我们主张无阻塞感的动效设计,结合运用 HarmonyOS 动效物理引擎,将自然属性运用到界面的操作中,比如摩擦力、弹性、碰撞影响等。
- 点击:点击的接触过程中有一段100ms~300ms的时长是无反馈状态,为了提升感知体验,可以在按下那一刻即响应动效反馈。这一可先行的触控响应机制强化了界面元素的视觉反馈,为理解界面状态提供了更多的线索信息。
- 滑动:滑动手势是用户进行滑动操作时产生的相应动画效果,例如随手指移动的平滑过渡动画,增强了界面的流畅性。保证对象动效反馈的结果与手势动作的连贯性是滑动手势动效设计的关键。
- 翻动:翻动手势动效通常用于模拟翻书或翻页的效果,用户可以通过拖拽或抛滑手势来翻转页面或切换内容,界面元素会产生相应的翻页动画,提供更真实的交互体验。翻页有成功与否,未成功会停留在当前内容上;成功则显示下一页/几页的内容。为了提示性,翻页也有过界拖拽的场景。
- 夹捏:捏合手势是指双/多指合拢或分开的动作,常用于缩放或旋转对象。手势过程中需要令对象跟随手势做出相应的响应趋势。
- 拖拽:拖拽手势是指手指按下同时进行移动的动作,动效设计了对象通过拖拽行为进行状态转换的整个过程,以确保用户操作的连贯性和流畅性。
4、微动效
微动效是指在界面中细微的动画效果,用于增加界面的生动感和交互性。微动效可以体现在按钮的点击效果、图标的变化、文本的出现等。例如,当用户打开某个面板时,可以使用微小的缩放或颜色变化来体现(如图所示)。
5、插画动效
插画动效是指在界面中应用的基于插画的动画效果。通过插画动效,可以为界面增添趣味和个性化。例如,在一个游戏应用中,可以使用插画动效来展示角色的动作、表情或者场景的变化。
通过动画的方式丰富视觉元素所要表达的信息,可以引导解读功能信息并串联前后画面,便于用户理解,也使画面表现更富有生命力。
三、动画能力选型
开发人员接收到设计需求后,需要选择合适的动画能力完成该设计。HarmonyOS为开发者提供了系统能力、资源调用、三方库三种方式,在选择动画能力时,开发者需要考虑目标和需求以及效率和质量,合理选择能够满足需求的工具、追求高效率和高质量的结果导向,帮助应用实现更好的动画效果。
1、系统能力
- 属性动画:通过更改组件的属性值实现渐变过渡效果,例如缩放、旋转、平移等。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等。
- 显示动画:可以通过用户的直接操作或应用程序的特定逻辑来触发,例如按钮点击时的缩放动画、列表项展开时的渐变动画等。HarmonyOS提供了全局animateTo显式动画接口来指定由于闭包代码导致状态变化的插入过渡动效。
- 转场动画:转场动画可以实现平滑的界面切换效果,例如页面之间的淡入淡出、滑动切换、旋转切换等,增强了界面的连贯性和吸引力。具体使用方法可参考。
- 路径动画:指对象沿着指定路径进行移动的动画效果。通过设置路径可以实现视图沿着预定义的路径进行移动,例如曲线运动、圆周运动等,为用户呈现更加生动的交互效果。
- 粒子动画:通过大量小颗粒的运动来形成整体动画效果。通过对粒子在颜色、透明度、大小、速度、加速度、自旋角度等维度变化做动画,来营造一种氛围感。
2、资源调用
- GIF动画:GIF动画可以在特定位置循环播放,为应用界面增添生动的视觉效果。在开发中,可以使用image组件来实现GIF动画的播放。通过在特定位置放置Image组件,并加载GIF格式的图像,开发者可以轻松实现动画效果,具体实现可以参考后文”加载GIF实现微动效”。
- 帧动画:通过逐帧播放一系列图片来实现动画效果,在开发中可以使用imageAnimator组件来实现帧动画的播放。开发者可以配置需要播放的图片列表,以及每张图片的播放时长,从而实现精细的动画效果。
3、三方库
- Lottie:解析Adobe After Effects软件通过Bodymovin插件导出的json格式的动画,并在移动设备上进行本地渲染。Lottie动画可以在各种屏幕尺寸和分辨率上呈现,并且支持动画的交互性,通过添加触摸事件或其他用户交互操作,使动画更加生动和具有响应性。
- SVG:通过将SVG图片解析并渲染到页面上并对SVG图片样式动态改变实现动画。OHOS-SVG不仅能够提供高质量的图形呈现,而且还能够实现图形样式的实时更新,为用户带来更加丰富的视觉体验。
四、视角转换步骤
- 了解系统能力:首先,开发者需要深入了解HarmonyOS系统提供的动画能力。这包括了解动画以及如何在HarmonyOS应用中使用相关API。
- 分析UX设计视角:仔细分析UX设计所提供的动效,理解设计师的意图。
- 设计动画方案:基于分析的结果,设计出合理的动画方案。确定动画的触发时机、动画的类型和参数等。
- 使用动画能力:利用HarmonyOS提供的动画能力,如属性动画、路径动画等或者调用三方库,完成设计效果。
- 调试和优化:在实施动画的过程中,进行调试和优化。确保动画效果流畅,动效符合预期,且满足性能要求。
五、动画实践案例
动画能力 | 特点 | |||
---|---|---|---|---|
系统能力 | 可以直接调用,性能优秀,但太复杂的动画不便于实现 | |||
GIF | 可设计、直接调用组件实现,但文件占用空间大,掉帧严重、会出现失真、模糊、锯齿等现象 | |||
帧动画 | 兼容性高、直接调用组件实现,但需要大量图片,占据大量内存 | |||
Lottie | 跨平台、可设计,但性能难以提升、帧率较低 | |||
SVG | 可代码编辑,文件较小、无损伸缩,但实现、维护成本高,并且复杂度高会减慢渲染速度 |
1、使用属性动画实现微动效
实现效果:随着用户滑动,顶端图标和文字需要随着主体内容变更而切换
export const ICON_SUBTITLE_ARRAY: IconSubtitle[] = [
{ icon: $r('app.media.ic_design_style'), title:'设计风格', enTitle: 'DESIGN STYLE' },
{ icon: $r('app.media.ic_building'), title:'建筑信息', enTitle: 'BUILDING INFORMATION' },
{ icon: $r('app.media.ic_geography_icon'), title:'地理位置', enTitle: 'GEOGRAPHIC LOCATION' }
]
StyleTitle(item: IconSubtitle, index: number) {
// 读取需要变化的信息
Column() {
Image(item.icon)
// 图片对应属性
…
Text(item.title)
// 标题对应属性
…
Text(item.enTitle)
// 副标题对应属性
…
}
// 列组件对应属性设置
…
// 动画组件与进入方式
.animation({
duration: Const.TITLE_ICON_ANIMATION_DURATION,
curve: Curve.EaseOut
})
}
2、使用路径动画实现特征动效
实现效果:在本场景中,需要实现当页面显示后,对应位置的小图标持续上下跳动
@Entry
@Component
struct AnimationExample {
// 动画控制器
@State toggle: boolean = true
// 需要设置动画的组件
build() {
Stack() {
Image($r('app.media.icon_bg'))
// 图片的属性值设置
…
Image(this.item.icon)
// 图片的属性值设置
…
}
// 路径属性设置
.motionPath({ path: 'Mstart.x start.y L 0 30 L 0 0 ', from: 0.0, to: 1.0 })
// 设置界面出现时触发路径动画
.onAppear(() => {
animateTo({ duration: 4000, curve: Curve.Linear, iterations: -1 }, () => {
// 通过this.toggle变化组件的位置
this.toggle = !this.toggle
})
})
}
}
3、使用粒子动画实现插画动效
实现效果:在本场景中,需要在背景页面上实现飘雪效果以避免太过单调
Particle({
particles: [{
// 粒子发射器配置
emitter: {
particle: {
type: ParticleType.POINT,
config: {
radius: 10
},
count: 1000,
lifetime: 50000
},
emitRate: 3,
position: [0, 0],
shape: ParticleEmitterShape.ELLIPSE
},
color: {
range: [Color.Red, Color.Yellow],
updater: {
type: ParticleUpdater.CURVE,
// 粒子集合
config: [
// 单独粒子的颜色变化、速度等属性
{
from: Color.White,
to: Color.Pink,
startMillis: 0,
endMillis: 3000,
curve: Curve.FastOutLinearIn
},
// 其他单个粒子设定
…
]
}
},
// 加速度的配置,从大小和方向两个维度变化,speed表示加速度大小,angle表示加速度方向
acceleration: {
speed: {
range: [200, 500],
updater: {
type: ParticleUpdater.RANDOM,
config: [1, 20]
}
},
angle: {
range: [80, 100]
}
}
}]
})
4、加载GIF实现微动效
实现效果:在本场景中,需要实现小魔法棒反复播放的微动效
Image($r('app.media.ic_topics_gif'))
.width($r('app.float.topics_select_width'))
.height($r('app.float.topics_select_height'))
.margin({ right: $r('app.float.topic_margin_right'), bottom: $r('app.float.topic_margin_bottom') })
.onClick(() => {
const bundleName = (getContext(this) as common.UIAbilityContext).applicationInfo.name;
router.pushUrl({ url: `@bundle:${bundleName}/topic/ets/pages/ThemeSettingPage` });
})
5、加载lottie库实现特征动效
实现效果:在本场景中,需要在点击徽章后将其放大并播放烟花动效
import lottie from '@ohos/lottie'
//构建渲染上下文
private mainRenderingSettings: RenderingContextSettings = new RenderingContextSettings(true)
private mainCanvasRenderingContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.mainRenderingSettings)
build() {
Column() {
// 显示徽章
List({ space: Constants.MIDDLE_SPACE }) {
ForEach(ACHIEVE_IMAGE_LIST, (item: AchieveImage) => {
ListItem() {
Image(this.getShowImg(item))
// 图片的属性值
…
// 点击事件
.onClick(() => {
if (this.learnedIds.includes(item.pathId)) {
lottie.loadAnimation({
container: this.mainCanvasRenderingContext,
renderer: 'canvas',
loop: false,
autoplay: false,
name: item.pathId,
path: item.lottiePath
})
lottie.play()
this.clickedItem = item;
this.isShow = true;
}
})
}, (item: AchieveImage) => JSON.stringify(item))
}
// 模态转场
.bindContentCover(
this.isShow,
this.playLottieBuilder(),
{ modalTransition: ModalTransition.ALPHA, backgroundColor: $r('app.color.achieve_background_color'), onDisappear: () => {lottie.destroy()}}
)
// 列表属性
…
}
// 列容器属性
…
}
//模态转场后页面
@Builder playLottieBuilder() {
Column() {
Column() {
// 建立画布
Canvas(this.mainCanvasRenderingContext)
.height('50%')
.width('80%')
.backgroundColor($r('app.color.achieve_background_color'))
.onReady(() => {
if (this.clickedItem != null) {
lottie.loadAnimation({
container: this.mainCanvasRenderingContext,
renderer: 'canvas',
loop: false,
autoplay: true,
name: this.clickedItem.pathId,
path: this.clickedItem.lottiePath
})
}
})
.onClick(() => {
this.isShow = false;
})
}
Column() {
Button('知道啦')
.onClick(() => {
this.isShow = false;
})
}
}
}
}
六、总结
- 用户体验:动画应该能够提升用户体验,而不是仅仅为了动画而动画。动画应该能够使用户界面更加生动、直观和易于理解,而不应该过于花哨或者繁琐。
- 性能优化:动画的流畅性对于用户体验至关重要。在设计动画时,需要考虑到设备的性能和资源消耗,避免过多的动画效果导致性能下降或者卡顿。
- 可访问性:在设计动画时,需要考虑到一些用户可能存在的视觉或认知障碍。动画效果应该不会影响到用户对应用界面的理解和操作。
- 上下文适应:动画效果应该根据应用的具体场景和功能进行设计,与应用的整体风格和设计语言保持一致。