基于HarmonyOS ArkUI实现音乐列表功能

本节将演示如何在基于HarmonyOS ArkUI的List组件来实现音乐列表功能。

本文涉及的所有源码,均可以在文末链接中找到。

活动主页

华为开发者论坛

规则要求具体要求如下:

  • 第1步:观看<HarmonyOS第一课>“营”在暑期•系列直播,一步步学会基于HarmonyOS最新版本的应用开发。
  • 第2步:基于自适应布局和响应式布局,实现一次开发,多端部署音乐专辑,并成功完成展现音乐列表页的实现。如图所示:

创建应用

选择空模板。

cke_206.png

创建名为ArkTSMusicPlayer的HarmonyOS应用。

cke_207.png

核心代码讲解

主页

主页Index.ets 分为三部分:头部、中部、底部。

cke_208.png

代码如下:

import { BreakpointConstants } from '../common/constants/BreakpointConstants';

import { StyleConstants } from '../common/constants/StyleConstants';

import { Content } from '../components/Content';
import { Header } from '../components/Header';
import { Player } from '../components/Player';

@Entry
@Component
struct Index {

  @State currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM;
  build() {
    Stack({ alignContent: Alignment.Top }) {
      // 头部
      Header({ currentBreakpoint: $currentBreakpoint })

      // 中部
      Content({ currentBreakpoint: $currentBreakpoint })

      // 底部
      Player({ currentBreakpoint: $currentBreakpoint })
    }
    .width(StyleConstants.FULL_WIDTH)
  }

}复制

头部

头部Header.ets分为三部分:返回按钮、播放器名称、菜单。代码如下:

import router from '@ohos.router';
import { StyleConstants } from '../common/constants/StyleConstants';
import { HeaderConstants } from '../common/constants/HeaderConstants';
import { BreakpointType } from '../common/media/BreakpointSystem';

@Preview
@Component
export struct Header {
  @Link currentBreakpoint: string;

  build() {
    Row() {
      // 返回按钮
      Image($r('app.media.ic_back'))
        .width($r('app.float.icon_width'))
        .height($r('app.float.icon_height'))
        .margin({ left: $r('app.float.icon_margin') })
        .onClick(() => {
          router.back()
        })

      // 播放器名称
      Text($r('app.string.play_list'))
        .fontSize(new BreakpointType({
          sm: $r('app.float.header_font_sm'),
          md: $r('app.float.header_font_md'),
          lg: $r('app.float.header_font_lg')
        }).getValue(this.currentBreakpoint))
        .fontWeight(HeaderConstants.TITLE_FONT_WEIGHT)
        .fontColor($r('app.color.title_color'))
        .opacity($r('app.float.title_opacity'))
        .letterSpacing(HeaderConstants.LETTER_SPACING)
        .padding({ left: $r('app.float.title_padding_left') })

      Blank()

      // 菜单
      Image($r('app.media.ic_more'))
        .width($r('app.float.icon_width'))
        .height($r('app.float.icon_height'))
        .margin({ right: $r('app.float.icon_margin') })
        //.bindMenu(this.getMenu())
    }
    .width(StyleConstants.FULL_WIDTH)
    .height($r('app.float.title_bar_height'))
    .zIndex(HeaderConstants.Z_INDEX)
  }

}复制

中部

头部Content.ets分为2部分:封面和歌曲列表。代码如下:

 

import { GridConstants } from '../common/constants/GridConstants';
import { StyleConstants } from '../common/constants/StyleConstants';
import { AlbumCover } from './AlbumCover';
import { PlayList } from './PlayList';

@Preview
@Component
export struct Content {
  @Link currentBreakpoint: string;

  build() {
    GridRow() {

      // 封面
      GridCol({ span: { sm: GridConstants.SPAN_TWELVE, md: GridConstants.SPAN_SIX, lg: GridConstants.SPAN_FOUR } }) {
        AlbumCover({ currentBreakpoint: $currentBreakpoint })
      }
      .backgroundColor($r('app.color.album_background'))

      // 歌曲列表
      GridCol({ span: { sm: GridConstants.SPAN_TWELVE, md: GridConstants.SPAN_SIX, lg: GridConstants.SPAN_EIGHT } }) {
        PlayList({ currentBreakpoint: $currentBreakpoint })
      }
      .borderRadius($r('app.float.playlist_border_radius'))
    }
    .height(StyleConstants.FULL_HEIGHT)
    .onBreakpointChange((breakpoints: string) => {
      this.currentBreakpoint = breakpoints;
    })
  }
}复制

其中,歌曲列表的核心是通过List组件实现的,核心代码如下:

