前言
直到她猛然想起在《HarmonyOS》中所学的bindSheet半模态弹窗,她就是她,不能谈及是一个新的页面,但是依旧不能忽略,隐墨她转身,下定了某种决心.......
一: bindSheet属性
1.1 概念和作用
bindSheet 是鸿蒙操作系统(HarmonyOS)中用于实现半模态页面的一个属性。它允许开发者将一个组件绑定为半模态页面,这种页面可以在不完全覆盖当前界面的情况下显示,通常用于弹出菜单、对话框等用户交互元素。半模态页面可以通过点击屏幕外部或特定的关闭按钮来关闭。
1.2 参数
bindSheet(isShow: boolean, builder: CustomBuilder, options?: SheetOptions)
-
isShow (this.isWarning): 波尔类型,用于控制半模态页面是否显示。当 ishow 为 true 时,半模态页面显示;为false 时,半模态页面隐藏。
-
builder (this.WarningInformation()): 一个函数,返回Sheet的内容。构建半模态页面的内容,需要使用
@Builder
修饰 -
options: 一个对象,包含多个配置项来定制Sheet的外观和行为。包含半模态页面的可选配置。这些配置可以包括半模态页面的高度、背景颜色、模糊样式、是否显示关闭按钮等。
1.3 options定制Sheet外观
options 一个对象,包含多个配置项来定制Sheet的外观和行为
detents: [700],
backgroundColor: Color.White,
blurStyle: BlurStyle.Thick,
showClose: true,
enableOutsideInteractive: false, //是否允许用户在 Sheet 以外的区域交互
dragBar: true
-
detents: 一个数组,包含Sheet可能的高度或位置设置。在这个例子中,
[700]
表示Sheet的固定高度为700像素。 -
backgroundColor: 设置Sheet的背景颜色。这里使用
Color.White
来设置背景为白色。 -
blurStyle: 设置Sheet背后的模糊效果。
BlurStyle.Thick
表示使用较厚的模糊效果。 -
showClose: 布尔值,表示是否在Sheet中显示一个关闭按钮。
true
表示显示。 -
enableOutsideInteractive: 布尔值,表示Sheet显示时,用户是否可以与Sheet之外的区域进行交互。
false
表示禁止交互。 -
dragBar: 布尔值,表示Sheet是否有一个可拖动的条,用户可以通过拖动它来改变Sheet的显示位置或隐藏Sheet。
true
表示启用。
二: bindSheet示例
本示例基于天气预报所构建的半模态弹窗,仅为展示 bindSheet 的实现效果。对于服务端获取数据 weatherMainInformation , daysWeather 和 airCondition。
2.1 页面根组件处调用bindSheet
@Prop weatherMainInformation: City<WeatherInformation>
@Prop daysWeather: WeatherInformation
@Prop airCondition: ConditionInformation
@State isMainInformation:boolean = false
@State isWarning :boolean = false
build() {
if (this.daysWeather.daily && this.airCondition.now != undefined) {
Column({ space: 20 }) {
Column({ space: 15 }) {
Text(`${this.weatherMainInformation.detail?.now?.temp}°`).fontSize(120).fontWeight(600).fontColor(Color.White)
Text(`${this.daysWeather.daily[0].tempMin}°/${this.daysWeather.daily[0].tempMax}°`)
.fontSize(18)
.fontWeight(500)
.fontColor(Color.White)
Row({ space: 20 }) {
Text(`${this.weatherMainInformation.detail?.now?.text}`)
.fontSize(21)
.fontWeight(500)
.fontColor(Color.White)
Text(`空气${this.airCondition.now.category}`).fontSize(21).fontWeight(500).fontColor(Color.White)
}
.justifyContent(FlexAlign.Center)
}
.onClick(() => this.isMainInformation = !this.isMainInformation)
.bindSheet(this.isMainInformation, this.MainInformation(), {
detents: [700],
backgroundColor: Color.White,
blurStyle: BlurStyle.Thick,
showClose: true,
enableOutsideInteractive: false, //是否允许用户在 Sheet 以外的区域交互
dragBar: true
})
if (this.airCondition.warning != undefined && this.airCondition.warning[0] != undefined) {
Row({ space: 10 }) {
Text(subString(this.airCondition.warning[0].title)).fontSize(18).fontWeight(400).fontColor(Color.White)
Image($r('app.media.right_arrow')).width(30).fillColor(Color.White)
}
.onClick(() => this.isWarning = !this.isWarning)
.bindSheet(this.isWarning, this.WarningInformation(), {
detents: [700],
backgroundColor: Color.White,
blurStyle: BlurStyle.Thick,
showClose: true,
enableOutsideInteractive: false, //是否允许用户在 Sheet 以外的区域交互
dragBar: true
})
}
}
.width('100%')
.margin({
left: 30,
right: 30,
top: 10,
bottom: 10
})
.alignItems(HorizontalAlign.Center)
}
isMainInformation 和 isWarning
是定义的状态变量,它用于控制主信息区域的显示状态,通过点击改变 isMainInformation 和 isWarning 的值实现对于半模态弹窗的展示或者隐藏。对于不同的根组件有不同的展示效果。
this.MainInformation() 和 this.WarningInformation() 为实现展开的内容。
未展开的页面如下
2.2 使用@Builder修饰组件
//展开主要的天气信息
@Builder MainInformation() {
Column({ space: 10 }) {
Column({ space: 5 }) {
Text(this.weatherMainInformation.name).fontSize(20).fontWeight(CommonConstants.FONT_WEIGHT_600)
if (this.weatherMainInformation.detail?.now?.obsTime) {
Text(this.CalculateTime(this.weatherMainInformation.detail?.now?.obsTime)).fontSize(15).opacity(0.6)
}
}
.width('100%')
.height(50)
.alignItems(HorizontalAlign.Start)
if (this.weatherMainInformation.detail?.now && this.daysWeather.daily && this.airCondition.now != undefined) {
Row() {
Column({ space: 25 }) {
Text(`${this.weatherMainInformation.detail?.now?.temp}°`)
.fontSize(100)
.fontWeight(500)
Row() {
Text(`${this.weatherMainInformation.detail?.now?.text} °`)
.fontWeight(300)
.fontSize(20).fontWeight(200)
Text(`空气${this.airCondition.now.category}`).fontColor(Color.White).fontSize(10).fontWeight(300)
}
.justifyContent(FlexAlign.Center)
}.layoutWeight(1)
Image($r(`app.media.${this.weatherMainInformation.detail.now.icon}`)).width(100).height(100)
}
.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.margin(50)
}
Divider()
.color('#ff5b5a5a')
.width('95%')
Grid() {
if (this.weatherMainInformation.detail?.now) {
GridItem() {
this.RealTimeCard('体感温度', `${this.weatherMainInformation.detail?.now?.feelsLike}°`)
}
GridItem() {
//风向
this.RealTimeCard(this.weatherMainInformation.detail.now?.windDir,
`${this.weatherMainInformation.detail?.now?.windScale}级`)
}
GridItem() {
this.RealTimeCard('风向360角度', `${this.weatherMainInformation.detail?.now?.wind360}`)
}
GridItem() {
this.RealTimeCard('相对湿度', `${this.weatherMainInformation.detail?.now?.humidity}%`)
}
GridItem() {
this.RealTimeCard('过去1小时降水量', `${this.weatherMainInformation.detail?.now?.precip}/ml`)
}
GridItem() {
this.RealTimeCard('大气压强', `${this.weatherMainInformation.detail?.now?.pressure}/BP`)
}
GridItem() {
this.RealTimeCard('能见度', `${this.weatherMainInformation.detail?.now?.humidity}/Km`)
}
GridItem() {
this.RealTimeCard('云量', `${this.weatherMainInformation.detail?.now?.cloud}%`)
}
GridItem() {
this.RealTimeCard('露点温度', `${this.weatherMainInformation.detail?.now?.humidity}°`)
}
}
}
.width('100%')
.height(300)
.rowsTemplate('1fr 1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
}
.width('95%')
.height('100%')
.margin({top:20})
.padding(10)
}
//展开主要的预警信息
@Builder WarningInformation(){
Column({space:10}) {
ForEach(this.airCondition.warning,(warn:getWarning)=>{
List({space:15}) {
ListItem() {
Column({space:8}){
Row({space:8}) {
Image($r('app.media.warning_picture')).width(20).height(20)
Text(warn.title).fontSize(16).fontWeight(500)
}
Text(formatDate(warn.pubTime)).fontSize(12).fontWeight(500)
Text(warn.text).fontSize(16)
}
.alignItems(HorizontalAlign.Start)
.padding(10)
.margin(10)
.width('95%')
}
}
.width('100%')
})
}
}
@Builder RealTimeCard(title: string, context:string) {
Column({ space: 8 }) {
Text(title)
.fontSize(12)
.opacity(0.8)
Text(context)
.fontSize(16)
.fontWeight(CommonConstants.FONT_WEIGHT_500)
}
}
//计算时间的差值
CalculateTime( data : string): string {
// 移除时区偏移,将其转换为一个Date对象
let obsDate = new Date(data.replace('T', ' ').replace('+08:00', ''));
// 获取当前时间
let currentDate = new Date();
// 计算时间差,单位是毫秒, 将时间差转换为分钟
let diffInMinutes = Math.floor((currentDate.getTime() - obsDate.getTime()) / (1000 * 60));
// 根据时间差显示“X分钟前”
let timeAgo:string = ''
if (diffInMinutes < 1) {
timeAgo = "刚刚发布";
} else {
timeAgo = diffInMinutes + "分钟前发布";
}
return timeAgo
}
对于点击不同的组件时会展现不同的 bindSheet 属性的内容
this.MainInformation() 实现展开的内容。
this.WarningInformation() 实现展开的内容。
2.3 相关的注意事项
-
确保在使用
bindSheet
时,相关的状态变量(如示例中的showSheet
)是正确的,并且可以通过用户交互来更新。 -
配置选项可以根据设计需求进行调整,以达到预期的用户界面效果。
-
在设计半模态页面时,考虑到用户体验,确保关闭按钮或外部点击可以关闭半模态页面,并且半模态页面的内容不会干扰用户对主界面的操作。
后言
“当着天空中出现乌云的时候,我们就指出:这不过是暂时的现象,黑暗即将过去,曙光即在前头。”
任何状态都是一时的,不是永久的。昨天在哭今天在笑,昨天今天失败明天成功了,去年钱多多今年大破产。无常是常态。得到的总会失去,又有新的得到。你会困难,你会绝望,但当你咬牙坚持下去时,你看过去的日子,让你真正寻味的是自己的态度,对自己生活的态度!
前进吧,少年!