鸿蒙OS开发:【一次开发,多端部署】(音乐专辑主页)

news2024/11/26 6:59:07

一多音乐专辑主页

介绍

本示例展示了音乐专辑主页。

  • 头部返回栏: 因元素单一、位置固定在顶部,因此适合采用自适应拉伸,充分利用顶部区域。
  • 专辑封面: 使用栅格组件控制占比,在小尺寸屏幕下封面图与歌单描述在同一行。
  • 歌曲列表: 使用栅格组件控制宽度,在小尺寸屏幕下宽度为屏幕的100%,中尺寸屏幕下宽度为屏幕的50%,大尺寸屏幕下宽度为屏幕的75%。
  • 播放器: 采用自适应拉伸,充分使用底部区域。

本示例使用一次开发多端部署中介绍的自适应布局能力和响应式布局能力进行多设备(或多窗口尺寸)适配,保证应用在不同设备或不同窗口尺寸下可以正常显示。

用到了媒体查询接口[@ohos.mediaquery]。

效果预览

本示例在预览器中的效果:

本示例在开发板上运行的效果:

image.png

使用说明:

1.启动应用,查看本应用在全屏状态下的效果。

2.在应用顶部,下滑出现窗口操作按钮。(建议通过外接鼠标操作,接入鼠标只需要将鼠标移动至顶部即可出现窗口)

3.点击悬浮图标,将应用悬浮在其他界面上显示。

4.拖动应用悬浮窗口的四个顶角,改变窗口尺寸,触发应用显示刷新。改变窗口尺寸的过程中,窗口尺寸可能超出屏幕尺寸,此时在屏幕中只能看到应用部分区域的显示。可以通过移动窗口位置,查看应用其它区域的显示。

开发前请熟悉鸿蒙开发指导文档gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。

工程目录

AppMarket/entry/src/main/ets/
|---model
|   |---MediaData.ets                      // 主页用到的图片资源
|   |---SongList.ets                       // 歌曲数据
|   |---SongModule.ets                     // 事件监听函数模块
|---pages                                  
|   |---index.ets                          // 首页
|---common                                    
|   |---Content.ets                        // 内容组件
|   |---Header.ets                         // 标题栏
|   |---Player.ets                         // app模块(包含安装,展示图片,更多功能)
|   |---PlayList.ets                       // 歌单列表
|   |---PlayListCover.ets                  // 歌单封面                                          

具体实现

本示例介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口,将页面分拆为4个部分。

标题栏

由于在不同断点下,标题栏始终只显示“返回按钮”、“歌单”以及“更多按钮”,但“歌单”与“更多按钮”之间的间距不同。
通过栅格实现:将标题栏划分为“返回按钮及歌单”和“更多按钮”两部分,这两部分在不同断点下占据的列数不同。

歌单封面

通过栅格实现歌单封面,它由封面图片、歌单介绍及常用操作三部分组成这三部分的布局在md和lg断点下完全相同,但在sm断点下有较大差异,[源码参考]。

