HarmonyOS Next之仿网易云APP实战开发教程(下) 原创
一、背景
上一节我们实现了仿网易云的列表页面和简单的自定义播放组件,这一节呢我们继续上一节的内容进行一个拓展和延伸,这节的主要实现内容就是点击列表中的歌曲列表能够跳转到音乐播放详情页面,并实现点击左右切换音乐,切换的同时页面上其他歌曲信息也要同步切换,并且在音乐暂停和播放的时候我们要根据状态来实现一个播放动画,让我们的应用更加的丰富一些,最后不要忘记歌曲的进度条和歌曲的时间展示。我们先来看看要实现的页面把:
二、线程通讯
上一节我们实现列表展示,点击事件里边我们用线程通讯的方式传递item数据过去,
let eventData: emitter.EventData = {
data: {
"content": item,
"id": 1,
}
};
let innerEvent: emitter.InnerEvent = {
eventId: 1,
priority: emitter.EventPriority.HIGH
};
emitter.emit(innerEvent, eventData);
然后在详情页面中接收传递过来的数据
let innerEvent: emitter.InnerEvent = {
eventId: 1
};
emitter.once(innerEvent, (data) => {
JSON.stringify(data)
});
之后我们在组件中开始处理数据,把音乐的图片和名称展示到组件上
Column() {
Row() {
封面
Image(this.songList[this.selectIndex].label)
.width(200)
.height(200)
.borderRadius(100)
.rotate({ angle: this.imageRotate })
.onAppear(() => {
this.animationFun();
})
}
歌曲名称 歌手
Column() {
Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
Text(this.songList[this.selectIndex].title)
.fontSize(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && !this.isFoldFull ?
$r('app.float.title_font_play_md') : $r('app.float.title_font_play'))
.fontColor(Color.White)
.opacity(0.86)
.fontWeight(FontWeight.Bold)
.fontFamily(PlayerConstants.FONT_FAMILY_BOLD)
}
Text(this.songList[this.selectIndex].singer)
.textAlign(TextAlign.Start)
.fontSize(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_MD && !this.isFoldFull ?
$r('app.float.title_font_play') : $r('app.float.font_fourteen'))
.fontColor($r('app.color.play_text_color'))
.fontFamily(PlayerConstants.FONT_FAMILY_BLACK)
.margin({ top: $r('app.float.music_text_margin_top') })
.width(StyleConstants.FULL_WIDTH)
.fontWeight(FontWeight.Regular)
}
.margin({ top: $r('app.float.music_info_margin_top') })
Blank()
ControlAreaComponent()
}
.height(StyleConstants.FULL_HEIGHT)
.width(StyleConstants.FULL_HEIGHT)
.clip(false)
效果如下
可以看到数据已经展示到页面上了
三、音乐播放控制
音乐播放控制这里就比较好实现了,因为我们实现已经封装了一个控制音乐播放的工具类,直接在image组件的click事件里做处理就好了
Row() {
Image($r('app.media.ic_public_forward'))
.controlImageBuilder()
.width(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
$r('app.float.control_width_lg') : $r('app.float.control_width'))
.onClick(() => {
MediaService.getInstance().playPrevious();
this.pageShowTime = 0;
})
Image(this.isPlay ? $r('app.media.ic_public_play') : $r('app.media.ic_public_pause'))
.controlImageBuilder()
.onClick(() => {
if (this.isPlay) {
MediaService.getInstance().pause();
} else {
if (MediaService.getInstance().getFirst()) {
MediaService.getInstance().loadAssent(0);
} else {
MediaService.getInstance().play();
}
}
this.pageShowTime = 0;
})
Image($r('app.media.ic_public_next'))
.controlImageBuilder()
.width(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
36 : 32)
.onClick(() => {
MediaService.getInstance().playNextAuto(true);
this.pageShowTime = 0;
})
}
.width(StyleConstants.FULL_WIDTH)
.justifyContent(FlexAlign.SpaceBetween)
.padding({
left: 36,
right: 36
})
可以看到底部的按钮和功能我们已经实现成功了
四、播放动画显示
播放动画这里我们就需要新增一些属性了,让他作用于我们的image组件上,实现一个动态旋转的图片
我们先实现动画要用的内容
private backDisplaySyncSlow: displaySync.DisplaySync | undefined = undefined;
private drawFrame: (value: displaySync.IntervalInfo) => void = (value: displaySync.IntervalInfo) => {
if (this.imageRotate >= 360 ) {
this.imageRotate = 0;
}
this.imageRotate += 1;
};
定义完成之后在生命周期aboutToAppear初始化数据
aboutToAppear() {
let range : ExpectedFrameRateRange = {
expected: 30,
min: 0,
max: 30
};
this.backDisplaySyncSlow = displaySync.create();
this.backDisplaySyncSlow.setExpectedFrameRateRange(range);
this.backDisplaySyncSlow.on('frame', this.drawFrame);
}
当音乐播放的时候我们需要动画去旋转,当音乐暂停的时候动画也暂停,这时候就需要对播放状态进行一个监听
@StorageLink('isPlay') @Watch('animationFun') isPlay: boolean = false;
监听方法实现一下,控制动画
animationFun() {
if (this.isPlay) {
this.backDisplaySyncSlow?.start();
} else {
this.backDisplaySyncSlow?.stop();
}
}
到这里就实现了音乐的动画效果了
五、播放模式控制
在这里边我们定义了两种播放模式,一种是默认播放模式,一种是拖动进度条的播放模式,他可以以进度条内的任意点进行播放和暂停,上边我们已经实现了进度条组件,但是并没有添加逻辑。现在我们实现一下
先定义一个参数进行标记 @StorageLink('pageShowTime') pageShowTime: number = 0;
然后在onChange时间里对播放进度进行处理。
代码如下:
Slider({ min: 0, max: this.max, step: 1, value: this.value })
.blockColor($r('app.color.slider_block'))
.selectedColor($r('app.color.slider_select'))
.trackColor($r('app.color.slider_track'))
.blockSize({
width: $r('app.float.slider_block'),
height: $r('app.float.slider_block')
})
.onChange((value: number, mode: SliderChangeMode) => {
if (mode === SliderChangeMode.End || mode === SliderChangeMode.Begin) {
MediaService.getInstance().seek(value);
}
this.pageShowTime = 0;
})
.height($r('app.float.slider_height'))
.hitTestBehavior(HitTestMode.Block)
运行之后可以看到拖动之后时间和歌曲的进度也会同步更新
到这里我们就实现了仿网易云音乐的播放详情页面