曲線救國,JS表情包卡片!
??想了解更多關(guān)于開源的內(nèi)容,請?jiān)L問:??
一、效果
- 存在問題
- 曲線救國
二、思考
新建一個(gè)工程,創(chuàng)建JS卡片,工程結(jié)構(gòu)如下:
觀察工程結(jié)構(gòu)與HarmonyOS開發(fā)大致一樣,區(qū)別在于FormAbility是交給JS側(cè)來管理的,因?yàn)镺penHarmony的開發(fā)沒有用到JAVA,同樣的卡片樣式是在widget里面進(jìn)行管理。
那我們要做一個(gè)動態(tài)的卡片,只需要在樣式里面添加image組件,放一張gif圖就行了。
但似乎不會主動循環(huán)?開個(gè)定時(shí)器刷新路徑,似乎因?yàn)槭峭粡垐D片并不會主動進(jìn)行刷新。
于是我陷入的沉思…
我想到了兩種解決方法:
- 存放兩張一樣的gif圖,開個(gè)定時(shí)器來回切換。
- 分解成幀動畫,逐幀切換。這樣更麻煩了,但是反過來想,如果封裝得好,我們就可以自行DIY動畫了,比如定格動畫。
三、解決方法
這里我們只針對卡片的動態(tài)實(shí)現(xiàn),至于服務(wù)卡片細(xì)節(jié)工程結(jié)構(gòu)與其含義,咱不如直接看官網(wǎng)文檔,這里參考HarmonyOS官網(wǎng)和OpenHarmony官網(wǎng)都行,兩者基本同步。
1、工程結(jié)構(gòu)
這里可以分析出,我們在widget中對卡片樣式進(jìn)行設(shè)計(jì),在FormAbility中對卡片進(jìn)行操作就行了,本案例只針對卡片設(shè)計(jì),所以暫時(shí)不管MainAbility了,讓他就是HelloWorld就行。
2、卡片樣式
(1)index.hml
我在最初構(gòu)建卡片的時(shí)候選擇22,44大小的卡片,這里其實(shí)隨便就行。
然后按照之前曲線救國的思路,這里只需要一個(gè)image組件就好了,同時(shí)為了方便測試,給圖片路徑開個(gè)通路,方便JS側(cè)進(jìn)行圖片切換。
<div>
<div id="wrapper">
<image id="image" src="/common/dog/{{ pic_num }}.png" style="background-color: white;" ></image>
</div>
</div>
(2)index.json
這里可以對卡片的變量進(jìn)行初始化,和一些具體的事件定義(卡片可以賦予一些事件綁定,比如點(diǎn)擊卡片打開應(yīng)用)。但我并沒有在官網(wǎng)找到j(luò)son中更多方法實(shí)現(xiàn)的方式,所以我也不會,但是至少我們可以給hml樣式的變量賦初值。
{
"data": {
"mini": false,
"pic_num": "1"
},
"actions": {
}
}
我們也可以拍攝一張一張的圖片,來逐幀播放形成動畫。這里是為了測試效果,那么素材就是從動圖里面找。這里我們需要把動圖分解成一張一張的圖片,分別標(biāo)記為1,2,3,4…, 然后在JS側(cè)一張一張的切換得到動態(tài)的效果,也就是逐幀動畫實(shí)現(xiàn)。
3、Form.js
在這里我們實(shí)現(xiàn)動態(tài)的效果。
(1)分解動圖
這里我們首先,選擇一張動圖并且把他分解成一幀一幀的圖片,標(biāo)記好后存放起來。
比如這張:
然后我們利用一些工具進(jìn)行分解。這里推薦一個(gè)在線工具,可以進(jìn)行圖片分解,并且標(biāo)注了每幀圖片持續(xù)多少秒,便于后面的制作。
傳送門。
于是我們就得到了,10幀的圖片。每幀持續(xù)0.09s,也就是90ms。
(2)曲線救國
基本結(jié)構(gòu)
首先,我們先了解Form.js的基本結(jié)構(gòu):
接口名 | 描述 |
onCreate(want: Want): formBindingData.FormBindingData | 卡片提供方接收創(chuàng)建卡片的通知接口。 |
onCastToNormal(formId: string): void | 卡片提供方接收臨時(shí)卡片轉(zhuǎn)常態(tài)卡片的通知接口。 |
onUpdate(formId: string): void | 卡片提供方接收更新卡片的通知接口。 |
onVisibilityChange(newStatus: { [key: string]: number }): void | 卡片提供方接收修改可見性的通知接口。 |
onEvent(formId: string, message: string): void | 卡片提供方接收處理卡片事件的通知接口。 |
onDestroy(formId: string): void | 卡片提供方接收銷毀卡片的通知接口。 |
onAcquireFormState?(want: Want): formInfo.FormState | 卡片提供方接收查詢卡片狀態(tài)的通知接口。 |
那么,曲線救國的思路是:
- 在onCreate方法中,來回切換同一個(gè)GIF圖。
- 在onCreate方法中,開一個(gè)定時(shí)器一幀一幀切換圖片,合成動圖。這個(gè)方式似乎可以幫助我們自由拼接圖片,或者制作自己的動畫?
切換圖片,就是要更新卡片,那么怎么更新卡片呢?
卡片的更新
onUpdate(formId) {
// 若卡片支持定時(shí)更新/定點(diǎn)更新/卡片使用方主動請求更新功能,則提供方需要覆寫該方法以支持?jǐn)?shù)據(jù)更新
console.log('FormAbility onUpdate');
let obj = {
"title": "titleOnUpdate",
"detail": "detailOnUpdate"
};
let formData = formBindingData.createFormBindingData(obj);
formProvider.updateForm(formId, formData).catch((error) => {
console.log('FormAbility updateForm, error:' + JSON.stringify(error));
});
},
分析官網(wǎng)給出的教程,可以得到以下信息:
- formId,每個(gè)卡片的"身份證"。
- obj中的數(shù)據(jù)就是我們在卡片的hml文件中開的通路,我們這里只有一條就是{{pic_num}},
- 卡片數(shù)據(jù)綁定類,formBindingData,我們需要把修改好的obj信息綁定在其中。
- 卡片管理和更新的類,formProvider,通過傳入卡片ID和卡片數(shù)據(jù)進(jìn)入updateForm方法中,就可以更新卡片了。
曲線救國
- 方法1: 來回切換
import formBindingData from '@ohos.application.formBindingData';
import formInfo from '@ohos.application.formInfo';
import formProvider from '@ohos.application.formProvider';
var obj={
"pic_num":"1"
}
var formData=formBindingData.createFormBindingData(obj);
export default {
onCreate(want) {
// Called to return a FormBindingData object.
// 獲取卡片ID
let formId = want.parameters["ohos.extra.param.key.form_identity"];
obj.pic_num="temp";
formData=formBindingData.createFormBindingData(obj);
//設(shè)置一個(gè)計(jì)時(shí)器, 來回切換同一張GIF圖
let flag=0;
setInterval(()=>{
if(flag==0){
//兩個(gè)一模一樣的GIF圖,只是名字不同來回切換罷了
obj.pic_num="temp";
flag=1;
}
else{
obj.pic_num="temp1";
flag=0;
}
formData = formBindingData.createFormBindingData(obj);
//更新卡片
formProvider.updateForm(formId,formData).catch((err)=>{
console.info("yzj"+JSON.stringify(err));
})
//以GIF時(shí)長作為間隔時(shí)間。
},2400)
return formData;
},
onCastToNormal(formId) {
// Called when the form provider is notified that a temporary form is successfully
// converted to a normal form.
console.info("yzj: onCastToNormal");
},
onUpdate(formId) {
// Called to notify the form provider to update a specified form.
},
onVisibilityChange(newStatus) {
// Called when the form provider receives form events from the system.
},
onEvent(formId, message) {
// Called when a specified message event defined by the form provider is triggered.
},
onDestroy(formId) {
// Called to notify the form provider that a specified form has been destroyed.
},
onAcquireFormState(want) {
// Called to return a {@link FormState} object.
return formInfo.FormState.READY;
}
}
- 方法2:幀動畫
這里用到 2.3.1分解的動圖來做素材,在逐幀播放。這樣似乎繞了一個(gè)大圈,那其實(shí)反而可以變成一個(gè)生產(chǎn)方式。我們可以自由選擇圖片逐幀播放形成動畫,比如制作定格動畫。那就可以變成定格動畫卡片了。通常一幀為1/12秒,差不多為83ms,這里只是用GIF分解出來的圖片進(jìn)行測試,所以時(shí)間間隔遵從了GIF本身的幀。
import formBindingData from '@ohos.application.formBindingData';
import formInfo from '@ohos.application.formInfo';
import formProvider from '@ohos.application.formProvider';
var obj={
"pic_num":"1"
}
var formData=formBindingData.createFormBindingData(obj);
export default {
onCreate(want) {
// Called to return a FormBindingData object.
// 獲取卡片ID
let formId = want.parameters["ohos.extra.param.key.form_identity"];
obj.pic_num="1";
formData=formBindingData.createFormBindingData(obj);
//設(shè)置一個(gè)計(jì)時(shí)器,循環(huán)播放圖片形成動畫。
//從第一張圖片開始,這里的動圖分解后只有10幀,那么我們的上限就是10
let i=1;
setInterval(()=>{
//如果已經(jīng)播放到第10幀了,那么切換回第一幀,實(shí)現(xiàn)循環(huán)播放
if(i>10){
i=1;
}
//修改pic_num的值,遞增播放
obj.pic_num=i.toString();
//綁定數(shù)據(jù)
formData = formBindingData.createFormBindingData(obj);
//更新卡片
formProvider.updateForm(formId,formData).catch((err)=>{
console.info("yzj"+JSON.stringify(err));
})
//播放下一幀
i++;
//每幀持續(xù)90ms,這里是根據(jù)實(shí)際情況設(shè)定的
},90);
return formData;
},
onCastToNormal(formId) {
// Called when the form provider is notified that a temporary form is successfully
// converted to a normal form.
console.info("yzj: onCastToNormal");
},
onUpdate(formId) {
// Called to notify the form provider to update a specified form.
},
onVisibilityChange(newStatus) {
// Called when the form provider receives form events from the system.
},
onEvent(formId, message) {
// Called when a specified message event defined by the form provider is triggered.
},
onDestroy(formId) {
// Called to notify the form provider that a specified form has been destroyed.
},
onAcquireFormState(want) {
// Called to return a {@link FormState} object.
return formInfo.FormState.READY;
}
}
效果
兩種方式產(chǎn)生的效果差不多。
4、存在問題
- 重啟板子后,需要重新開啟卡片,否則會靜止不動。
- 關(guān)閉應(yīng)用本身后,卡片只會循環(huán)一次。
四、更多
五、結(jié)語
應(yīng)該是放一張GIF就能結(jié)束的事情,但是現(xiàn)在似乎有一點(diǎn)bug?曲線救國能夠勉強(qiáng)實(shí)現(xiàn)功能,但換個(gè)角度想這樣做或許能自制動圖,定格動畫?
文章相關(guān)附件可以點(diǎn)擊下面的原文鏈接前往下載:
https://ost.51cto.com/resource/2211
https://ost.51cto.com/resource/2212