HarmonyOS实战开发-如何实现一个简单的电子相册应用开发
介绍
本篇Codelab介绍了如何实现一个简单的电子相册应用的开发,主要功能包括:
- 实现首页顶部的轮播效果。
- 实现页面跳转时共享元素的转场动画效果。
- 实现通过手势控制图片的放大、缩小、左右滑动查看细节等效果。
相关概念
- Swiper:滑块视图容器,提供子组件滑动轮播显示的能力。
- Grid:网格容器,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。
- Navigation:Navigation组件一般作为Page页面的根容器,通过属性设置来展示页面的标题、工具栏、菜单。
- List:列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。
- 组合手势:手势识别组,多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。
环境搭建
软件要求
- DevEco Studio版本:DevEco Studio 3.1 Release。
- OpenHarmony SDK版本:API version 9。
硬件要求
- 开发板类型:润和RK3568开发板。
- OpenHarmony系统:3.2 Release。
环境搭建
完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:
- 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:
2.搭建烧录环境。
- 完成DevEco Device Tool的安装
- 完成RK3568开发板的烧录
3.搭建开发环境。
- 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
- 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
- 工程创建完成后,选择使用真机进行调测。
代码结构解读
本篇Codelab只对核心代码进行讲解。
├──entry/src/main/ets // 代码区
│ ├──common
│ │ ├──constansts
│ │ │ └──Constants.ets // 常量类
│ │ └──utils
│ │ └──Logger.ets // Logger公共类
│ ├──entryability
│ │ └──EntryAbility.ts // 程序入口类
│ ├──pages
│ │ ├──DetailListPage.ets // 图片详情页面
│ │ ├──DetailPage.ets // 查看大图页面
│ │ ├──IndexPage.ets // 电子相册主页面
│ │ └──ListPage.ets // 图片列表页面
│ └──view
│ └──PhotoItem.ets // 首页相册Item组件
└──entry/src/main/resources // 资源文件
构建应用页面
应用首页
应用首页用Column组件来实现纵向布局,从上到下依次是标题组件Text、轮播图Swiper、相册列表Grid。标题和轮播图均设置固定高度,底部相册列表通过layoutWeight属性实现自适应占满剩余空间。
// IndexPage.ets
Column() {Row() {Text($r('app.string.EntryAbility_label'))}Swiper(this.swiperController) {ForEach(Constants.BANNER_IMG_LIST, (item: Resource) => {Row() {Image(item)...}}, (item: Resource, index: number) => JSON.stringify(item) + index)}...Grid() {ForEach(IMG_ARR, (photoArr: Array<Resource>) => {GridItem() {PhotoItem({ photoArr })}....onClick(() => {router.pushUrl({url: Constants.URL_LIST_PAGE,params: { photoArr: JSON.stringify(photoArr) }}).catch((error: Error) => {Logger.error(Constants.TAG_INDEX_PAGE, JSON.stringify(error));});})}, (item: Array<Resource>, index: number) => JSON.stringify(item) + index)}....layoutWeight(1)
}
图片列表页面
图片列表页是网格状展开的图片列表,主要使用Grid组件和GridItem组件,GridItem高度通过aspectRatio属性设置为跟宽度一致。
// ListPage.ets
Navigation() {Grid() {ForEach(this.photoArr, (img: Resource, index: number) => {GridItem() {Image(img).onClick(() => {this.selectedIndex = index;router.pushUrl({url: Constants.URL_DETAIL_LIST_PAGE,params: {photoArr: JSON.stringify(this.photoArr),}}).catch((error: Error) => {Logger.error(Constants.TAG_LIST_PAGE, JSON.stringify(error));});})}....aspectRatio(1)}, (item: Resource) => JSON.stringify(item))}.columnsTemplate(Constants.GRID_COLUMNS_TEMPLATE).layoutWeight(1)
}
图片详情页面
图片详情页由两个横向滚动的List组件完成整体布局,两个组件之间有联动的效果。滚动底部的List,上边展示的图片会随着改变,同样左右滑动上边的图片时,底部List组件也会随之改变。
// DetailListPage.ets
Stack({ alignContent: Alignment.Bottom }) {List({ scroller: this.bigScroller, initialIndex: this.selectedIndex }) {ForEach(this.photoArr, (img: Resource, index: number) => {ListItem() {Image(img)....gesture(PinchGesture({ fingers: Constants.DOUBLE_NUMBER }).onActionStart(() => this.goDetailPage())).onClick(() => this.goDetailPage())}}, (item: Resource) => JSON.stringify(item))}....onScroll((scrollOffset, scrollState) => {if (scrollState === ScrollState.Fling) {this.bigScrollAction(scrollTypeEnum.SCROLL);}}).onScrollStop(() => this.bigScrollAction(scrollTypeEnum.STOP))List({ scroller: this.smallScroller, space: Constants.LIST_ITEM_SPACE, initialIndex: this.selectedIndex }) {ForEach(this.smallPhotoArr, (img: Resource, index: number) => {ListItem() {this.SmallImgItemBuilder(img, index)}}, (item: Resource, index: number) => JSON.stringify(item) + index)}....listDirection(Axis.Horizontal).onScroll((scrollOffset, scrollState) => {if (scrollState === ScrollState.Fling) {this.smallScrollAction(scrollTypeEnum.SCROLL);}}).onScrollStop(() => this.smallScrollAction(scrollTypeEnum.STOP))
}
查看大图页面
查看大图页面由一个横向滚动的List组件来实现图片左右滑动时切换图片的功能,和一个Row组件实现图片的缩放和拖动查看细节功能。对图片进行缩放时会从List组件切换成Row组件来实现对单张图片的操作,对单张图片进行滑动操作时,也会由Row组件转换为List组件来实现图片的切换功能。
// DetailPage.ets
Stack() {List({ scroller: this.scroller, initialIndex: this.selectedIndex }) {ForEach(this.photoArr, (img: Resource) => {ListItem() {Image(img)....onClick(() => router.back())}.gesture(PinchGesture({ fingers: Constants.DOUBLE_NUMBER }).onActionStart(() => {this.resetImg();this.isScaling = true;this.imgOffSetX = 0;this.imgOffSetY = 0;}).onActionUpdate((event: GestureEvent) => {this.imgScale = this.currentScale * event.scale;}).onActionEnd(() => {if (this.imgScale < 1) {this.resetImg();this.imgOffSetX = 0;this.imgOffSetY = 0;} else {this.currentScale = this.imgScale;}}))}, (item: Resource) => JSON.stringify(item))}....onScrollStop(() => {let currentIndex = Math.round((this.scroller.currentOffset().xOffset + (this.imageWidth / Constants.DOUBLE_NUMBER)) / this.imageWidth);this.selectedIndex = currentIndex;this.scroller.scrollTo({ xOffset: currentIndex * this.imageWidth, yOffset: 0 });}).visibility(this.isScaling ? Visibility.Hidden : Visibility.Visible)Row() {Image(this.photoArr[this.selectedIndex])...}.visibility(this.isScaling ? Visibility.Visible : Visibility.Hidden)
}
通过手势控制图片
大图浏览界面双指捏合时通过改变Image组件的scale来控制图片的缩放,单手拖动时通过改变Image的偏移量来控制图片的位置,手势操作调用组合手势GestureGroup实现。其中PinchGesture实现双指缩放手势,PanGesture实现单指拖动手势。
// DetailPage.ets
Row() {Image(this.photoArr[this.selectedIndex]).position({ x: this.imgOffSetX, y: this.imgOffSetY }).scale({ x: this.imgScale, y: this.imgScale })}.gesture(GestureGroup(GestureMode.Exclusive,PinchGesture({ fingers: Constants.DOUBLE_NUMBER }).onActionUpdate((event: GestureEvent) => {this.imgScale = this.currentScale * event.scale;}).onActionEnd(() => {if (this.imgScale < 1) {this.resetImg();this.imgOffSetX = 0;this.imgOffSetY = 0;} else {this.currentScale = this.imgScale;}}),PanGesture().onActionStart(() => {this.preOffsetX = this.imgOffSetX;this.preOffsetY = this.imgOffSetY;}).onActionUpdate((event: GestureEvent) => {this.imgOffSetX = this.preOffsetX + event.offsetX;this.imgOffSetY = this.preOffsetY + event.offsetY;}).onActionEnd(() => this.handlePanEnd())))
总结
您已经完成了本次Codelab的学习,并了解到以下知识点:
- 如何实现首页顶部的轮播效果。
- 如何实现页面跳转时共享元素的转场动画效果。
- 如何通过手势控制图片的放大、缩小、左右滑动查看细节等效果。
为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频》
HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等…视频教程
鸿蒙生态应用开发白皮书V2.0PDF:
获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF》
鸿蒙 (Harmony OS)开发学习手册
一、入门必看
- 应用开发导读(ArkTS)
- .……
二、HarmonyOS 概念
- 系统定义
- 技术架构
- 技术特性
- 系统安全
- …
三、如何快速入门?《鸿蒙基础入门学习指南》
- 基本概念
- 构建第一个ArkTS应用
- .……
四、开发基础知识
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- .……
五、基于ArkTS 开发
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 7.网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- .……
更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》
相关文章:

