鸿蒙应用开发从入门到入行 - 篇3:ArkUI布局基础与制作可交互页面
鸿蒙应用开发从入门到入行 - 篇3:ArkUI布局基础与制作可交互页面
导读:在本篇文章里,您将掌握事件、装饰器、双向绑定等相关知识,并利用所学知识做一个待办列表的案例。
练手案例:登录界面
开始之前,先说些题外话
猫林老师发现不少同学可以独立写出来,我很欣慰。说明行动力、悟性、之前前端留下的布局思想都还在。希望各位同学和更多的朋友们都能参与进来。大家以后写完可以把自己的代码或者效果贴到评论区相互讨论。讨论的人越多越有学习氛围,在这里大家都可以找到志同道合的人。并且,每一次热烈的讨论都能激励猫林老师更认真迅速地去写下一篇文章。
而且写教程文真的很需要花费额外时间,那就会挤占猫林老师想做爱做的事的时间。而且纯爱心发电其实动力并不足,所以也真的很需要各位读者提供热烈的正向回馈来激励猫林老师,所以大家请一定要多点赞、收藏、评论。要是可以,也分享给你周围想学鸿蒙的朋友。猫林老师保证把系列文章更新下去,让大家从文章里就能学到真东西,并且具备找工作能力。
好了,话不多说,开始说回上次的作业案例,让我们先回顾一下作业的效果图:
从上图分析可以发现整体上所有内容是从上往下布局,所以用Column作为根容器非常合适。
然后里面可以分为8行元素,分别为:Image、Text、Text、TextInput、TextInput、Row、Button、Text,如图
这些都是比较容易看出来的布局,主要是给大家解释下
短信验证码登录和忘记密码那一行,为什么还要用一个Row包起来呢?因为如果这两个文字不被Row包起来的话,那么父组件是Column,那短信验证码登录和忘记密码就会变成一行一个。所以用一个Row包起来,因为Row有从左到右布局子组件的能力,而这两个文字就需要从左到右,只不过一个在起点,一个在终点(即在首尾),所以这里到时候还可以给它做一个主轴上的布局为SpaceBetween。其他的无非记得要让根容器
Column铺满屏幕,也即宽高百分百,图片给宽度、登录界面给文字大小和加粗,登录帐号以使用更多服务改文字颜色、文字大小。两个TextInput给占位符,其中第二个TextInput记得要把type设置为password。其他剩余的三个label都是改文字颜色、字体大小。登录按钮给宽度铺满。然后整个页面是灰色,所以给Column设置背景色,再给TextInput设置背景色为白色。根据上述分析,代码如下
Column() {
Image($r('app.media.app_icon'))
.width(100) Text('登录界面')
.fontSize(24)
.fontWeight(700)
Text('登录账号以使用更多服务')
.fontColor(Color.Gray)
.fontSize(14) TextInput({ placeholder: '账号' })
.backgroundColor('#fefefe') TextInput({ placeholder: '密码' })
.backgroundColor('#fefefe')
.type(InputType.Password) Row() {
Text('短信验证码登录')
.fontColor('#3172f3')
Text('忘记密码')
.fontColor('#3172f3')
}
.justifyContent(FlexAlign.SpaceBetween) Button('登录')
.width('100%')
Text('注册账号')
.fontColor('#3172f3')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#eff1f3')
对应效果如下:
此时大家发现两个问题:
- 明明
短信验证码那一行的Row给了justifyContent(FlexAlign.SpaceBetween),但没生效,看着还是居中。为什么呢? - 所有内容行与行之间没有间距,导致挨的太紧。
- 明明
这两个问题都很好很解决,分别如下
给了
FlexAlign.SpaceBetween也没生效,是因为猫林老师上节课就说过大部分组件不给宽高就是靠内容撑开宽高,也即内容有大,Row就只有多大。所以你设置首尾对齐实际上它已经是首尾了,只不过因为Row就那么大,所以效果不动所以解决办法很简答:给Row一个
width('100%')即可行与行之间要设置间距可以给Column加
space
因此,改良代码如下(仅写出本次改动部分)
Column({ space: 10 }) {
...... Row() {
Text('短信验证码登录')
.fontColor('#3172f3')
Text('忘记密码')
.fontColor('#3172f3')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween) ........
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.backgroundColor('#eff1f3')
此时效果如下
发现间距是有了,但是中间的账号、密码、短信验证码登录这歌区域跟上面和下面太近,需要把这部分跟上下加一些间距
如上图所示,发现这个时候我们应该把中间这一部分作为一个整体,再统一设置整体的上下外间距即可。因此需要给中间的2个
TextInput和它下面包住两个文字的Row再套一个父容器。这里请大家思考下,他们的父容器,用Column好还是Row好呢?- 没错,用
Column好!因为用Row他们会从左往右排列,而我们依然要它从上到下,只不过多个父容器而已,所以用Column
- 没错,用
那分析完加父容器后,还有个问题。怎么设置这个父容器的距离外部的间距呢?会
css的同学知道,是margin,没错,ArkTS里也是margin(如果不懂什么叫margin的请挑战到本文最后的附录:外间距与内间距,再回此继续观看),语法如下组件() { }
.margin(间距数) // 例
Column() { }
.margin(20) // 代表这个 Column 具体上下左右间距都是20
如果你不需要上下左右间距都是同一个值,则可以传入一个对象,分别设置不同的margin,例
Column() { }
.margin({ left: 20, right: 10, top: 15, bottom: 30 } ) // 代表这个Column左间距20,右间距10,上间距15,下间距30
也可以仅设置几个方向的间距,没设置方向的间距代表为0,例
Column() { }
.margin({ top: 10, bottom: 20 } ) // 代表这个Column上间距10,下间距20,左右间距因为没设置,那么则代表0也即没有间距
因此,案例代码里先给中间部分加
Column,且设置外间距。并且因为中间部分包了Colum后,他们各自之间也没间距了,因此给包住验证码登录文字的Row再加一个上间距,TextInput不用加,因为他们本身就要挨在一起,改动代码如下Column({ space: 10 }) {
......... Column() {
TextInput({ placeholder: '账号' })
.backgroundColor('#fefefe') TextInput({ placeholder: '密码' })
.backgroundColor('#fefefe')
.type(InputType.Password) Row() {
Text('短信验证码登录')
.fontColor('#3172f3')
Text('忘记密码')
.fontColor('#3172f3')
}
.margin({ top: 10 })
}
.margin({ top: 20, bottom: 20 }) .......
}
此时效果如下
没错,现在跟最终效果图已经差不多了,但是发现左右两边都挨到边边了,而效果图需要左右两边都有点间距。这时候有两种解决办法:
- 给两个TextInput、Row、Button这四行设置左右外间距
- 给他们共同的父组件设置内间距
很明显,用第二种给共同的父组件设置内间距办法更方便。但是ArkTS里如何设置呢?其实还是用
padding,并且用法跟margin是一样的,例Column() { }
.padding(20) // 上下左右四个方向内间距都是20 Column() { }
.padding({ top: 20, bottom: 10, left: 20, right: 25 }) // 上内间距20,下内间距10,左内间距20,右内间距25 Column() { }
.padding({ left: 20, right: 20 }) // 左内间距和右内间距都是20,上下没写则默认是0
因此,再给根组件
Column设置padding,且只需要左右间距即可Column({ space: 10 }) {
........
}
.......
.padding({ left: 10, right: 10 })
至此,一个完整的
登录界面就写完了,你学废了吗?本案例新知识:
- margin: 外间距
- padding :内间距
事件
上面的登录案例中,我们目前点
登录按钮是没有任何反应的。要想让它有反应,必须添加事件,在ArkTS中如何添加事件呢?语法
组件() { }
.on事件名( e => {
// 事件处理代码
} )
例
Button('登录')
.onClick(e => {
// 处理代码
})
注意:上面的Click里的C大写。后面的事件名如无特殊情况,都是要首字母大写,例如change事件,写的时候要加
onChange,这跟前端里的全小写不一样,大家要注意。e则是事件对象,但用的略少,不需要时,可以不写e,替换为小括号
Button('登录')
.onClick(() => {
// 处理代码
})
提示框
如果现在,我希望点击按钮后弹出
登录成功的提示框怎么办呢?ArkUI里提供了PromptAction对象,专门用来做弹窗用法:
- 先导入,再调用
PromptAction对象的showToast方法,传入对象,配置提示信息,例
import { promptAction } from '@kit.ArkUI' promptAction.showToast({
message: '提示消息', // 提示的文字
duration: 2000 // 显示时长,不填则默认为1500
});
- 先导入,再调用
技巧:可以在写代码时,直接写promptAction,然后出提示后按回车,DevEco会自动帮你生成导入的代码,如下图
注意:
- duration为提示框多久后消失(也即显示时长),可以不填,不填则默认为1500,并且最小值也是1500,最大值是10000。如果填写的数字小于1500,也按1500来显示,如果大于10000,也按10000来显示。
- 单位是毫秒,1500即1.5秒
例:
promptAction.showToast({ message: '猫林老师教程真好!' })
- 效果如下
更多弹窗的用法可阅读官方文档:点我跳转至官方文档
声明组件内成员变量
很多时候我们这个页面(组件)需要声明一些变量用来保存数据,和对其处理。那么怎么声明呢?
一般会写在
build函数的上面,struct关键子下面,即下图位置语法为:
变量名: 类型 = 初始值
例:
userId: string = '' // 声明了一个名为 userId 的变量,它是字符串类型,初始值为空字符串
变量声明好了,如何在代码中使用呢?一律前面加this访问,例
this.userId
双向绑定
学会声明成员变量后,我们在
登录案例里,声明两个变量,分别叫userId与userPwd,专门用来跟账号、密码输入框分别做双向绑定struct Index {
// 成员变量列表
userId: string = 'admin'
userPwd: string = '123' build() {
........
}
}
插播双向绑定: 即数据一旦改变,界面跟着变。 界面输入内容有变化,数据也跟着变。
那么
ArkTS里如何让数据跟输入框做双向绑定呢?(Next版本后新增的语法)TextInput({ text: $$成员变量 }) // 例
TextInput( text: $$this.userId )
接下来让我们把声明的
userId与userPwd分别绑定到账号框和密码框TextInput({ placeholder: '账号', text: $$this.userId })
.backgroundColor('#fefefe') TextInput({ placeholder: '密码', text: $$this.userPwd })
.backgroundColor('#fefefe')
.type(InputType.Password)
此时保存代码会看到预览器里界面已经能显示绑定的数据了,如图
那我们说双向绑定是:数据 -> 界面, 同样,界面的输入变化也会影响数据,那是否能呢?带着这个疑问,我们先给
登录按钮加一个点击事件,点击事件里用console.log输出这两个变量的值。Button('登录')
.width('100%')
.onClick(() => {
console.log(`账号:${this.userId}, 密码:${this.userPwd}`)
})
注意:这里用到了模板字符串,一些同学可能不太理解这种字符串。这里说明一下:首先是用`这个符号包起来,跟单引号双引号都表示字符串,但区别在于模板字符串能很方便做字符串拼接,例如上面的代码,相当于是 '账号:' + this.userId + '密码:' + this.userPwd
然后我们去预览起的界面上重新输入,再点按钮输出,看显示什么(具体看截图,可以看到在哪看console.log输出的内容)
小结:
- 在输入框里,使用成员变量前加
$$即可双向绑定
- 在输入框里,使用成员变量前加
需注意:
- 目前
$$仅能用在基本数据类型且绑定给内置组件
- 目前
装饰器 - @State
从上面的效果可以看到,已经实现了双向绑定,但此时存在一个问题:数据无法再触发界面更新
例:修改登录的点击事件,在里面我修改
userId的值,看界面是否能更新Button('登录')
.width('100%')
.onClick(() => {
this.userId = '我要变'
console.log('新值:' + this.userId)
})
- 结果如图
原因:默认声明的成员变量不具备数据改变触发界面更新渲染的功能
解决办法:需要使用装饰器
装饰器:
修饰某些数据、函数,使其具有特殊作用
装饰器有很多种,本次学的叫
@State,注意首字母大写@State作用:
- 当被@State修饰的变量数据改变时,UI会发生对应的重新渲染。
用法
@State 变量: 类型 = '初始值'
让我们测试一下,来到
登录案例里找到userId,给它加@State试试@State userId: string = 'admin'
效果如下图:
但是同样的,加了装饰器后会有轻微的性能开销,即使这种开销甚至可以忽略不计。但是对于对性能优化有要求的
App而言,则建议。如果数据仅仅只是用来内部参与运算或临时接收界面输入,不需要将来重新更新UI,就不加@State装饰器不光只有
@State,后续还有很多,学一个记一个。小结:
- 装饰器
- 修饰数据、函数等,使其具有特殊作用
- @State
- 被@State修饰的变量能当它数据改变时,UI会发生对应的重新渲染
- 装饰器
实现登录功能
最后,我们给
登录案例收个尾,当用户点击登录按钮时,如果输入的账号是admin,密码是123,则提示登录成功,否则登录失败(将来学发送请求,如今暂时写死硬判断)代码如下
Button('登录')
.width('100%')
.onClick(() => {
if (this.userId === 'admin' && this.userPwd === '123') {
promptAction.showToast({ message: '登录成功' })
} else {
promptAction.showToast({ message: '账号或密码错误' })
}
})
效果如图:
总结内容
本文中我们学了事件、提示框、成员变量声明、双向绑定、装饰器。我们回顾一下
事件:
- on事件名,事件名首字母大写,例如:onClick、onChange
提示框:
需要先导入
import { promptAction } from '@kit.ArkUI'
然后使用
promptAction.showToast( { message: '提示信息', duration:时长 } )
技巧:可以直接输入promptAction,出提示后,按回车,DevEco会自动导入
声明成员变量
变量: 类型 = 初始值
默认情况下,变量改变不会触发界面重新渲染,因此需要装饰器:@State
双向绑定
$$this.变量名
课后练习
- 判断题:请回答对或者错
promptAction.showToast方法,传入duration属性,值为1000,代表提示框在1秒后消失
成员变量与输入框双向绑定时,成员变量前面不用加this
数据如果不加@State,就不能进行计算
练习答案
错 2. 错 3. 错
(错错错,是我的错。热恋的时候怎么不说,生活的无奈我已好困惑,你能不能不要再啰嗦)--- 请唱出来
附加练习
- 如上图所示,做一个年度待办目标的列表。
- 本案例功能比较丰富,各位能做多少做多少。本案例也会贯穿后面好几天的教学,所以涉及非常多新知识,做不出来也正常。
- 提示:打勾部份可以用Image也可以用
Checkbox,如需要做出布局,需要自行根据文档预习Progress、Stack、List等
互动环节
- 你觉得鸿蒙开发跟你以前会的开发,区别大吗?欢迎留下你的观点。
- 最后,创作不易,请不要吝啬您的点赞、关注、收藏、转发!
交流群
- 建了个鸿蒙交流群,帮助希望从业的人员方便交流技术以及获取鸿蒙认证。需要的请添加猫林老师微信(llybf365),拉你进群
鸿蒙应用开发从入门到入行 - 篇3:ArkUI布局基础与制作可交互页面的更多相关文章
- Python Web自动化测试入门与实战,从入门到入行
Python Web自动化测试入门与实战 购买地址 · 京东:https://item.jd.com/69239480564.html 天猫:https://detail.tmall.com/it ...
- LARK BOARD开发板入门学习-第2篇
1. 本次主要研究下HDMI接口,使用芯片是CH7033,这个芯片可以接VGA和HDMI两种接口,和FPGA的接口是地址数据总线 2. 值得注意的地方,下图的D1,双二极管BAT54S在电路中一般用于 ...
- Python全栈开发之路 【第六篇】:Python基础之常用模块
本节内容 模块分类: 好处: 标准库: help("modules") 查看所有python自带模块列表 第三方开源模块: 自定义模块: 模块调用: import module f ...
- Python全栈开发之路 【第四篇】:Python基础之函数
本节内容 函数def: 1.位置参数,默认参数 2.位置参数,关键参数 3.如果参数中出现 *users,传递的参数就可以不再是固定的个数, 传过来的所有元素进行打包成元组 *args,**kwarg ...
- Python全栈开发之路 【第三篇】:Python基础之字符编码和文件操作
本节内容 一.三元运算 三元运算又称三目运算,是对简单的条件语句的简写,如: 简单条件语句: if 条件成立: val = 1 else: val = 2 改成三元运算: val = 1 if 条件成 ...
- Python全栈开发之路 【第五篇】:Python基础之函数进阶(装饰器、生成器&迭代器)
本节内容 一.名称空间 又名name space,就是存放名字的地方.举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方. 名称空间共3种,分别如下 ...
- 「Android 开发」入门笔记
「Android 开发」入门笔记(界面编程篇) ------每日摘要------ DAY-1: 学习笔记: Android应用结构分析 界面编程与视图(View)组件 布局管理器 问题整理: Andr ...
- 浅谈入行Qt桌面端开发程序员-从毕业到上岗(1):当我们说到桌面端开发时,我们在谈论什么?
谈谈我自己 大家好,我是轩先生,是一个刚入行的Qt桌面端开发程序员.我的本科是双非一本的数学专业,22年毕业,只是部分课程与计算机之间有所交叉,其实在我毕业的时候并没有想过会成为一名程序员,也没有想过 ...
- PHP开发入行真功夫 三扬科技
前言与目录 PHP开发入行真功夫 前言 PHP开发入行真功夫 目录 第2章 基本语法 2.1.1 判断闰年程序 2.1.2 我们现在能做的…… 2.2.1 PHP的语言概貌 2.2.2 为我们的程 ...
- 《开发专家 Visual C 开发入行真功夫》笔记
智能感知的功能,输入 is 后,同时按下Alt + →这两个键就出现了供选择变量.方法.宏等的列表,继续输入 in 后,isInit就出来了. stdafx.h预编译头文件,.h应用程序主头文件,do ...
随机推荐
- 关于 CLOI 头像&博客主题征集
是这样的,开了一个新号准备做一个官号,当作一个公告栏(?),大家访问博客或者看消息也方便 现在苦于脑袋比较笨,想不出头像来,有意者可以帮设计下 此外,还(选择性地)需要一个博客主题,主要是简洁,打开会 ...
- 排查maven 冲突及解决方式
Maven Maven 是一个以项目为中心的自动化构建工具,主要用于Java项目的管理和构建.它提供了一种统一的方式来描述项目的结构.依赖关系和构建过程,简化了项目的构建和管理. Maven 的主要特 ...
- foobar2000 v1.6.10 汉化版(2022.05.01)
foobar2000 v1.6.10 汉化版 -----------------------[软件截图]---------------------- -----------------------[软 ...
- SVN(Linux)提交时强制写日志
SVN(Linux)提交时强制写日志 1.创建并修改pre-commit文件 进入svn/code/hooks目录,在svn版本库的hooks文件夹下面,复制模版pre-commit.tmplcp p ...
- js 中什么情况下返回 undefined 值
1. 声明变量没有赋值 <script> let num console.log(num) //undefined </script> 2. 访问不存在的属性 <scri ...
- docker对的tomcat、mysql、redis、nginx的安装
本章篇章主要讲解了docker对常用软件的安装说明 总体步骤:搜索镜像.拉取镜像.查看镜像.启动镜像.停止容器.移除容器 tomcat docker seacher tomcat//也可以在docke ...
- .NET使用Graphql的演示
Graphql是什么?先来一段AI给的回答: GraphQL是一种为API设计的查询语言,与REST相比,它提供了更高效.强大和灵活的方法来与数据交互.GraphQL由Facebook于2012年开发 ...
- 云原生周刊:K8sGPT 加入 CNCF | 2024.1.8
开源项目推荐 VolSync VolSync 使用 rsync 或 rclone 在集群之间异步复制 Kubernetes 持久卷.它还支持通过 Restic 创建持久卷的备份. KubeClarit ...
- 云原生爱好者周刊:在 PaaS 平台上托管 WebAssembly 应用
云原生一周动态要闻: Knative v1.1 发布 Nocalhost v0.6.12 发布 CircleCI 的企业功能现在免费了 SolarWinds 修复了一个 Serv-U 漏洞 Nvidi ...
- OGRE 渲染引擎 Windows 平台构建及编译
0 OGRE 机器人领域常见的Rviz和Gazebo可视化的渲染后端. 1 无数的坑 这东西真的可恶,官方教程文档以及项目构建的方式是真的繁琐,在Windows上. CMake 的构建必须要使用 CM ...