逐幀動畫是常見的一種動畫呈現形式,本例就為大家介紹如何通過 translate(),setInterval(),clearAllInterval() 等方法實現逐幀動畫。
效果呈現

本例最終效果如上圖:
點擊“run”按鈕,火柴人開始走動。
點擊“stop”按鈕,火柴人停止走動。
運行環境
本例基于以下環境開發,開發者也可以基于其他適配的版本進行開發:
IDE:DevEco Studio 3.1 Release
SDK:Ohos_sdk_public 3.2.12.5(API Version 9 Release)
實現思路
本例的實現有兩個關鍵點: ①將連續走動的火柴人拆分為多幀靜態圖像,在固定的時間間隔內逐幀將圖像移動到動畫窗口,間隔時間要小于肉眼可察覺的時間。循環上述動作,就可以實現火柴人的走動動畫。
火柴人靜態圖像如下:
?
將背景圖片以固定速度相對于火柴人走動方向反方向移動,從而實現火柴人向前走動的效果。
背景圖如下:

本例使用 translate() 控制火柴人的移動,用 backgroundImagePosition() 控制背景圖的移動。 另外,通過 setInterval() 設置火柴人移動的時間間隔,通過 clearAllInterval() 清除移動。
開發步驟
①搭建 UI 框架
使用兩個 Row 組件分別呈現背景圖和火柴人,第二個 Row 組件作為第一個 Row 組件的子組件,父 Row 組件的背景設置為背景圖,子 Row 組件中添加 Image 組件用來呈現火柴人單幀圖像。
@Entry @Component exportdefaultstructframeAnimation{ build(){ Column(){ //父Row組件 Row(){ //子Row組件 Row(){ //通過Image組件顯示火柴人圖像 Image($r("app.media.man")).height(60).width(545.16) }.width(100) .justifyContent(FlexAlign.Start) .alignItems(VerticalAlign.Top) //截取顯示與背景同等大小的區域,控制單個火柴人顯示在畫面中 .clip(true) } //添加背景圖像 .backgroundImage($r("app.media.background")) //保持寬高比進行縮小或者放大,使得圖片兩邊都大于或等于顯示邊界。 .backgroundImageSize(ImageSize.Cover) .width('100%') .height(130) .justifyContent(FlexAlign.Center) .alignItems(VerticalAlign.Bottom) Row(){ //添加跑動按鈕 Button('run') .margin({right:10}) .type(ButtonType.Normal) .width(75) .borderRadius(5) //添加停止按鈕 Button('stop') .type(ButtonType.Normal) .borderRadius(5) .width(75) .backgroundColor('#ff0000') }.margin({top:30,bottom:10}) }.width('100%').width('100%').padding({top:30}) } }
②添加火柴人和背景圖片的移動邏輯
通過狀態變量設定火柴人和背景圖片的位置,位置變化時可以實時刷新 UI 界面。
//火柴人位置變量
@StatemanPostion:{
x:number,
y:number
}={x:0,y:0}
//背景圖位置變量
@StatetreePosition:{
x:number,
y:number
}={x:0,y:0}
給火柴人和背景圖片添加位置屬性。
Row(){
Row(){
Image($r("app.media.man"))
.height(60)
.width(545.16)
//通過translate實現火柴人的位移。綁定manPosition,用來改變火柴人位置。
.translate(this.manPostion)
}
...
}
.backgroundImage($r("app.media.background"))
.backgroundImageSize(ImageSize.Cover)
//通過backgroundImagePosition實現背景圖片的位移。綁定treePosition,用來改變背景圖片的位置。
.backgroundImagePosition(this.treePosition)
...
③為’‘run’'按鈕和"stop"按鈕綁定控制邏輯
構建火柴人和背景圖片移動的方法,用來設定火柴人和背景圖片每次移動的距離。 這里要注意火柴人每次移動的距離等于兩個火柴人之間的間隔距離(像素值)。
//火柴人移動方法
manWalk(){
if(this.manPostion.x<=?-517.902)?{
????this.manPostion.x?=?0
??}?else?{
????//?每次移動的距離為火柴人靜態圖像之間的間隔距離
????this.manPostion.x?-=?129.69
??}
}
//?背景移動方法
treesMove()?{
??if?(this.treePosition.x?<=?-1215)?{
????this.treePosition.x?=?0
??}?else?{
????this.treePosition.x?-=?20
??}
}
創建 doAnimation() 方法調用上述兩個方法,以便在后續的定時器中使用。
doAnimation(){
this.manWalk()
this.treesMove()
}
通過 setInterval 為“run”按鈕綁定走動邏輯。
Button('run')
.margin({right:10})
.type(ButtonType.Normal)
.width(75)
.borderRadius(5)
.onClick(()=>{
this.clearAllInterval()
//創建定時器,調用doAnimation方法,啟動動畫
lettimer=setInterval(this.doAnimation.bind(this),100)
this.timerList.push(timer)
})
通過 clearAllInterval 為“stop”按鈕綁定停止邏輯。
Button('stop')
.type(ButtonType.Normal)
.borderRadius(5)
.width(75)
.backgroundColor('#ff0000')
.onClick(()=>{
//清理定時器,停止動畫
this.clearAllInterval()
})
完整代碼
本例完整代碼如下:
@Entry
@Component
exportdefaultstructframeAnimation{
//火柴人位置變量
@StatemanPostion:{
x:number,
y:number
}={x:0,y:0}
//背景圖位置變量
@StatetreePosition:{
x:number,
y:number
}={x:0,y:0}
//定時器列表,當列表清空時,動畫停止
privatetimerList:number[]=[]
//火柴人移動方法
manWalk(){
if(this.manPostion.x<=?-517.902)?{
??????this.manPostion.x?=?0
????}?else?{
??????this.manPostion.x?-=?129.69
????}
??}
??//?背景移動方法
??treesMove()?{
????if?(this.treePosition.x?<=?-1215)?{
??????this.treePosition.x?=?0
????}?else?{
??????this.treePosition.x?-=?20
????}
??}
??//?銷毀所有定時器
??clearAllInterval()?{
????this.timerList.forEach((timer:?number)?=>{
clearInterval(timer)
})
this.timerList=[]
}
doAnimation(){
this.manWalk()
this.treesMove()
}
build(){
Column(){
//父Row組件
Row(){
//子Row組件
Row(){
//通過Image組件顯示火柴人圖像
Image($r("app.media.man"))
.height(60)
.width(545.16)
//通過translate實現火柴人的位移。綁定manPosition變量,用來改變火柴人位置。
.translate(this.manPostion)
}
.width(100)
.justifyContent(FlexAlign.Start)
.alignItems(VerticalAlign.Top)
//截取顯示與背景同等大小的區域,控制單個火柴人顯示在畫面中
.clip(true)
}
//添加背景圖像
.backgroundImage($r("app.media.background"))
//保持寬高比進行縮小或者放大,使得圖片兩邊都大于或等于顯示邊界。
.backgroundImageSize(ImageSize.Cover)
//通過backgroundImagePosition實現背景圖片的位移。綁定treePosition,用來改變背景圖片的位置。
.backgroundImagePosition(this.treePosition)
.width('100%')
.height(130)
.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Bottom)
Row(){
//添加跑動按鈕
Button('run')
.margin({right:10})
.type(ButtonType.Normal)
.width(75)
.borderRadius(5)
.onClick(()=>{
this.clearAllInterval()
lettimer=setInterval(this.doAnimation.bind(this),100)
this.timerList.push(timer)
})
//添加停止按鈕
Button('stop')
.type(ButtonType.Normal)
.borderRadius(5)
.width(75)
.backgroundColor('#ff0000')
.onClick(()=>{
this.clearAllInterval()
})
}.margin({top:30,bottom:10})
}.width('100%').width('100%').padding({top:30})
}
}
審核編輯:劉清
-
OpenHarmony
+關注
關注
33文章
3952瀏覽量
21094
原文標題:OpenHarmony上實現逐幀動畫
文章出處:【微信號:gh_834c4b3d87fe,微信公眾號:OpenHarmony技術社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
基于凌羽派的OpenHarmony北向應用開發:Hello World 示例應用
【原創】OpenHarmony系統投屏工具軟件 - OpenHarmony_OHScrcpy使用推薦
SGTools--動畫控件--屏幕實現動畫顯示 就是這么簡單
【M-K1HSE開發板免費體驗】相關源碼之閱讀和分析1-使用XComponent + Vsync 實現自定義動畫
分享---儲能UI界面能量流動動畫實現方法
ElfBoard技術貼|如何在【RK3588】ELF 2開發板中實現自定義開機動畫
如何在OpenHarmony上實現逐幀動畫?
評論