HarmonyOS实战开发-如何实现一个简单的电子相册应用开发
介绍 本篇Codelab介绍了如何实现一个简单的电子相册应用的开发,主要功能包括: 实现首页顶部的轮播效果。实现页面跳转时共享元素的转场动画效果。实现通过手势控制图片的放大、缩小、左右滑动查看细节等效果。 相关概念 Swiper:滑块视图容…...

FFmpeg将绿幕视频处理成透明视频播放
怎么在网页端插入透明视频呢,之前在做Web3D项目时,使用threejs可以使绿幕视频透明显示在三维场景中,但是在网页端怎么让绿幕视频透明显示呢? 如图上图,视频背景遮挡住后面网页内容 想要如下图效果 之前有使用过ffmpeg…...

【2024系统架构设计】案例分析- 4 嵌入式
目录 一 基础知识 二 真题 一 基础知识 1 基本概念 ◆系统可靠性是系统在规定的时间内及规定的环境条件下,完成规定功能的能力,也就是系统无故障运行的概率。或者,可靠性是软件系统在应用或系统错误面前,在意外或错误使用的情况下维持软件系统的功能特性的基本能力。...

基于javaweb(springboot+mybatis)生活美食分享平台管理系统设计和实现以及文档报告
基于javaweb(springbootmybatis)生活美食分享平台管理系统设计和实现以及文档报告 博主介绍:多年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 …...