build() {
    Column() {
      // 播放全部
      this.PlayAll()

      // 歌单列表
      List() {
        LazyForEach(new SongDataSource(this.songList), (item: SongItem, index: number) => {
          ListItem() {
            Column() {
              this.SongItem(item, index)
            }
            .padding({
              left: $r('app.float.list_item_padding'),
              right: $r('app.float.list_item_padding')
            })
          }
        }, (item, index) => JSON.stringify(item) + index)
      }
      .width(StyleConstants.FULL_WIDTH)
      .backgroundColor(Color.White)
      .margin({ top: $r('app.float.list_area_margin_top') })
      .lanes(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ?
      ContentConstants.COL_TWO : ContentConstants.COL_ONE)
      .layoutWeight(1)
      .divider({
        color: $r('app.color.list_divider'),
        strokeWidth: $r('app.float.stroke_width'),
        startMargin: $r('app.float.list_item_padding'),
        endMargin: $r('app.float.list_item_padding')
      })
    }
    .padding({
      top: this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? 0 : $r('app.float.list_area_padding_top'),
      bottom: $r('app.float.list_area_padding_bottom')
    })
  }复制

底部

底部就是歌曲播放器了。代码如下:

import { SongItem } from '../common/bean/SongItem';
import { PlayerConstants } from '../common/constants/PlayerConstants';
import { StyleConstants } from '../common/constants/StyleConstants';
import { BreakpointType } from '../common/media/BreakpointSystem';
import { MusicList } from '../common/media/MusicList';

@Preview
@Component
export struct Player {
  @StorageProp('selectIndex') selectIndex: number = 0;
  @StorageLink('isPlay') isPlay: boolean = false;
  songList: SongItem[] = MusicList;
  @Link currentBreakpoint: string;

  build() {
    Row() {
      Row() {
        Image(this.songList[this.selectIndex]?.label)
          .height($r('app.float.cover_height'))
          .width($r('app.float.cover_width'))
          .borderRadius($r('app.float.label_border_radius'))
          .margin({ right: $r('app.float.cover_margin') })
          .rotate({ angle: this.isPlay ? PlayerConstants.ROTATE : 0 })
          .animation({
            duration: PlayerConstants.ANIMATION_DURATION,
            iterations: PlayerConstants.ITERATIONS,
            curve: Curve.Linear
          })
        Column() {
          Text(this.songList[this.selectIndex].title)
            .fontColor($r('app.color.song_name'))
            .fontSize(new BreakpointType({
              sm: $r('app.float.song_title_sm'),
              md: $r('app.float.song_title_md'),
              lg: $r('app.float.song_title_lg')
            }).getValue(this.currentBreakpoint))
          Row() {
            Image($r('app.media.ic_vip'))
              .height($r('app.float.vip_icon_height'))
              .width($r('app.float.vip_icon_width'))
              .margin({ right: $r('app.float.vip_icon_margin') })
            Text(this.songList[this.selectIndex].singer)
              .fontColor($r('app.color.singer'))
              .fontSize(new BreakpointType({
                sm: $r('app.float.singer_title_sm'),
                md: $r('app.float.singer_title_md'),
                lg: $r('app.float.singer_title_lg')
              }).getValue(this.currentBreakpoint))
              .opacity($r('app.float.singer_opacity'))
          }
        }
        .alignItems(HorizontalAlign.Start)
      }
      .layoutWeight(PlayerConstants.LAYOUT_WEIGHT_PLAYER_CONTROL)

      Blank()

      Row() {
        Image($r('app.media.ic_previous'))
          .height($r('app.float.control_icon_height'))
          .width($r('app.float.control_icon_width'))
          .margin({ right: $r('app.float.control_icon_margin') })
          .displayPriority(PlayerConstants.DISPLAY_PRIORITY_TWO)

        Image(this.isPlay ? $r('app.media.ic_play') : $r('app.media.ic_pause'))
          .height($r('app.float.control_icon_height'))
          .width($r('app.float.control_icon_width'))
          .displayPriority(PlayerConstants.DISPLAY_PRIORITY_THREE)

        Image($r('app.media.ic_next'))
          .height($r('app.float.control_icon_height'))
          .width($r('app.float.control_icon_width'))
          .margin({
            right: $r('app.float.control_icon_margin'),
            left: $r('app.float.control_icon_margin')
          })
          .displayPriority(PlayerConstants.DISPLAY_PRIORITY_TWO)
        Image($r('app.media.ic_music_list'))
          .height($r('app.float.control_icon_height'))
          .width($r('app.float.control_icon_width'))
          .displayPriority(PlayerConstants.DISPLAY_PRIORITY_ONE)
      }
      .width(new BreakpointType({
        sm: $r('app.float.play_width_sm'),
        md: $r('app.float.play_width_sm'),
        lg: $r('app.float.play_width_lg')
      }).getValue(this.currentBreakpoint))
      .justifyContent(FlexAlign.End)
    }
    .width(StyleConstants.FULL_WIDTH)
    .height($r('app.float.player_area_height'))
    .backgroundColor($r('app.color.player_background'))
    .padding({
      left: $r('app.float.player_padding'),
      right: $r('app.float.player_padding')
    })
    .position({
      x: 0,
      y: StyleConstants.FULL_HEIGHT
    })
    .translate({
      x: 0,
      y: StyleConstants.TRANSLATE_PLAYER_Y
    })
  }
}复制