/*

 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



import { optionList } from '../model/SongList'



@Component

export default struct PlayListCover {

  @State imgHeight: number = 0

  @StorageProp('coverMargin') coverMargin: number = 0

  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm'

  @StorageProp('fontSize') fontSize: number = 0



  @Builder

  CoverImage() {

    Stack({ alignContent: Alignment.BottomStart }) {

      Image($r('app.media.pic_album'))

        .width('100%')

        .aspectRatio(1)

        .borderRadius(8)

        .onAreaChange((oldArea: Area, newArea: Area) => {

          this.imgHeight = newArea.height as number

        })

      Text($r('app.string.collection_num'))

        .letterSpacing(1)

        .fontColor('#fff')

        .fontSize(this.fontSize - 4)

        .translate({ x: 10, y: '-100%' })

    }

    .width('100%')

    .height('100%')

    .aspectRatio(1)

  }



  @Builder

  CoverIntroduction() {

    Column() {

      Text($r('app.string.list_name'))

        .opacity(0.9)

        .fontWeight(500)

        .fontColor('#556B89')

        .fontSize(this.fontSize + 2)

        .margin({ bottom: 10 })



      Text($r('app.string.playlist_Introduction'))

        .opacity(0.6)

        .width('100%')

        .fontWeight(400)

        .fontColor('#556B89')

        .fontSize(this.fontSize - 2)

    }

    .width('100%')

    .height(this.currentBreakpoint === 'sm' ? this.imgHeight : 70)

    .alignItems(HorizontalAlign.Start)

    .justifyContent(FlexAlign.Center)

    .padding({ left: this.currentBreakpoint === 'sm' ? 20 : 0 })

    .margin({

      top: this.currentBreakpoint === 'sm' ? 0 : 30,

      bottom: this.currentBreakpoint === 'sm' ? 0 : 20

    })

  }



  @Builder

  CoverOptions() {

    Row() {

      ForEach(optionList, item => {

        Column({ space: 4 }) {

          Image(item.image).height(30).width(30)

          Text(item.text)

            .fontColor('#556B89')

            .fontSize(this.fontSize - 1)

        }

      })

    }

    .width('100%')

    .height(70)

    .padding({

      left: this.currentBreakpoint === 'sm' ? 20 : 0,

      right: this.currentBreakpoint === 'sm' ? 20 : 0

    })

    .margin({

      top: this.currentBreakpoint === 'sm' ? 15 : 0,

      bottom: this.currentBreakpoint === 'sm' ? 15 : 0

    })

    .justifyContent(FlexAlign.SpaceBetween)

  }



  build() {

    if (this.currentBreakpoint === 'sm') {

      Column() {

        GridRow() {

          GridCol({ span: { sm: 4, md: 10 }, offset: { sm: 0, md: 1, lg: 1 } }) {

            this.CoverImage()

          }



          GridCol({ span: { sm: 8, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {

            this.CoverIntroduction()

          }



          GridCol({ span: { sm: 12, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {

            this.CoverOptions()

          }

        }

        .margin({ left: this.coverMargin, right: this.coverMargin })

        .padding({ top: this.currentBreakpoint === 'sm' ? 50 : 70 })

      }

    } else {

      Column() {

        GridRow() {

          GridCol({ span: { sm: 4, md: 10 }, offset: { sm: 0, md: 1, lg: 1 } }) {

            this.CoverImage()

          }



          GridCol({ span: { sm: 8, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {

            this.CoverIntroduction()

          }



          GridCol({ span: { sm: 12, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) {

            this.CoverOptions()

          }.margin({

            top: this.currentBreakpoint === 'sm' ? 15 : 0,

            bottom: this.currentBreakpoint === 'sm' ? 15 : 0

          })

        }

        .margin({ left: this.coverMargin, right: this.coverMargin })

        .padding({ top: this.currentBreakpoint === 'sm' ? 50 : 70 })

      }

      .height('100%')

    }

  }

}

1、在sm断点下,封面图片和歌单介绍占满12列,常用操作此时会自动换行显示。
2、在lg和md断点下,封面图片,歌单和常用操作各占一行中显示。

歌单列表

通过List组件的lanes属性实现:在不同断点下,歌单列表的样式一致,但sm和md断点下是歌单列表是单列显示,lg断点下是双列显示,[源码参考]。

搜狗高速浏览器截图20240326151344.png

/*`HarmonyOS与OpenHarmony鸿蒙文档籽料:mau123789是v直接拿`

 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



import { songList } from '../model/SongList'

import MyDataSource from '../model/SongModule'



@Component

export default struct PlayList {

  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm'

  @StorageProp('fontSize') fontSize: number = 0

  @Consume coverHeight: number



  @Builder

  PlayAll() {

    Row() {

      Image($r("app.media.ic_play_all"))

        .height(23)

        .width(23)

      Text($r('app.string.play_all'))

        .maxLines(1)

        .padding({ left: 10 })

        .fontColor('#000000')

        .fontSize(this.fontSize)

      Blank()

      Image($r('app.media.ic_order_play'))

        .width(24)

        .height(24)

        .margin({ right: 16 })

      Image($r('app.media.ic_sort_list'))

        .height(24)

        .width(24)

    }

    .height(60)

    .width('100%')

    .padding({ left: 12, right: 12 })

  }



  @Builder

  SongItem(title: string, label: Resource, singer: string) {

    Row() {

      Column() {

        Text(title)

          .fontColor('#000000')

          .fontSize(this.fontSize)

          .margin({ bottom: 4 })

        Row() {

          Image(label)

            .width(16)

            .height(16)

            .margin({ right: 4 })

          Text(singer)

            .opacity(0.38)

            .fontColor('#000000')

            .fontSize(this.fontSize - 4)

        }

      }

      .alignItems(HorizontalAlign.Start)



      Blank()

      Image($r('app.media.ic_list_more'))

        .height(24)

        .width(24)

    }

    .height(60)

    .width('100%')

  }



  build() {

    Column() {

      this.PlayAll()

      Scroll() {

        List() {

          LazyForEach(new MyDataSource(songList), item => {

            ListItem() {

              Column() {

                this.SongItem(item.title, item.label, item.singer)

                Divider()

                  .strokeWidth(0.5)

                  .color('#000')

                  .opacity(0.1)

              }

              .width('100%')

              .height(50)

              .padding({ left: 14, right: 14 })

            }

          }, item => item.id.toString())

        }

        .width('100%')

        .lanes(this.currentBreakpoint === 'lg' ? 2 : 1)

      }

      .height('100%')

      .flexGrow(1)

      .flexShrink(1)

    }

    .width('100%')

    .height('100%')

    .borderRadius({ topLeft: 20, topRight: 20 })

    .backgroundColor(Color.White)

    .padding({ bottom: this.currentBreakpoint === 'sm' ? this.coverHeight : 0 })

  }

}
播放控制栏

通过Blank组件实现拉伸能力:在不同断点下,播放控制栏显示的内容完全一致,唯一的区别是歌曲信息与播放控制按钮之间的间距有差异。

总体运行效果

通过在首页Column()中引用上述各组件后,可实现首页的组件整合渲染,即可完成整体页面开发,[源码参考]。

/*

 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */



