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

news/2024/7/21 8:30:33 标签: 人工智能, harmonyos, 鸿蒙系统

本节将演示如何在基于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_实战课程_慕课网

http://www.niftyadmin.cn/n/4971567.html

相关文章

AttributeError: module ‘torchvision.io.image‘ has no attribute ‘ImageReadMode‘

我的torch和torchvision版本 import torch torch.__version__‘1.7.1cu110’ import torchvision torchvision.__version__‘0.8.2cu110’ 原代码 mode torchvision.io.image.ImageReadMode.RGB labels.append(torchvision.io.read_image(os.path.join(voc_dir, Segmentat…

Git企业开发控制理论和实操-从入门到深入(二)|Git的基本操作

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总https://blog.csdn.net/yu_cblog/cate…

亚马逊云科技云技能学习

文章目录 前言一、云技能学习的优势二、云技能学习的学习路径三、云技能学习的未来前景总结 前言 亚马逊云科技&#xff08;Amazon Web Services&#xff0c;AWS&#xff09;作为全球领先的云计算服务提供商&#xff0c;提供了众多创新的云技术解决方案。在这些方案中&#xf…

登录校验-JWT令牌-生成和校验

目录 JWT-生成 具体代码 运行结果如下 JWT-校验 具体代码 运行结果如下 小结 JWT-生成 具体代码 /*** 测试JWT令牌的生成*/Testpublic void TestJWT() {// 设置自定义内容Map<String, Object> claims new HashMap<>();claims.put("id", 1);claims…

若依前后端分离版本项目总结笔记

若依前后端分离学习笔试 1.路由问题 注意这个是前端找到你的路由的路径。 2.表格开关按钮快速实现 <el-table-column label"状态" align"center" key"status"><template slot-scope"scope"><el-switchv-model"s…

Linux内核学习(十)—— 块 I/O 层(基于Linux 2.6内核)

目录 一、剖析一个块设备 二、缓冲区和缓冲区头 三、bio 结构体 四、请求队列 五、I/O 调度程序 系统中能够随机&#xff08;不需要按顺序&#xff09;访问固定大小数据片&#xff08;chunks&#xff09;的硬件设备称作块设备&#xff0c;这些固定大小的数据片就称作块。最…

Alibaba Nacos Authentication Bypass Vulnerability

文章目录 Nacos 提供了四大功能服务发现和服务健康检查动态配置管理动态域名解析服务服务和元数据管理 Alibaba Nacos Authentication Bypass Vulnerability Alibaba Nacos(Dynamic Naming and Configuration Service)是由阿里巴巴公司维护的一款开源项目&#xff0c;易于构建云…

动态规划解题示例

一、动态规划 动态规划问题解决的思路一般有以下几步&#xff1a; 确定状态&#xff1a;在动态规划问题中&#xff0c;状态一般就是我们需要优化的问题中的变量。状态需要满足无后效性&#xff08;即某一阶段的状态一旦确定&#xff0c;就不受之后决策的影响&#xff09;。 确…