背景
承接上篇,我们已经实现了整个页面的布局,首先我们再次看一下最终效果吧。
继续实例
日期选择器 (DatePicker)
上篇中,我们完成了布局结构,其中中间是一个日期选择器,我们需要实现用户选择日期后,查询其所选日期的功能,这时候就需要获取用户选择的日期了,这对于ArkUI提供的DatePicker组件还是很方便实现的。
那么我们了解下本篇第一个知识点DatePicker:
日期选择器 (DatePicker)通过滑动选择器,实现用户交互式选择日期功能。
根据指定日期范围创建日期滑动选择器。
DatePicker(options?: DatePickerOptions)
ArkUI提供了DatePickerOptions配置日期选择器组件的参数。
其包含以下三个参数:
| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| start | Date | 否 | 指定选择器的起始日期。 默认值:Date(‘1970-1-1’) |
| end | Date | 否 | 指定选择器的结束日期。 默认值:Date(‘2100-12-31’) |
| selected | Date | 否 | 设置选中项的日期。 默认值:当前系统日期 |
那么如果我们需要设置2024年1月1日至2025年1月1日的日期范围,只需要设置参数的start和end值即可。此时代码如下:
DatePicker({
start: new Date('2024-1-1'),
end: new Date('2025-1-1'),
})
好了范围设定好了,我们需要将用户选择的日期,保存下来,此时我们就需要用到selected参数了,在当前视图build() 前添加这段代码, 保存用户选择的日期值,其默认值是新的当前日期对象
private selectedDate: Date = new Date()
此时DatePicker内增加selected参数
DatePicker({
start: new Date('2024-1-1'),
end: new Date('2025-1-1'),
selected: this.selectedDate
})
时间选择器还有些颜色值和效果和我们默认有些差别,我们需要对其部分属性进行修改,让我们了解下DatePicker的一些特有属性。
| 名称 | 参数类型 | 描述 |
|---|---|---|
| lunar | boolean | 日期是否显示农历。 - true:展示农历。 - false:不展示农历。 默认值:false |
| disappearTextStyle | PickerTextStyle | 设置所有选项中最上和最下两个选项的文本颜色、字号、字体粗细。 默认值: { color: ‘#ff182431’, font: { size: ‘14fp’, weight: FontWeight.Regular } } |
| textStyle | PickerTextStyle | 设置所有选项中除了最上、最下及选中项以外的文本颜色、字号、字体粗细。 默认值: { color: ‘#ff182431’, font: { size: ‘16fp’, weight: FontWeight.Regular } } |
| selectedTextStyle | PickerTextStyle | 设置选中项的文本颜色、字号、字体粗细。 默认值: { color: ‘#ff007dff’, font: { size: ‘20vp’, weight: FontWeight.Medium } } |
我们可以看到其默认是不显示农历的,故lunar属性可以不写,我们主要是修改下选择部分文字颜色,需要用到selectedTextStyle属性,此时DatePicker增加该属性,代码如下:
DatePicker({
start: new Date('2024-1-1'),
end: new Date('2025-1-1'),
selected: this.selectedDate
})
.selectedTextStyle({ color: '#132968', font: { size: '18', weight: FontWeight.Regular } })
最后,我们通过选择日期时触发的事件保存用户选择的日期到selectedDate中,看下DatePicker支持的变量:
| 名称 | 功能描述 |
|---|---|
| onDateChange(callback: (value: Date) => void) | 选择日期时触发该事件。 Date:返回选中的时间。 |
最后,我们增加当前onDateChange事件,代码如下:
atePicker({
start: new Date('2024-1-1'),
end: new Date('2025-1-1'),
selected: this.selectedDate
})
.selectedTextStyle({ color: '#132968', font: { size: '18', weight: FontWeight.Regular } })
.onDateChange((value: Date) => {
this.selectedDate = value
})
.padding(3)
.height(165)
.width(230)
日期选择器完成,那么接下来实现,查询用户选择的日期当天的火车票。也就是下一个组件Button按钮实现了。
按钮 (Button)
Button通常用于响应用户的点击操作并执行相应的功能事件。
其包含以上几种普通样式。
也可以通过包裹子元素实现图文混合的按钮。
基于我们的UI设计稿,我们需要的是带红色的纯文字按钮。
只需要在Button内部设置Text组件即可实现,颜色值则通过其backgroundColor属性实现,其他圆角和位置我们就通过布局完善和UI一样的效果即可。代码如下:
Button({ type: ButtonType.Normal }) {
Text( "开始查询")
.fontSize(18)
.fontColor(Color.White)
.margin({ left: 80, right: 80, top: 5, bottom: 5 })
}
.backgroundColor("#FC6A68")
最终我们需要这个“开始查询”按钮点击查询的功能,基于UI稿,我们知道用户点击按钮后就显示当前日期的车票信息,包含“日期”、“时间”、“车次”、“车厢”、“座位号”、“票价”这些,因为本次实例仅做基本演示,故除了“日期”外其他数据均写个文本即可,真实开发这些数据需要通过服务器反馈查询结果。
故,此时点击“开始查询”按钮会发生两件事情,
- “开始查询”按钮变成“确认订票”按钮。
- 隐藏日期选择器,显示查询的车票信息
我们需要用到@State装饰器判断用户点击“开始查询”按钮前后状态。
那么我们继续了解下一个知识点:@State装饰器
@State装饰器:组件内状态
@State装饰的变量又名状态变量,当我们在变量前加上@State装饰器后,其就和组件绑定起来,实现变量控制组件变化的显示的效果。
那么我们设定下用户是否点击“开始查询”的状态变量为ifStartSearch,其是默认为false的布尔值,我们需要再build() 前设置该变量,代码如下:
@State ifStartSearch: boolean = false;
当用户点击“开始查询”按钮时,当前变量需要改成true,此时我们为Button添加点击事件,此时Button的代码如下
Button({ type: ButtonType.Normal }) {
Text( "开始查询")
.fontSize(18)
.fontColor(Color.White)
.margin({ left: 80, right: 80, top: 5, bottom: 5 })
}
.margin(20)
.height(35)
.backgroundColor("#FC6A68")
.borderRadius(8)
.onClick(() => {
this.ifStartSearch = true
})
发现发现发现 基于上述分析,当用户点击“开始查询”按钮时发生的两件事情,我们首先解决第一件事情,即按钮文字的变化。我们可以借助三元运算符判断不同ifStartSearch状态显示的文字内容,此时Button内Text修改如下:
Text(this.ifStartSearch ? "确认订票" : "开始查询")
接下来需要解决第二件事情,即隐藏日期选择器,显示新的查票界面,此时我们需要借助if实现条件判断。
if/else:条件渲染
条件渲染可根据应用的不同状态,使用if、else和else if渲染对应状态下的组件内容。 其具有以下更新机制:
- 基于判断条件,若分支无变化,则不需要继续执行。
- 若判断条件发生改变,则删除此前构建组件。
- 构建符合判断条件的新组件,将新组件添加到if父容器中。
- 如果适用的else不存在,则不构建任何内容。
此时我们将之前DatePicker增加条件渲染判断,同时需要完善新的信息显示组件。代码如下:
if (!this.ifStartSearch) {
DatePicker({
start: new Date('2024-1-1'),
end: new Date('2025-1-1'),
selected: this.selectedDate
})
.selectedTextStyle({ color: '#132968', font: { size: '18', weight: FontWeight.Regular } })
.onDateChange((value: Date) => {
this.selectedDate = value
})
.padding(3)
.height(165)
.width(230)
}
else {
Column() {
}
.justifyContent(FlexAlign.SpaceAround)
.height(165)
当ifStartSearch为true时,需要显示新的内容,基于UI稿和前面内容,我们已经可以很简单知道查询内容怎么写了,其包含上下两个Row布局,每个Row又显示对应的两行文字。其中日期文本需要显示刚刚DatePicker获取的日期。代码如下:
Column() {
Row({ space: 15 }) {
Column({ space: 10 }) {
Text("日期")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text((this.selectedDate.getMonth() + 1).toString() + "月" + (this.selectedDate.getDate()).toString() + "日")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
Column({ space: 10 }) {
Text("时间")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("10:08")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
Column({ space: 10 }) {
Text("车次")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("Z225")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
}
Row({ space: 15 }) {
Column({ space: 10 }) {
Text("车厢")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("07车")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
Column({ space: 10 }) {
Text("座位号")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("061号")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
Column({ space: 10 }) {
Text("票价")
.fontSize(15)
.fontWeight(FontWeight.Normal)
.fontColor("#A1A9C3")
Text("210.0元")
.fontSize(17)
.fontColor("#132968")
}
.width(80)
}
}
.justifyContent(FlexAlign.SpaceAround)
.height(165)
其中我们通过获取的 this.selectedDate日期的getMonth()和getDate()获取最终月和日,注意,最终需要通过toString()将获取的数字转换成字符串。
月:this.selectedDate.getMonth() + 1).toString()
日:this.selectedDate.getDate()).toString()
那么目前还有下方两个功能没有实现:
-
点击切换目的地与出发地
-
点击“确认订票”实现订票功能吐司弹窗
这两个功能都是按钮相关的,那么我们一个个解决。
首先是目的地与出发地的切换,点击切换按钮后,实现目的地和出发地对调。
我们可以根据刚刚的@State装饰器和if/else条件渲染的知识点,对当前按钮也设置变量状态绑定。
首先设置变量,我们继续在build() 前设置该新的变量,代码如下:
@State ifSwitch : boolean = false;
然后在出发地和目的地组件位置,通过条件渲染,设置相反的组件,代码如下:
//出发地
if (!this.ifSwitch) {
Column({ space: 5 }) {
Text("信阳")
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor("#132968")
Text("XinYang")
.fontSize(13)
.fontColor("#132968")
}
.width(70)
}
else {
Column({ space: 5 }) {
Text("深圳")
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor("#132968")
Text("ShenZhen")
.fontSize(13)
.fontColor("#132968")
}
.width(70)
}
//目的地
if (!this.ifSwitch) {
Column({ space: 5 }) {
Text("深圳")
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor("#132968")
Text("ShenZhen")
.fontSize(13)
.fontColor("#132968")
}
.width(70)
}
else {
Column({ space: 5 }) {
Text("信阳")
.fontSize(20)
.fontWeight(FontWeight.Medium)
.fontColor("#132968")
Text("XinYang")
.fontSize(13)
.fontColor("#132968")
}
.width(70)
}
然后就是点击切换按钮后,其本身图标也会改变,因为点击后用户需要重新设定订票日期,所以其Button内需要增加一个修改ifStartSearch为false事件,代码如下:
Button() {
if (!this.ifSwitch) {
Image("/pages/ComponentClassification/ExampleComponents/OneReserve/buttonArrow.png")
.width(40)
}
else {
Image("/pages/ComponentClassification/ExampleComponents/OneReserve/buttonArrowReverse.png")
.width(40)
}
}
.backgroundColor("#DEEBF9")
.width(40)
.onClick(() => {
this.ifSwitch = !this.ifSwitch;
this.ifStartSearch = false
})
最后,我们最后一个功能,即点击“立即订票”,完成订票功能,我们用一个吐司弹窗代表订票成功。
因为只有ifStartSearch变量为true才会有“立即订票”按钮,所以我们需要再该按钮增加一个if/else条件渲染,当ifStartSearch变量为true时,点击弹出吐司弹窗。
ArkUI的吐司弹窗需要导入弹窗模板,我们在当前代码顶部加入代码:
import promptAction from '@ohos.promptAction';
然后通过该模板的ShowToastOptions命令实现吐司弹窗,让我们看下其包含的属性
| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| message | string或Resource | 是 | 显示的文本信息。 |
| duration | number | 否 | 默认值1500ms,取值区间:1500ms-10000ms。若小于1500ms则取默认值,若大于10000ms则取上限值10000ms。 |
| bottom | string或 number | 否 | 设置弹窗边框距离屏幕底部的位置。 默认值:80vp |
| showMode | ToastShowMode | 否 | 设置弹窗是否显示在应用之上。 默认值:ToastShowMode.DEFAULT,默认显示在应用内。 |
我们先简单修改内部message就行,修改为“恭喜您!购票成功,请尽快前往取票窗口取票”
当前Button代码最终如下:
Button({ type: ButtonType.Normal }) {
Text(this.ifStartSearch ? "确认订票" : "开始查询")
.fontSize(18)
.fontColor(Color.White)
.margin({ left: 80, right: 80, top: 5, bottom: 5 })
}
.margin(20)
.height(35)
.backgroundColor("#FC6A68")
.borderRadius(8)
.onClick(() => {
if (this.ifStartSearch) {
promptAction.showToast({
message: "恭喜您!购票成功,请尽快前往取票窗口取票"
})
}
this.ifStartSearch = true
})
至此,我们已经实现当前实例全部功能,效果如上图所示,但是目前还是毫无动画效果的,那么下一章我们开始制作相关动画吧。敬请期待!