import { songList } from '../model/SongList'

import MyDataSource from '../model/SongModule'



@Component

export default struct PlayList {

  @StorageProp('currentBreakpoint') currentBreakpoint: string = 'sm'

  @StorageProp('fontSize') fontSize: number = 0

  @Consume coverHeight: number



  @Builder

  PlayAll() {

    Row() {

      Image($r("app.media.ic_play_all"))

        .height(23)

        .width(23)

      Text($r('app.string.play_all'))

        .maxLines(1)

        .padding({ left: 10 })

        .fontColor('#000000')

        .fontSize(this.fontSize)

      Blank()

      Image($r('app.media.ic_order_play'))

        .width(24)

        .height(24)

        .margin({ right: 16 })

      Image($r('app.media.ic_sort_list'))

        .height(24)

        .width(24)

    }

    .height(60)

    .width('100%')

    .padding({ left: 12, right: 12 })

  }



  @Builder

  SongItem(title: string, label: Resource, singer: string) {

    Row() {

      Column() {

        Text(title)

          .fontColor('#000000')

          .fontSize(this.fontSize)

          .margin({ bottom: 4 })

        Row() {

          Image(label)

            .width(16)

            .height(16)

            .margin({ right: 4 })

          Text(singer)

            .opacity(0.38)

            .fontColor('#000000')

            .fontSize(this.fontSize - 4)

        }

      }

      .alignItems(HorizontalAlign.Start)



      Blank()

      Image($r('app.media.ic_list_more'))

        .height(24)

        .width(24)

    }

    .height(60)

    .width('100%')

  }



