admin 管理员组文章数量: 1103806
这个项目开始是在api11版本下开发的,但是为了更多的友友学习,我还是把它向下适配到了api9,所以升级到api11或者api12的友友也可以瞅瞅,改动不大。
下面为大家讲解项目中的一些要点:
布局
页面布局比较简单,一眼望去纵向布局,中间穿插着一些横向布局,从上往下排就可以了。
要注意的是,页面底部还有个音乐列表弹窗,弹窗与主页面是层叠布局,所以主页面和弹窗要用Stack包裹。
因为弹窗是默认隐藏的,所以设置列表弹窗的初始y值为屏幕高度,布局基本代码如下:
@State screenWidth:number = px2vp(display.getDefaultDisplaySync().width)
@State screenHeight:number = px2vp(display.getDefaultDisplaySync().height)
@State listViewPosition:number = this.screenHeight
Stack({alignContent:Alignment.Bottom}){
//主页面
Flex({direction:FlexDirection.Column,justifyContent:FlexAlign.SpaceBetween}){
}
.width('100%')
.height('100%')
.padding({left:20,right:20})
//背景色渐变
.radialGradient({
center: [this.screenWidth/2, this.screenHeight/2],
radius: this.screenWidth*2,
colors: [[0xE0EEFF, 0.0], [0xE4F2FF, 0.3], [0xFBD4FF, 1]]
})
//底部弹窗
ListView({musicList:$musicList)
//设置初始位置
.position({y:this.listViewPosition})
}
关于弹窗的弹出和隐藏动画,会在下面动画部分讲解。
动画
本项目中的动画主要有两个,首先是音乐封面的匀速旋转,我选择使用计时器setInterval()来改变图片的角度:
//初始角度为0
@State angle: number = 0;
//点击播放按钮执行动画
startRotate() {
this.timer = setInterval(() => {
//保留2位小数
this.angle = this.angle + 0.005
}, 30);
}
//音乐封面
Image($rawfile(this.musicList[this.currentIndex].cover))
.width(this.screenWidth - 50)
.height(this.screenWidth - 50)
.borderRadius((this.screenWidth - 50)/2)
.objectFit(ImageFit.Fill)
.rotate({ x: 0, y: 0, z: 1, angle: this.angle*360 })
接下来是弹窗的出现和隐藏,前面说了弹窗一开始在屏幕底部看不到的位置,点击列表按钮时使用animateTo给它设置一个正确的y值即可实现由下向上的动画效果:
animateTo({
//动画时间
duration: 200,
}, () => {
//计算弹窗高度
let y = 20 + 40 + 62*this.musicList.length
//设置y值
this.listViewPosition = this.screenHeight - y
})
隐藏弹窗的动画相对麻烦一些,我做了一个类似手机屏幕底部的横条,在下拉横条的时候隐藏动画。
所以要给图中横条添加下滑手势,在下滑手势结束时使用刚才的方法将y值恢复初始值:
private panOption: PanGestureOptions = new PanGestureOptions({ direction: PanDirection.Down })
Row(){
}
.width(40)
.height(4)
.backgroundColor('rgb(234,235,237)')
.borderRadius(2)
.gesture(
PanGesture(this.panOption)
.onActionStart((event?: GestureEvent) => {
//识别到下拉手势
console.info('Pan start')
})
.onActionUpdate((event?: GestureEvent) => {
if (event) {
//下拉手势执行中
console.info('event:',JSON.stringify(event))
}
})
.onActionEnd(() => {
console.info('Pan end')
//下拉手势结束
animateTo({
duration: 200,
}, () => {
this.listViewPosition = this.screenHeight
})
})
)
播放音频
本文使用AVPlayer来播放音频,音频素材是本地rawfile中的文件,您也可以选择使用网络音频,注意播放网络音频要申请网络权限,它们的创建方法分别如下:
播放rawfile文件:
// 创建avPlayer实例对象
let avPlayer: media.AVPlayer = await media.createAVPlayer();
// 创建状态机变化回调函数
this.setAVPlayerCallback(avPlayer);
// 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
// 返回类型为{fd,offset,length},fd为HAP包fd地址,offset为媒体资源偏移量,length为播放长度
let context = getContext(this) as common.UIAbilityContext;
let fileDescriptor = await context.resourceManager.getRawFd(this.musicList[this.currentIndex].url);
let avFileDescriptor: media.AVFileDescriptor =
{ fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };
this.isSeek = false; // 支持seek操作
// 为fdSrc赋值触发initialized状态机上报
avPlayer.fdSrc = avFileDescriptor;
this.avPlayer = avPlayer
播放网络音频:
// 创建avPlayer实例对象
let avPlayer: media.AVPlayer = await media.createAVPlayer();
// 创建状态机变化回调函数
this.setAVPlayerCallback(avPlayer);
this.isSeek = false; // 不支持seek操作
avPlayer.url = 'https://cdn.soundstripe/uploads/audio_file/381e129db0964d5289ebdaec01f61bf1/mp3_PALA_OneMoreDance_Full.mp3?token=1712968809_026183eab08f6d0f3a7aa5d422212a980252cc82b135e6a9950ee00fc8d74b73';
this.avPlayer = avPlayer
第二步,为avPlayer设置回调函数:
// 注册avplayer回调函数
setAVPlayerCallback(avPlayer: media.AVPlayer) {
avPlayer.on('timeUpdate', (seekDoneTime: number) => {
if(this.duration > 0){
let progress = seekDoneTime/this.duration
this.progressNow = progress*100
}
this.progressTimeString = this.durationToTimeString(seekDoneTime)
})
// seek操作结果回调函数
avPlayer.on('seekDone', (seekDoneTime: number) => {
console.info(`AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
})
// 状态机变化回调函数
avPlayer.on('stateChange', async (state: string, reason: media.StateChangeReason) => {
switch (state) {
case 'idle': // 成功调用reset接口后触发该状态机上报
console.info('AVPlayer state idle called.');
avPlayer.release(); // 调用release接口销毁实例对象
break;
case 'initialized': // avplayer 设置播放源后触发该状态上报
console.info('AVPlayer state initialized called.');
avPlayer.prepare();
break;
case 'prepared': // prepare调用成功后上报该状态机
console.info('AVPlayer state prepared called.');
if(this.isPlay){
avPlayer.play();
}
this.duration = avPlayer.duration
this.durationTimeString = this.durationToTimeString(this.duration)
console.log('duration:',avPlayer.duration)
break;
case 'playing': // play成功调用后触发该状态机上报
console.info('AVPlayer state playing called.');
if (this.count !== 0) {
if (this.isSeek) {
console.info('AVPlayer start to seek.');
avPlayer.seek(avPlayer.duration); //seek到音频末尾
} else {
// 当播放模式不支持seek操作时继续播放到结尾
console.info('AVPlayer wait to play end.');
}
} else {
// avPlayer.pause(); // 调用暂停接口暂停播放
}
this.count++;
break;
case 'paused': // pause成功调用后触发该状态机上报
console.info('AVPlayer state paused called.');
// avPlayer.play(); // 再次播放接口开始播放
break;
case 'completed': // 播放结束后触发该状态机上报
console.info('AVPlayer state completed called.');
// avPlayer.stop(); //调用播放结束接口
// this.endRotate();
if(this.currentIndex < this.musicList.length - 1){
this.currentIndex += 1
this.changeSong()
}else {
this.endRotate();
}
break;
case 'stopped': // stop接口成功调用后触发该状态机上报
console.info('AVPlayer state stopped called.');
// avPlayer.reset(); // 调用reset接口初始化avplayer状态
break;
case 'released':
console.info('AVPlayer state released called.');
break;
default:
console.info('AVPlayer state unknown called.');
break;
}
})
}
下面是AVPlayer的常用方法:
//播放
this.avPlayer.play()
//暂停
this.avPlayer.pause()
//结束
this.avPlayer.stop()
//重置
this.avPlayer.reset()
//销毁释放
this.avPlayer.release()
对于如何进行切换歌曲,只需要重置当前AVPlayer对象并重新初始化即可。
以上就是对音乐播放器项目的讲解,由于涉及到播放音频和获取设备屏幕尺寸,请使用模拟器或真机运行项目。
如果大家还没有掌握鸿蒙,现在想要在最短的时间里吃透它,我这边特意整理了《鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程》以及《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://docs.qq/doc/DZVVBYlhuRkZQZlB3
鸿蒙语法ArkTS、TypeScript、ArkUI等…视频教程:https://docs.qq/doc/DZVVBYlhuRkZQZlB3
OpenHarmony APP应用开发教程步骤:https://docs.qq/doc/DZVVBYlhuRkZQZlB3
《鸿蒙开发学习手册》:
如何快速入门:https://docs.qq/doc/DZVVBYlhuRkZQZlB3
1.基本概念
2.构建第一个ArkTS应用
3.……
开发基础知识:https://docs.qq/doc/DZVVBYlhuRkZQZlB3
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……
基于ArkTS 开发:https://docs.qq/doc/DZVVBYlhuRkZQZlB3
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……
鸿蒙生态应用开发白皮书V2.0PDF:https://docs.qq/doc/DZVVkRGRUd3pHSnFG
版权声明:本文标题:HarmonyOS实战开发案列-如何开发一个音乐播放器 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.520sys.cn/xp/1754993114a1454543.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论