效果演示

这个是竖版效果。

cke_209.png

这个横板效果。

cke_210.png

基于自适应布局和响应式布局,实现一次开发,多端部署。

完整视频演示见:【老卫搬砖】039期:HarmonyOS ArkTS实现音乐播放器UI_哔哩哔哩_bilibili

music.gif

源码

见:GitHub - waylau/harmonyos-tutorial: HarmonyOS Tutorial. 《跟老卫学HarmonyOS开发》

学习更多HarmonyOS

作为开发者,及时投入HarmonyOS 4的学习是非常必要的。鸿蒙生态经历了艰难的四年,但轻舟已过万重山,目前已经慢慢走上了正轨,再现繁荣指日可待。

可以从HaromnyOS 官网(华为HarmonyOS智能终端操作系统官网 | 应用设备分布式开发者生态)了解到最新的HaromnyOS咨询以及开发指导。除此之外,笔者也整理了以下学习资料。

  • 华为开发者联盟:华为开发者论坛
  • 《跟老卫学HarmonyOS开发》 开源免费教程:GitHub - waylau/harmonyos-tutorial: HarmonyOS Tutorial. 《跟老卫学HarmonyOS开发》
  • 《鸿蒙HarmonyOS手机应用开发实战》(清华大学出版社)
  • 《鸿蒙HarmonyOS应用开发从入门到精通战》(北京大学出版社),
  • “鸿蒙系统实战短视频App 从0到1掌握HarmonyOS” :鸿蒙系统实战短视频App 从0到1掌握HarmonyOS_实战课程_慕课网

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/89785.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构双向链表

Hello&#xff0c;好久不见&#xff0c;今天我们讲链表的双向链表&#xff0c;这是一个很厉害的链表&#xff0c;带头双向且循环&#xff0c;学了这个链表&#xff0c;你会发现顺序表的头插头删不再是一个麻烦问题&#xff0c;单链表的尾插尾删也变得简单起来了&#xff0c;那废…

spring整合mybatis教程(详细易懂)

一、引言 1、Spring整合MyBatis的目的是&#xff1f; 将两个框架结合起来&#xff0c;以实现更好的开发体验和效果。Spring提供了一种轻量级的容器和依赖注入的机制&#xff0c;可以简化应用程序的配置和管理。而MyBatis是一个优秀的持久层框架&#xff0c;可以方便地进行数据…

Docker使用mysql:5.6和 owncloud 镜像,构建一个个人网盘,安装搭建私有仓库 Harbor

一、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。 [rootlocalhost ~]# docker pull mysql:5.6[rootlocalhost ~]# docker pull owncloud[rootlocalhost ~]# docker run -itd --name mysql --env MYSQL_ROOT_PASSWORD123456 mysql:5.6 d45cc5b95f00692881baaf…

传输层协议

文章目录 端口号UDP协议UDP报文UDP发送数据报过程 TCP协议TCP报文确认应答超时重传连接管理流量控制拥塞控制补充小结 UDP实现TCP总结TCP和UDP的区别 端口号 端口号(Port)标识了一个主机上进行通信的不同的应用程序。 简单的说&#xff0c;就是两台主机通信时&#xff0c;要想…

Linux内核学习(八)—— 内存管理(基于Linux 2.6内核)

目录 一、页&#xff08;page&#xff09; 二、区&#xff08;zone&#xff09; 三、页操作 四、kmalloc() 五、vmalloc() 六、slab 分配器 七、在栈上的静态分配 一、页&#xff08;page&#xff09; 内核把物理页作为内存管理的基本单位。尽管处理器的最小可寻 …

Notepad++正则匹配

Notepad正则匹配 Notepad正则表达式字符串最长不能超过69个字符一、支持的语法二、正则表达式诀窍三、案例3.1、匹配时间戳3.2、提取指定字符串3.3、提取单词3.4、查找中文字符 四、示例4.1、示例1&#xff1a;把含目标字符串及之后的字符串全部替换4.2、示例2&#xff1a;4.3、…

项目部署之后页面没有刷新怎么办?

最近项目部署成功之后&#xff0c;突然产品找我&#xff0c;上线之后&#xff0c;页面没有生效&#xff0c;这是怎么回事&#xff1f;我这是第一次部署这个项目,也不太清楚历史问题,接下来就慢慢寻找答案吧, 如果心急的可以直接看后面的总结&#xff0c;下面我们好好聊聊缓存的…