  build() {

    Column() {

      this.PlayAll()

      Scroll() {

        List() {

          LazyForEach(new MyDataSource(songList), item => {

            ListItem() {

              Column() {

                this.SongItem(item.title, item.label, item.singer)

                Divider()

                  .strokeWidth(0.5)

                  .color('#000')

                  .opacity(0.1)

              }

              .width('100%')

              .height(50)

              .padding({ left: 14, right: 14 })

            }

          }, item => item.id.toString())

        }

        .width('100%')

        .lanes(this.currentBreakpoint === 'lg' ? 2 : 1)

      }

      .height('100%')

      .flexGrow(1)

      .flexShrink(1)

    }

    .width('100%')

    .height('100%')

    .borderRadius({ topLeft: 20, topRight: 20 })

    .backgroundColor(Color.White)

    .padding({ bottom: this.currentBreakpoint === 'sm' ? this.coverHeight : 0 })

  }

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

汽车电子零部件(14):TMS热管理系统

前言: TMS(thermal management system)热管理系统,这是新能源汽车诞生后随之而产生的一种新汽车零部件,一旦热管理失控会触发自燃,这种现象也是对EV来说是件头疼的事。汽车的热管理系统(TMS)是一个关键部件,有助于调节汽车电池组、车厢和其他车辆系统的温度。TMS的主要…

假象和谎言

原创 | 刘教链 隔夜BTC(比特币)徘徊在69k一线。5.25教链内参报告,《BTC ETF持仓即将超越中本聪》。ETH ETF的尘嚣逐渐散去,复归于平静。戏刚唱了个开头,结尾还留着悬念。4000刀之于ETH看来是个关键阻力位,最…

JavaEE-Spring Controller(服务器控制以及Controller的实现和配置)

Spring Controller 服务器控制 响应架构 Spring Boot 内集成了 Tomcat 服务器,也可以外接 Tomcat 服务器。通过控制层接收浏览器的 URL 请求进行操作并返回数据。 底层和浏览器的信息交互仍旧由 servlet 完成,服务器整体架构如下: Server&…

[9] CUDA性能测量与错误处理

CUDA性能测量与错误处理 讨论如何通过CUDA事件来测量它的性能如何通过CUDA代码进行调试 1.测量CUDA程序的性能 1.1 CUDA事件 CPU端的计时器可能无法给出正确的内核执行时间CUDA事件等于是在你的CUDA应用运行的特定时刻被记录的时间戳,通过使用CUDA事件API&#…

第十四届蓝桥杯c++研究生组

A 关键思路是求每个十进制数的数字以及怎么在一个数组中让判断所有的数字次数相等。 求每个十进制的数字 while(n!0){int x n%10;//x获取了n的每一个位数字n/10;}扩展:求二进制的每位数字 (注意:进制转换、1的个数、位运算) x…

rk3568_semaphore

文章目录 前言1 什么是信号量1.1 信号量API函数2、信号量实验2.1 实验目的2.2函数源码2.3 运行结果图前言 本文记录rk3568开发板的信号量实验 1 什么是信号量 信号量是同步的一种方式,常常用于控制对共享资源的访问。 举个例子:停车场的停车位有100个,这100个停车位就是共…

js的学习

什么是JavaScript? JavaScript(简称:JS)是一门跨平台、面向对象的脚本语言。是用来控制网页行为的,”它能使网页可交互。 JavaScript 和Java 是完全不同的语言,不论是概念还是设计。但是基础语法类似。 JavaScript在1995 年由 Brendan Eich 发明&#x…

【OpenCV】图像通道合并与分离,ROI

介绍可以实现图像通道合并与分离的API,这只是一种方式,后续还会介绍其他的合并与分离方法,以及ROI区域截取的方法。相关API: split() merge() Mat对象() 代码: #include "iostream" #include "ope…

VUE3 学习笔记(6):data数据的监听、表单绑定、操作DOM

data数据的监听&#xff08;侦听&#xff09; 对于data的值的监听&#xff0c;可以用watch中与data中的参数命名一致的值做为函数进行获取监听变动前后的值再做逻辑判断&#xff0c;如下图所示。 示例代码 <template><div><p :class"classDemo">{…

【SQL学习进阶】从入门到高级应用(二)

文章目录 简单查询查一个字段查多个字段查所有字段查询时字段可参与数学运算查询时字段可起别名as关键字省略as关键字别名中有空格别名中有中文 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xf…

【测评】香橙派 AIpro上手初体验

AI毋庸置疑是近年来&#xff0c;热度最高的技术之一&#xff0c;作为一名工程师拥抱新技术的同时不可或缺的需要一块强悍的开发板&#xff0c;香橙派 AIpro除了拥有好看的皮囊之外&#xff0c;还拥有一个有趣且充满魅力的灵魂。作为一位长期活跃在嵌入式开发领域的工程师&#…

Autodl服务器中Faster-rcnn(jwyang)复现(一)

前言 在做实验时需要用到faster-rcnn做对比,本节首先完成代码复现,用的数据集是VOC2007~ 项目地址:https://github.com/jwyang/faster-rcnn.pytorch/tree/pytorch-1.0 复现环境:autodl服务器+python3.6+cuda11.3+Ubuntu20.04+Pytorch1.10.0 目录 一、环境配置二、编译cud…

杀死那个进程

一、场景 eclipse在启动tomcat时&#xff0c;出现端口被占用的情况。我寻思着“任务管理器”没出现相应程序在跑啊。 1.1问题&#xff1a;端口和进程的关系 端口和进程之间存在着一种关系&#xff0c;端口是一个逻辑概念&#xff0c;它用于标识网络通信中的一个终点&#xff0…

二分答案思想下的二进制问题

序列合并 题目描述 给定一个长度为 n n n 的非负整数序列 { a n } \{a_n\} {an​}&#xff0c;你可以进行 k k k 次操作&#xff0c;每次操作你选择两个相邻的数&#xff0c;把它们合并成它们的按位或。 形式化地&#xff0c;一次操作中&#xff0c;你选择一个下标 i i …

【算法】【二叉树,DFS,哈希集合,分类讨论】力扣1110. 删点成林

1110. 删点成林 文章目录 【算法】力扣【二叉树&#xff0c;DFS&#xff0c;哈希集合&#xff0c;分类讨论】1110. 删点成林题目描述示例 1&#xff1a;示例 2&#xff1a; 输入输出示例解释思路解析核心思想算法步骤复杂度分析 代码实现总结 【算法】力扣【二叉树&#xff0c…

软件程序设计规范(代码编写规范文档)-word下载

程序的编码是一个创造性极强的工作&#xff0c;必须要遵守一定的规则和限制&#xff0c;编码风格的重要性对软件项目开发来说是不言而喻的。 开发工程师在开发过程中必须遵守本规范&#xff0c;规范是代码编写及代码验收等管理环节中必须执行的标准。 编制基本原则&#xff1a;…

json/excel文件上传下载工具方法汇总

文章目录 浏览器下载json文件浏览器下载excel文件【Workbook】浏览器导入json文件【ObjectMapper】浏览器导入excel文件【Workbook】ResourceLoader读取类路径下单个jsonResourceLoader读取类路径下所有json文件 浏览器下载json文件 Operation(summary "设备模型导出(带分…

【Vue】自动导入组件

1. 下载插件 npm install unplugin-vue-components 2. 修改vite.config.js import { fileURLToPath, URL } from node:urlimport { defineConfig } from vite import vue from vitejs/plugin-vue import Components from unplugin-vue-components/vite // 按需加载自定义组件/…

鲜花门店小程序开发流程:详细教程,让你轻松掌握

想要开发一款专属于自己鲜花门店的小程序吗&#xff1f;不知道从何开始&#xff1f;别担心&#xff0c;本文将为你提供详细的开发流程&#xff0c;帮助你轻松掌握。 1. 注册登录乔拓云网并进入操作后台 首先&#xff0c;你需要注册并登录乔拓云网&#xff0c;然后进入操作后台…

系统开发与运行知识

系统开发与运行知识 导航 文章目录 系统开发与运行知识导航一、软件工程二、软件生命周期三、开发模型四、开发方法五、需求分析结构化分析 六、数据流图分层数据流图的画法设计注意事项 七、数据字典数据字典的内容 八、系统设计九、结构化设计常用工具十、面向对象十一、UML…