OpenHarmony开发者论坛
标题:
基于OpenHarmony 5.0Release 开发的在线音乐应用卡片
[打印本页]
作者:
深开鸿-孙炼
时间:
2024-10-14 09:53
标题:
基于OpenHarmony 5.0Release 开发的在线音乐应用卡片
[md]# 前言
OpenHarmony社区最新发布了5.0 Release版本,在多媒体播放能力上有所加强,另外卡片的功能支持也更加丰富,对于在线音乐播放类应用,卡片是一个必不可少的功能,因此,本文在OpenHarmony 5.0Release (API12)版本上开发了在线音乐应用的卡片。
# 功能
预览图2*4:
![image.png](
https://forums-obs.openharmony.c ... 9lu1l24qu2jzkgu.png
"image.png")
卡片功能包括:
1、展示并实时刷新播放信息:歌曲名称、歌手、播放状态、歌曲封面图(网络)
2、播放控制:播放模式、上一首、播放/暂停、下一首、收藏
# 实现
本功能在集成测试仓的在线音乐播放应用基础上开发:[在线音乐播放应用](
https://gitee.com/openharmony-si ... o/MusicPlayerOnline
"在线应用应用")。开发卡片功能包含如下几个部分:
## 1、创建卡片工程
右键基础工程Entry,创建卡片工程:
![image.png](
https://forums-obs.openharmony.c ... x16tto10tcc22tz.png
"image.png")
根据提示创建完成后,生成卡片工程文件:
1)Ability
![image.png](
https://forums-obs.openharmony.c ... biot4eb9we9hiew.png
"image.png")
2)布局
![image.png](
https://forums-obs.openharmony.c ... qlg4mipgf3a5yqy.png
"image.png")
3)配置
![image.png](
https://forums-obs.openharmony.c ... nnev9uj77jq7jen.png
"image.png")
并且在工程原配置文件中增加了Ability标签:
```
"extensionAbilities": [
{
"name": "EntryFormAbility",
"srcEntry": "./ets/entryformability/EntryFormAbility.ets",
"label": "$string:EntryFormAbility_label",
"description": "$string:EntryFormAbility_desc",
"type": "form",
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
}
],
```
## 2、卡片UI布局
WidgeCard布局代码:
```
build() {
Stack({ alignContent: Alignment.TopStart }) {
Row() {
}
.width(this.FULL_PERCENT)
.height(this.FULL_PERCENT)
.displayPriority(this.DISPLAY_PRIORITY_ONE)
.backgroundImage('memory://' + this.imgName)
.backgroundImageSize(ImageSize.Cover)
Column()
.width(this.FULL_PERCENT)
.height(this.FULL_PERCENT)
.backgroundColor(Color.White)
.opacity(0.9)
Row() {
Column() {
Row()
.width(128)
.height(128)
.borderRadius(64)
.margin(8)
.shadow({ radius: 2, color: Color.Gray })
.backgroundImage('memory://' + this.imgName)
.backgroundImageSize(ImageSize.Cover)
.onClick(() => {
postCardAction(this, {
action: this.ACTION_TYPE,
abilityName: this.ABILITY_NAME,
});
})
}
.justifyContent(FlexAlign.Center)
.height(this.FULL_PERCENT)
Column() {
Row() {
Column() {
Text(this.audioItem.title)
.fontSize(32)
.fontColor($r('app.color.information_title_font'))
.fontWeight(FontWeight.Medium)
.maxLines(this.MAX_LINES_VALUE)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(this.audioItem.artist)
.fontSize(24)
.fontColor($r('app.color.item_text_font'))
.fontWeight(FontWeight.Regular)
.margin({ top: 4 })
.maxLines(this.MAX_LINES_VALUE)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.justifyContent(FlexAlign.SpaceEvenly)
.alignItems(HorizontalAlign.Start)
.margin({ left: 8, right: 8 })
.width('80%')
.onClick(() => {
postCardAction(this, {
action: this.ACTION_TYPE,
abilityName: this.ABILITY_NAME,
});
})
Image(this.audioItem.isFavor ? $r('app.media.heart_fill') : $r('app.media.heart'))
.width(48)
.height(48)
.onClick(() => {
this.onSetFavor()
})
}
.alignItems(VerticalAlign.Top)
.justifyContent(FlexAlign.SpaceBetween)
.width(this.FULL_PERCENT)
Row() {
Image(this.playMode === PLAY_MODE.REPEAT ? $r('app.media.repeat') : (this.playMode === PLAY_MODE.REPEAT1 ? $r('app.media.repeat_1') : $r('app.media.shuffle')))
.width(64)
.height(64)
.padding(4)
.onClick(() => {
this.setPlayMode();
})
Image($r('app.media.backward_end_fill'))
.width(64)
.height(64)
.padding(4)
.onClick(() => {
this.onPreviousClick()
})
if (this.isPlaying === ServerConstants.PLAYER_STATE_PLAYING) {
Image($r('app.media.pause'))
.width(64)
.height(64)
.padding(8)
.onClick(() => {
this.onPauseClick();
})
.onAppear(() => {
if (this.audioItem.id !== '') {
if (this.downloadImgId === this.audioItem.id) {
return;
}
this.downloadImgId = this.audioItem.id;
postCardAction(this, {
action: 'message',
params: {
info: ServerConstants.SONG_IMAGE_URL + this.audioItem.id
}
});
}
})
} else {
Image($r('app.media.play_fill'))
.width(64)
.height(64)
.padding(4)
.onClick(() => {
this.onPlayClick();
})
}
Image($r('app.media.forward_end_fill'))
.width(64)
.height(64)
.padding(4)
.onClick(() => {
this.onNextClick()
})
}
.justifyContent(FlexAlign.SpaceBetween)
.width(this.FULL_PERCENT)
}
.width('60%')
.height(this.FULL_PERCENT)
.justifyContent(FlexAlign.SpaceEvenly)
}
.width(this.FULL_PERCENT)
.justifyContent(FlexAlign.SpaceEvenly)
.displayPriority(this.DISPLAY_PRIORITY_TWO)
}
}
```
预览效果:
![image.png](
https://forums-obs.openharmony.c ... 42r492p41222p1v.png
"image.png")
## 3、卡片内容更新
WidgetCard通过LocalStorageProp 绑定需要刷新的数据:
```
@LocalStorageProp('formId') formId: string = '';
@LocalStorageProp('audioItem') audioItem: AudioData = new AudioData('未播放', '--', '')
@LocalStorageProp('isPlaying') isPlaying: string = ServerConstants.PLAYER_STATE_UNKNOWN;
@LocalStorageProp('imgName') imgName: string = '';
@LocalStorageProp('playMode') playMode: number = PLAY_MODE.REPEAT;
```
在播放后台通过formProvider.updataForm更新卡片内容:
```
updateCard() {
let formData: Record<string, AudioData| string> = {
'audioItem': this.item,
'isPlaying': this.state,
};
let formMsg: formBindingData.FormBindingData = formBindingData.createFormBindingData(formData);
formProvider.updateForm(this.formId, formMsg).then(() => {
console.info('FormAbility updateForm success.');
}).catch((error: Base.BusinessError) => {
console.info(`Operation updateForm failed. Cause: ${JSON.stringify(error)}`);
})
}
```
## 4、卡片功能事件
通过三种Action事件方式实现卡片的三种功能:
1、Router:点击图片或歌曲名跳转到应用主页面:
```
postCardAction(this, {
action: 'router',
abilityName: this.ABILITY_NAME,
});
```
2、Call:点击播放/暂停、上一首下一首等,调用后台播放功能:
发送消息:
```
onPlayClick(): void {
postCardAction(this, {
'action': 'call',
'abilityName': this.ABILITY_NAME,
'params': {
'method': 'play'
}
});
console.info(TAG, 'postCardAction onPlayClick');
}
```
后台消息处理:
```
try {
this.callee.on('play', (data: rpc.MessageSequence) => {
aPlayerManager.resume();
return null;
});
```
3、通过Message消息通知EntryFormAbility下载封面的网络图片并显示:
发送消息,将图片url发给EntryFormAbility的OnFormEvent:
```
postCardAction(this, {
action: 'message',
params: {
info: ServerConstants.SONG_IMAGE_URL + this.audioItem.id
}
});
```
下载图片并通知UI加载:
```
let httpRequest = http.createHttp()
httpRequest.request(params.info, (err, data) => {
if (!err && data.responseCode == http.ResponseCode.OK) {
let imgFile = fs.openSync(tmpFile, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.write(imgFile.fd, data.result as ArrayBuffer).then((writeLen: number) => {
console.info(TAG, "write data to file succeed and size is:" + writeLen);
}).catch((err: Base.BusinessError) => {
console.error(TAG, "write data to file failed with error message: " + err.message + ", error code: " + err.code);
}).finally(() => {
fs.closeSync(imgFile);
});
console.info(TAG, 'ArkTSCard download complete: %{public}s', tmpFile);
let file: fileFs.File;
let fileInfo: Record<string, string | number> = {};
try {
file = fs.openSync(tmpFile);
fileInfo[fileName] = file.fd;
} catch (e) {
console.error(TAG, `openSync failed: ${JSON.stringify(e as Base.BusinessError)}`);
}
class FormDataClass {
imgName: string = fileName;
formImages: object = fileInfo;
}
let formData = new FormDataClass();
let formInfo = formBindingData.createFormBindingData(formData);
formProvider.updateForm(formId, formInfo).then(() => {
console.info(TAG, '%{public}s', 'FormAbility updateForm success.');
}).catch((error: Base.BusinessError) => {
console.error(TAG, `FormAbility updateForm failed: ${JSON.stringify(error)}`);
});
} else {
console.error(TAG, `ArkTSCard download task failed. Cause: ${JSON.stringify(err)}`);
}
httpRequest.destroy();
})
```
# 效果
![Screenshot_20241014095106954.jpeg](
https://forums-obs.openharmony.c ... 7n9rx8rgwiuag8.jpeg
"Screenshot_20241014095106954.jpeg")
# 总结
当前卡片的基本功能都可以实现,但是仍有些不足,比如:不支持图片url自动加载;不支持点击效果ClickEffect;卡片对于动画的支持比较弱,不能实现长时间的动画效果;卡片进程不能成为后台任务,在生命周期没有活动时只能存活5秒,加载网络图片超时即失败等。
完整工程代码已开源到集成测试仓:[在线音乐应用](
https://gitee.com/openharmony-si ... o/MusicPlayerOnline
)。
后续随着版本迭代,OpenHarmony的功能会更加完善。
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5