HarmonyOS NEXT应用开发边学边玩系列:从零实现一影视APP (五、电影详情页的设计实现)
在上一篇文章中,完成了电影列表页的开发。接下来,将进入电影详情页的设计实现阶段。这个页面将展示电影的详细信息,包括电影海报、评分、简介以及相关影人等。将使用 HarmonyOS 提供的常用组件,并结合第三方库
nutpi/axios
来实现网络请求。下面,一步步地来看如何实现电影详情页。
开源项目地址:https://atomgit.com/csdn-qq8864/hmmovie
好的作品是需要不断打磨,在你的学习和体验过程中有任何问题,欢迎到我的开源项目代码仓下面提交issue,持续优化。
获取电影详情接口
首先,需要定义一个用于获取电影详情的接口。这里使用 axiosClient.post
方法来实现,代码如下:
export const getDetailMv = (id: string): HttpPromise<DetailMvResp> => axiosClient.post({ url: '/detailmovie', data: { id: id } });
电影详情接口的具体信息如下:
POST http://120.27.146.247:8000/api/v1/detailmovie
Content-Type: application/json{"id": "1292052"
}
电影详情页的组件使用
在电影详情页中,将使用 Badge
、SymbolSpan
、Button
、Rating
等组件来展示电影的详细信息。
-
Badge 组件
Badge
组件用于在某个组件的右上角显示一个标记,通常用于展示某种数量或状态。在电影详情页中,将使用Badge
组件来展示“想看”和“看过”的数量。 -
SymbolSpan 组件
SymbolSpan
组件用于在文本中嵌入图标。在电影详情页中,将使用SymbolSpan
组件来展示“想看”和“看过”的图标。 -
Button 组件
Button
组件用于创建按钮,用户可以通过点击按钮来执行特定的操作。在电影详情页中,将使用Button
组件来创建“播放”按钮,用户点击后可以跳转到视频播放页面。 -
Rating 组件
Rating
组件用于展示评分。在电影详情页中,将使用Rating
组件来展示电影的豆瓣评分。
电影详情页的实现
下面,将展示电影详情页的具体实现代码:
import { getDetailMv, getMovieSrc } from "../../common/api/movie"
import { Log } from "../../utils/logutil"
import { BusinessError } from "@kit.BasicServicesKit"
import { DetailMvResp, DetailMvRespCast } from "../../common/bean/DetailMvResp"
import { LengthMetrics, promptAction } from "@kit.ArkUI"
import { MvSourceResp } from "../../common/bean/MvSourceResp"@Builder
export function MovieDetailPageBuilder() {Detail()
}@Component
struct Detail {pageStack: NavPathStack = new NavPathStack()private uid = ''@State detailData: DetailMvResp | null = null;private srcData: MvSourceResp | null = null;private description: string = ''private isToggle = false@State toggleText: string = ''@State toggleBtn: string = '展开'build() {NavDestination() {Column({ space: 0 }) {Row() {Image(this.detailData?.images).objectFit(ImageFit.Auto).width(120).borderRadius(5)Column({ space: 8 }) {Text(this.detailData?.title).fontSize(18)Text(this.detailData?.year + " " + this.detailData?.genre).fontSize(14)Row() {Badge({count: this.detailData?.wish_count,maxCount: 10000,position: BadgePosition.RightTop,style: { badgeSize: 22, badgeColor: '#fffab52a' }}) {Row() {Text() {SymbolSpan($r('sys.symbol.heart')).fontWeight(FontWeight.Lighter).fontSize(32).fontColor(['#fffab52a'])}Text('想看')}.backgroundColor('#f8f4f5').borderRadius(5).padding(5)}.padding(8)Blank(10).width(40)Badge({count: this.detailData?.reviews_count,maxCount: 10000,position: BadgePosition.RightTop,style: { badgeSize: 22, badgeColor: '#fffab52a' }}) {Row() {Text() {SymbolSpan($r('sys.symbol.star')).fontWeight(FontWeight.Lighter).fontSize(32).fontColor(['#fffab52a'])}Text('看过')}.backgroundColor('#f8f4f5').borderRadius(5).padding(5)}.padding(8)}Button('播放', { buttonStyle: ButtonStyleMode.NORMAL, role: ButtonRole.NORMAL }).borderRadius(8).borderColor('#fffab52a').fontColor('#fffab52a').width(100).height(35).onClick(() => {console.info('Button onClick')if (this.srcData != null) {this.pageStack.pushDestinationByName("VideoPlayerPage", { item: { video: this.srcData.urls[0], tvurls: this.srcData.tvurls, title: this.srcData.title, desc: this.detailData?.summary } }).catch((e: Error) => {// 跳转失败,会返回错误码及错误信息console.log(`catch exception: ${JSON.stringify(e)}`)}).then(() => {// 跳转成功});} else {promptAction.showToast({ message: '暂无资源' })}})}.alignItems(HorizontalAlign.Start) // 水平方向靠左对齐.justifyContent(FlexAlign.Start) // 垂直方向靠上对齐.padding(10)}.height(160).width('100%')Row() {Text('豆瓣评分').fontSize(16).padding(5)Rating({ rating: (this.detailData?.rate ?? 0) / 2, indicator: true }).stars(5).stepSize(0.5).height(28)Text(this.detailData?.rate.toString()).fontColor('#fffab52a').fontWeight(FontWeight.Bold).fontSize(36).padding(5)}.width('100%').height(80).borderRadius(5).backgroundColor('#f8f4f5').margin(20)Text('简介').fontSize(18).padding({ bottom: 10 }).fontWeight(FontWeight.Bold).alignSelf(ItemAlign.Start)Text(this.toggleText).fontSize(14).lineHeight(20).alignSelf(ItemAlign.Start)Text(this.toggleBtn).fontSize(14).fontColor(Color.Gray).padding(10).alignSelf(ItemAlign.End).onClick(() => {this.isToggle = !this.isToggleif (this.isToggle) {this.toggleBtn = '收起'this.toggleText = this.description} else {this.toggleBtn = '展开'this.toggleText = this.description.substring(0, 100) + '...'}})Text('影人').fontSize(18).padding({ bottom: 10 }).fontWeight(FontWeight.Bold).alignSelf(ItemAlign.Start)Scroll() {Row({ space: 5 }) {ForEach(this.detailData?.cast, (item: DetailMvRespCast) => {Column({ space: 0 }) {Image(item.cover).objectFit(ImageFit.Auto).height(120).borderRadius(5).onClick(() => {})Text(item.name).alignSelf(ItemAlign.Center).maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis }).fontSize(14).padding(10)}.justifyContent(FlexAlign.Center)}, (itm: DetailMvRespCast, idx) => itm.id)}}.scrollable(ScrollDirection.Horizontal)}.padding({ left: 10, right: 10 })}.title("电影详情").width('100%').height('100%').onReady(ctx => {this.pageStack = ctx.pathStack//从上个页面拿参数this.pageStack.getParamByName("MovieDetailPage")interface params {id: string;}let par = ctx.pathInfo.param as paramsLog.debug("par:%s", par.id)this.uid = par.id}).onShown(() => {console.info('Detail onShown');getDetailMv(this.uid).then((res) => {Log.debug(res.data.message)Log.debug("request", "res.data.code:%{public}d", res.data.code)this.detailData = res.datathis.description = this.detailData.summarythis.toggleText = this.description.substring(0, 100) + '...'}).catch((err: BusinessError) => {Log.debug("request", "err.data.code:%d", err.code)Log.debug("request", err.message)});getMovieSrc(this.uid).then((res) => {Log.debug(res.data.message)Log.debug("request", "res.data.code:%{public}d", res.data.code)if (res.data.code == 0) {this.srcData = res.data}}).catch((err: BusinessError) => {Log.debug("request", "err.data.code:%d", err.code)Log.debug("request", err.message)});})}
}
折叠效果的实现
在电影详情页中,对于电影的简介,使用了折叠效果,即默认只显示部分简介内容,用户点击“展开”按钮后可以查看完整简介。这个效果的实现主要通过控制 Text
组件的显示内容来实现。具体代码如下:
Text(this.toggleText).fontSize(14).lineHeight(20).alignSelf(ItemAlign.Start)
Text(this.toggleBtn).fontSize(14).fontColor(Color.Gray).padding(10).alignSelf(ItemAlign.End).onClick(() => {this.isToggle = !this.isToggleif (this.isToggle) {this.toggleBtn = '收起'this.toggleText = this.description} else {this.toggleBtn = '展开'this.toggleText = this.description.substring(0, 100) + '...'}
})
通过上述代码,实现了电影简介内容的折叠效果。
总结
在本文中,完成了电影详情页的设计与实现。主要使用了 Badge
、SymbolSpan
、Button
、Rating
等组件,并结合 nutpi/axios
库来实现网络请求。通过这些技术,可以快速地开发出功能丰富、用户体验良好的影视应用。希望本文对你有所帮助。
作者介绍
作者:csdn猫哥
原文链接:https://blog.csdn.net/yyz_1987
团队介绍
坚果派团队由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉等相关内容,团队成员聚集在北京、上海、南京、深圳、广州、宁夏等地,目前已开发鸿蒙原生应用和三方库60+,欢迎交流。
版权声明
本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
其他资源
官方系统图标资源:https://developer.huawei.com/consumer/cn/doc/design-guides/system-icons-0000001929854962
https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis-arkui/arkui-ts/ts-basic-components-symbolSpan.md
https://developer.huawei.com/consumer/cn/design/harmonyos-symbol/
相关文章:

HarmonyOS NEXT应用开发边学边玩系列:从零实现一影视APP (五、电影详情页的设计实现)
在上一篇文章中,完成了电影列表页的开发。接下来,将进入电影详情页的设计实现阶段。这个页面将展示电影的详细信息,包括电影海报、评分、简介以及相关影人等。将使用 HarmonyOS 提供的常用组件,并结合第三方库 nutpi/axios 来实现…...

hive表修改字段类型没有级连导致历史分区报错
一:问题背景 修改hive的分区表时有级连概念,指字段的最新状态,默认只对往后的分区数据生效,而之前的分区保留历史元数据状态。好处就是修改语句的效率很快,坏处就是如果历史分区的数据还有用,那就回发生分…...

云上贵州多彩宝荣获仓颉社区先锋应用奖 | 助力数字政务新突破
在信息技术应用创新的浪潮中,仓颉社区吸引了众多企业和开发者的积极参与,已有多个应用成功落地,展现出蓬勃的创新活力。仓颉编程语言精心遴选了在社区建设、应用创新、开源共建、技术布道等方面做出突出贡献的优秀项目应用,并颁发…...

JS宏进阶:JS宏中的文件系统FileSystem
FileSystem对象中包含文件和文件夹的一些基本和常见的操作接口。比如:判断路径是否存在、创建文件夹、创建文件、读取文件等等。他的出现可以取代文件流对txt或csv等文件的操作。官方文档网址:https://open.wps.cn/previous/docs/client/wpsLoad…...

XML序列化和反序列化的学习
1、基本介绍 在工作中,经常为了调通上游接口,从而对请求第三方的参数进行XML序列化,这里常使用的方式就是使用JAVA扩展包中的相关注解和类来实现xml的序列化和反序列化。 2、自定义工具类 import javax.xml.bind.JAXBContext; import javax.x…...

npm ERR! code CERT_HAS_EXPIRED
很不幸看到这个提示。 查了很多网上的解决方案,都提到一个解决方案: npm install -g npmlatest 靠就是执行install报的错,你要我通过install来解决这个问题。可见大多数人都是转发,从不自己试试。 第二个是看系统时间。这个基…...

30分钟内搭建一个全能轻量级springboot 3.4 + 脚手架 <5> 5分钟集成好caffeine并使用注解操作缓存
快速导航 <1> 5分钟快速创建一个springboot web项目 <2> 5分钟集成好最新版本的开源swagger ui,并使用ui操作调用接口 <3> 5分钟集成好druid并使用druid自带监控工具监控sql请求 <4> 5分钟集成好mybatisplus并使用mybatisplus generator自…...

【设计模式-结构型】装饰器模式
一、什么是装饰器模式 装饰器模式(Decorator Pattern)是一种结构型设计模式,它的核心思想是在不改变原有对象结构的情况下,动态地给对象增加一些功能,从而达到扩展功能的目的。举个例子,今天在家妈妈给蒸馒…...

分布式数据存储基础与HDFS操作实践(副本)
以下为作者本人撰写的报告,步骤略有繁琐,不建议作为参考内容,可以适当浏览,进一步理解。 一、实验目的 1、理解分布式文件系统的基本概念和工作原理。 2、掌握Hadoop分布式文件系统(HDFS)的基本操作。 …...

Linux 进程前篇(冯诺依曼体系结构和操作系统)
目录 一.冯诺依曼体系结构 1.概念 2.硬件层面的数据流 3.总结加补充 二.操作系统 (Operating System) 1.概念 2.设计OS的目的 3.定位 4.操作系统的管理 5.计算机体系的层状结构 在我们认识进程之前,我们先了解什么是冯诺依曼体系结构 一.冯诺依曼体系结构…...

Springboot Redisson 分布式锁、缓存、消息队列、布隆过滤器
redisson-spring-boot-starter 是 Redisson 提供的 Spring Boot 集成包,旨在简化与 Redis 的交互,包括分布式锁、缓存、消息队列、布隆过滤器等功能的实现。 Maven 依赖 在 Spring Boot 项目中添加 redisson-spring-boot-starter 依赖: <…...

【C语言】_字符串拷贝函数strcpy
目录 1. 函数声明及功能 2. 使用示例 3. 注意事项 4. 模拟实现 4.1 第一版:基本功能判空const修饰 4.2 第二版:优化对于\0的单独拷贝 4.3 第三版:仿strcpy的char*返回值 1. 函数声明及功能 char * strcpy ( char * destination, cons…...

基于 Vue 的拖拽缩放卡片组件:实现思路、方法及使用指南
引言 在前端开发中,实现可交互的组件能够极大地提升用户体验。本文将介绍一个基于 Vue 封装的可缩放卡片组件,从实现思路、代码具体实现以及使用方法等方面进行详细阐述,帮助开发者更好地理解和运用这一组件。项目源码地址:https…...

nginx 实现 正向代理、反向代理 、SSL(证书配置)、负载均衡 、虚拟域名 ,使用其他中间件监控
我们可以详细地配置 Nginx 来实现正向代理、反向代理、SSL、负载均衡和虚拟域名。同时,我会介绍如何使用一些中间件来监控 Nginx 的状态和性能。 1. 安装 Nginx 如果你还没有安装 Nginx,可以通过以下命令进行安装(以 Ubuntu 为例࿰…...

Kafka客户端-“远程主机强迫关闭了一个现有的连接”故障排查及解决
Kafka客户端-“远程主机强迫关闭了一个现有的连接”故障排查及解决 1. 故障现象 Kafka客户端发送数据时,出现“远程主机强迫关闭了一个现有的连接”错误,导致数据发送失败。错误信息如下: 2. 故障排查 【1】. 查看服务网络状态 出现故障…...

Node.js - Express框架
1. 介绍 Express 是一个基于 Node.js 的 Web 应用程序框架,主要用于快速、简便地构建 Web 应用程序 和 API。它是目前最流行的 Node.js Web 框架之一,具有轻量级、灵活和功能丰富的特点。 核心概念包括路由,中间件,请求与响应&a…...

AWS Lambda
AWS Lambda 是 Amazon Web Services(AWS)提供的无服务器计算服务,它让开发者能够运行代码而不需要管理服务器或基础设施。AWS Lambda 会自动处理代码的执行、扩展和计费,开发者只需关注编写和部署代码,而无需担心底层硬…...

mysql 如何快速删除表数据
在数据库管理中, 经常会遇到需要删除大量数据的情况. 对于 MySQL 数据库而言, 如何高效快速地删除数据是一个值得深入探讨的问题. 本文将详细介绍几种在 MySQL 中快速删除数据的方法及相关注意事项. delete 语句 delete 语句可以删除符合条件的指定数据, 但是在删除大量数据…...

物联网网关Web服务器--lighttpd服务器部署与应用测试
以下是在国产ARM处理器E2000飞腾派开发板上部署 lighttpd 并进行 CGI 应用开发的步骤: 1、lighttpd简介 Lighttpd 是一款轻量级的开源 Web 服务器软件,具有以下特点和功能: 特点 轻量级:Lighttpd 在设计上注重轻量级和高效性&a…...

vmware虚拟机配置ubuntu 18.04(20.04)静态IP地址
VMware版本 :VMware Workstation 17 Pro ubuntu版本:ubuntu-18.04.4-desktop-amd64 主机环境 win11 1. 修改 VMware虚拟网络编辑器 打开vmware,点击顶部的“编辑"菜单,打开 ”虚拟化网络编辑器“ 。 选择更改设置&#…...

智能家居篇 一、Win10 VM虚拟机安装 Home Assistant 手把手教学
智能家居篇 一、Win10 VM虚拟机安装 Home Assistant 手把手教学 文章目录 [智能家居篇]( )一、Win10 VM虚拟机安装 Home Assistant 手把手教学 前言一.下载Vm版本的HomeAsistant安装包 二.打开Vmware选择新建虚拟机1.选择自定义高级2.选择16.x及以上3.选择稍后安装4.根据官网的…...

Flutter插件制作、本地/远程依赖及缓存机制深入剖析(原创-附源码)
Flutter插件在开发Flutter项目的过程中扮演着重要的角色,我们从 https://pub.dev 上下载添加到项目中的第三方库都是以包或者插件的形式引入到代码中的,这些第三方工具极大的提高了开发效率。 深入的了解插件的制作、发布、工作原理和缓存机…...

Python猜数小游戏
Python 实现的《猜数游戏》 介绍 本文将展示如何使用 Python 编写一个简单的《猜数游戏》。这个游戏将会生成一个1到10之间的随机数,用户有最多三次机会来猜测正确的数字。如果用户猜对了,游戏将结束并显示恭喜信息;如果没有猜对࿰…...

--- 用java实现一个计时器 ---
这里的计时器值得是当线程设定的时间过了之后,自动执行该线程的工作 设计 MyTimer 既然是要在指定的时间之后执行任务,那么传入的参数就应该有run方法(需要执行的任务),time(在多少时间之后执行ÿ…...

OPI4A,目标检测,口罩检测,mnn,YoloX
记得之前,使用了bubbling导师复现的python版yolox,训练了自建的口罩数据集,得到了h5文件,又转换成pb文件,再使用阿里巴巴的MNN,使用它的MNNConvert,转换成mnn文件 最终实现了,在树莓…...

C#与Vue2上传下载Excel文件
1、上传文件流程:先上传文件,上传成功,返回文件名与url,然后再次发起请求保存文件名和url到数据库 前端Vue2代码: 使用element的el-upload组件,action值为后端接收文件接口,headers携带session信…...

Linux(Centos7)安装Mysql/Redis/MinIO
安装Mysql 安装Redis 搜索Redis最先版本所在的在线安装yum库 查看以上两个组件是否是开机自启 安装MinIO 开源的对象存储服务,存储非结构化数据,兼容亚马逊S3协议。 minio --help #查询命令帮助minio --server --help #查询--server帮助minio serve…...

港科夜闻 | 香港科大与微软亚洲研究院签署战略合作备忘录,推动医学健康教育及科研协作...
关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大与微软亚洲研究院签署战略合作备忘录,推动医学健康教育及科研协作。根据备忘录,双方将结合各自于科研领域的优势,携手推动医学健康领域的交流与合作。合作方向将涵盖人才培训、…...

森林网络部署,工业4G路由器实现林区组网远程监控
在广袤无垠的林区,每一片树叶的摇曳、每一丝空气的流动,都关乎着生态的平衡与安宁。林区监控正以强大的力量,为这片绿色家园筑起一道坚固的防线。 工业 4G 路由器作为林区监控组网的守护者,凭借着卓越的通讯性能,突破…...

ASP.NET Core - 配置系统之自定义配置提供程序
ASP.NET Core - 配置系统之自定义配置提供程序 4. 自定义配置提供程序IConfigurationSourceIConfigurationProvider 4. 自定义配置提供程序 在 .NET Core 配置系统中封装一个配置提供程序关键在于提供相应的 IconfigurationSource 实现和 IConfigurationProvider 接口实现&…...