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,点击顶部的“编辑"菜单,打开 ”虚拟化网络编辑器“ 。 选择更改设置&#…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
Python第七周作业
Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt,并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径,并创建logs目录(若不存在) 3.递归遍历目录data,输出所有.csv文件的路径…...