RE:从零开始的车载Android HMI(四) - 收音机刻度尺

最近比较忙&#xff0c;研究复杂的东西需要大量集中的时间&#xff0c;但是又抽不出来&#xff0c;就写点简单的东西吧。车载应用开发中有一个几乎避不开的自定义View&#xff0c;就是收音机的刻度条。本篇文章我们来研究如何绘制一个收音机的刻度尺。 本系列文章的目的是在讲…

4.12 TCP 连接,一端断电和进程崩溃有什么区别?

目录 TCP keepalive TCP 的保活机制 主机崩溃 进程崩溃 有数据传输的场景 客户端主机宕机&#xff0c;又迅速重启 客户端主机宕机&#xff0c;一直没有重启 TCP连接服务器宕机和进程退出情况总结 TCP keepalive TCP 的保活机制 TCP 保活机制需要通过 socket 接口设置 S…

pytorch 实现VGG

VGG全称是Visual Geometry Group&#xff0c;因为是由Oxford的Visual Geometry Group提出的。AlexNet问世之后&#xff0c;很多学者通过改进AlexNet的网络结构来提高自己的准确率&#xff0c;主要有两个方向&#xff1a;小卷积核和多尺度。而VGG的作者们则选择了另外一个方向&a…

在Ubuntu上安装和设置RabbitMQ服务器,轻松实现外部远程访问

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

编码基础一:侵入式链表

一、简介概述 1、普通链表数据结构 每个节点的next指针指向下一个节点的首地址。这样会有如下的限制&#xff1a; 一条链表上的所有节点的数据类型需要完全一致。对某条链表的操作如插入&#xff0c;删除等只能对这种类型的链表进行操作&#xff0c;如果链表的类型换了&#…

牛客网Verilog刷题 | 入门特别版本

文章目录 1、 VL1 输出12、VL2 wire连线3、 VL3 多wire连接4、VL4 反相器5、VL5 与门6、VL6 NOR 门7、VL7 XOR 门8、VL8 逻辑运算10、VL10 逻辑运算211、VL11 多位信号12、VL12 信号顺序调整13、VL13 位运算与逻辑运算14、VL14 对信号按位操作15、VL15 信号级联合并16、VL16 信…

安装Docker并配置镜像加速器、容器

1.安装docker服务&#xff0c;配置镜像加速器 安装软件包 [rootlocalhost ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 设置yum源 [rootlocalhost ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo…

【问题处理】解决Spring事务@Transactional多层嵌套失效

场景&#xff1a; 在 AService 中&#xff0c;我会直接调用 A 的数据操作层去操作 A的数据 以及 A关联密切的其它数据&#xff0c;在操作完之后&#xff0c;会去调用 BService 和 CService 中更新对应的数据&#xff0c;并在每个方法上使用了事务&#xff0c;但在调用 BService…

VMware 中Centos8的NAT网络设置

1、先将虚拟机设置为NAT模式 2、打开虚拟网络编辑器&#xff0c;记录以下信息 NAT设置&#xff1a;子网掩码、网关 DHCP设置&#xff1a;I P 范围 (自动时) 3、进入Centos8的网络设置页面&#xff0c;按照记录的信息进行配置 4、重载、重启网卡 nmcli c reload ensl60 n…

4G电力摄像机如何通过AT指令对接到国网平台呢?

对于针对电网安全运行的迫切需求&#xff0c;”输电线路智能可视化监测系统”被研发并应用&#xff0c;通过视频监控和AI智能分析技术&#xff0c;实现了对输电线路远程视频在线监测、外力破坏智能分析&#xff0c;可实现对输电线路的全天候实时监测和预警&#xff0c;有效保障…

element plus 的图片上传组件回显

element图片回显是通过修改file-list属性的url属性实现的。 <!-- 图片上传 --><el-form-item label"景区图片" prop"s_img"><el-uploadlist-type"picture-card":action"网址":on-change"handleChange":befor…

【KingSCADA】问题处理:记录KS历史报警查询异常

哈喽&#xff0c;大家好&#xff01;我是雷工。 本篇记录KingSCADA的历史报警应用中的一个问题&#xff0c;及处理过程。 一、问题描述 最近客户遇到这么一个问题&#xff1a;当打开历史报警窗界面&#xff0c;自动加载的报警信息中有显示最近几天的报警信息&#xff0c;但当…

[JavaWeb]【十二】web后端开发-事务管理AOP

目录 一、事务管理 1.1 事务回顾 1.2 Spring事务管理 1.2.1 案例 1.2.1.1 EmpMapper新增deleteByDeptId方法 1.2.1.2 DeptServiceImpl 1.2.1.3 启动服务-测试 1.2.2 模拟异常 1.2.3 分析问题 1.2.4 Spring事务管理&#xff08;一般用在类似多次delete&#xff09; 1.2.4…