【MySQL探索之旅】MySQL数据表的增删查改——约束
📚博客主页:爱敲代码的小杨. ✨专栏:《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更…...

【Linux】体验一款开源的Linux服务器运维管理工具
今天为大家介绍一款开源的 Linux 服务器运维管理工具 - 1panel。 一、安装 根据官方那个提供的在线文档,这款工具的安装需要执行在线安装, # Redhat / CentOScurl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start…...

STM32 软件I2C方式读取AS5600磁编码器获取角度例程
STM32 软件I2C方式读取AS5600磁编码器获取角度例程 🔖本例程使用正点原子例程作为工程模板创建。 📘 硬件电路部分 🌿原理图部分: 🌿PCB布线和电路 📙驱动代码部分 int main(void) {u16 i 0;u16 ra…...

[WTL/Win32]_[初级]_[如何设置ListView的列宽不出现水平滚动条]
场景 开发WTL/Win32的程序时,经常会用到表格控件CListViewCtrl。这个控件需要设置列的宽度,当用完100%的宽度来平均分配给列宽时,一加载数据多,就会出现垂直滚动条后,水平滚动条也会同时出现的问题。怎么设置才能让水…...
Mac更换JDK版本
1.确保系统中存在多个Java版本。 在Terminal中执行: /usr/libexec/java_home -V 结果: Matching Java Virtual Machines (2): 11.0.1, x86_64: "Java SE 11.0.1" /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home 1.8.0_2…...

Day55:WEB攻防-XSS跨站CSP策略HttpOnly属性Filter过滤器标签闭合事件触发
目录 XSS跨站-安全防御-CSP XSS跨站-安全防御-HttpOnly XSS跨站-安全防御-XSSFilter(过滤器的意思) 1、无任何过滤 2、实体化 输入框没有 3、全部实体化 利用标签事件 单引号闭合 4、全部实体化 利用标签事件 双引号闭合 5、事件关键字过滤 利用其他标签调用 双引号闭合…...

root_fs文件系统结构分析和内核加载流程
目录 概述 1 根文件系统下目录介绍 2 文件系统内容分析 2.1 etc/inittab代码分析 2.2 /etc/init.d/rcS 代码分析 2.3 /etc/mdev.conf代码分析 2.3.1 功能概述 2.3.2 /etc/mdev.conf的详细代码 2.4 /etc/init.d/rcS的源代码文件 3 分析内核中加载root_fs的流程 3.1 调…...

macOS系统配置RUST开发环境
打开rust语言官方网,然后点击马上开始: Rust 程序设计语言 配置RUST开发环境: 使用curl下载rust安装脚本: 复制到终端执行: curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs | sh 输入: y 选择默认安装,输入: 1...
Android 15全面解读:性能飙升、隐私守护与智能生活新纪元
1. 更强大的性能 Android 15 带来了一系列性能方面的改进,以确保您的设备在运行应用程序时能够更加流畅。通过对系统进行优化,Android 15 在响应速度和性能方面都有了显著的提升。 这些优化包括: 新一代处理器支持: Android 15 …...

Java项目:80 springboot师生健康信息管理系统
作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 系统的角色:管理员、宿管、学生 管理员管理宿管员,管理学生,修改密码,维护个人信息。 宿管员…...
云服务器配置 docker-spark
云服务器配置 docker-spark 1. 安装2. 启动3. 查看4. 验证5. 其他 1. 安装 我的服务器是腾讯云轻量应用服务器,2 核 2 G,已经内置了 docker, 配置大概如下: ubuntuVM-20-5-ubuntu --------------------- OS: Ubuntu 22.04 LTS x…...

Matlab之求直角坐标系下两直线的交点坐标
目的:在直角坐标系下,求两个直线的交点坐标 一、函数的参数说明 输入参数: PointA:直线A上的点坐标; AngleA:直线A的倾斜角,单位度; PointB:直线B上的点坐标…...

Python3:ModuleNotFoundError: No module named ‘elftools‘
问题背景 问题 ModuleNotFoundError: No module named ‘elftools’ 解决方法 pip3 install pyelftools 成功!!!...
【Vue】创建vue项目 npm ERR! code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED
在安装完vue后,一段时间后发现再次使用出错;感觉可能是使用了代理的原因,但是就算关闭了代理一样不行;最后重启大法解决。 此处记录解决时使用到的命令。 检查版本 node -v cnpm -v vue --version vue -V安装 npm install -g vu…...
5、Cocos Creator 动作系统
目录 1、动作系统 API 2、动作系统 API 3、缓动动作 4、参考 动作系统并不能取代动画系统,动作系统提供的是面向程序员的 API 接口,而动画系统则是提供在编辑器中来设计的。它们服务于不同的使用场景,动作系统比较适合来制作简单的形变和…...
web3 token 如何理解
"Web3 Token"是指建立在Web3技术堆栈上的数字令牌。为了更好地理解这个概念,让我们逐步解释: Web3:指的是下一代互联网(Web3.0),它是基于区块链技术的去中心化网络。Web3的核心理念是去中心化、安…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...