> 文档中心 > openHarmony的UI开发

openHarmony的UI开发


自适应布局

拉伸能力

Blank在容器主轴方向上,空白填充组件具有自动填充容器空余部分的能力。仅当父组件为Row/Column时生效,即是线性布局。这样便可以在两个固定宽度或高度的组件中间添加一个Blank(),将剩余空间占满,从而实现占两头的效果

在这里插入图片描述

​ 而在使用弹性布局中,可以使用flexBasis设置子组件在父容器主轴方向上的基准尺寸,还可以使用flexGrow来设置父容器的剩余空间分配给此属性所在组件的比例。最后还有flexShrink,它可以在父容器空间不足时,压缩子组件的比例。

缩放能力

​ 自适应缩放是指在各种不同大小设备中,子组件按照预设的比例,尺寸随容器尺寸的变化而变化。有两种方法可以实现。

1、使用layoutWeight属性

​ 父容器尺寸确定时,设置了layoutWeight属性的子组件与兄弟元素占主轴尺寸按照权重进行分配,忽略元素本身尺寸设 置,在任意尺寸设备下,自适应占满剩余空间

2、使用百分比设置

​ 父容器尺寸确定时,使用百分比设置子组件以及兄弟组件的width宽度,可以保证各自元素在任意尺寸下的自适应占比

定位能力

1、相对定位

​ 使用组件的offset属性进行相对定位,会根据初始位置按照设定好的偏移量进行位置调整。使用线性布局和offset可以实现大部 分布局的开发

2、绝对定位

​ 使用positon属性实现绝对布局,设定左上角为(0,0)位置,可以设置x和y坐标进行位置调整。但是对于不同尺寸的设备,使 得很多时候用绝对定位的适应性会比较差,在屏幕的适配上有缺陷

延伸能力

​ 容器在一个屏幕下无法展示所有内容的时候,就需要通过滚动条拖动展示,方法有两种:List组件和Scroll组件。list和scroll纵向 和横向均可以。用循环渲染进行渲染,若数据量过多,超过了一个屏幕,便可以通过滚动条拖动显示。

均分能力

线性布局

在这里插入图片描述

​ 通过上图的三个参数设置,实现了布局的自适应均分能力

弹性布局

​ 相比于前者,弹性布局少了space参数,但是directionwrapalignContent的加入,更加能体现出布局的自适应均分能力

网格布局

​ 网格布局具备较强的页面均分能力,它可以按行按列将容器均分成n块,然后再按列按行将子组件一个个放进去。例如在计算器 应用,可以将网格布局的页面均分能力充分地体现出来。

占比能力

​ 网格布局具备较强的子组件占比控制能力,支持自定义网格布局行数和列数,以及每行每列尺寸占比,支持设置子组件横跨几行 或者几列

隐藏能力

1、条件渲染

2、显隐控制

拆行能力

​ 网格布局支持设置子组件横跨几行或者几列

响应式布局

断点

栅格系统断点

​ 栅格系统通过监听窗口或容器的尺寸变化进行断点,通过reference设置断点切换参考物,从而实现了根据断点来判断采用哪 种设备的布局设置,最多可以设置六种设备。

{ //  设栅格系统有12列,断点有五个,可以判断六种设备columns:  12, breakpoints: {   value: ['200vp', '300vp', '400vp', '500vp', '1200vp'],   reference: BreakpointsReference.ComponentSize }  span: {  // 第一个种设备每个栅格子元素占用两列,第二种3列,第三种四列,以此类推  xs: 2,  sm: 3,  md: 4,  lg: 6,  xl: 8,  xxl: 12}

上面参数的设置的效果如下图所示:

在这里插入图片描述

媒体查询

媒体查询(Media Query)作为响应式设计的核心,在移动设备上应用十分广泛。它根据不同设备类型或同设备不同状态修改应用的样式。媒体查询的优势有:

  1. 提供丰富的媒体特征监听能力,针对设备和应用的属性信息(比如显示区域、深浅色、分辨率),设计出相匹配的布局。
  2. 当屏幕发生动态改变时(比如分屏、横竖屏切换),同步更新应用的页面布局。

官方例子:

import mediaquery from '@ohos.mediaquery'let portraitFunc = null@Entry@Componentstruct MediaQueryExample {  @State color: string = '#DB7093'  @State text: string = 'Portrait'  listener = mediaquery.matchMediaSync('(orientation: landscape)') // 当设备横屏时条件成立  onPortrait(mediaQueryResult) {    if (mediaQueryResult.matches) {      this.color = '#FFD700'      this.text = 'Landscape'    } else {      this.color = '#DB7093'      this.text = 'Portrait'    }  }  aboutToAppear() {    portraitFunc = this.onPortrait.bind(this) // 绑定当前应用实例    this.listener.on('change', portraitFunc)  }  build() {    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {      Text(this.text).fontSize(50).fontColor(this.color)    }    .width('100%').height('100%')  }}

横屏下文本内容为Landscape,颜色为#FFD700

在这里插入图片描述

非横屏下文本内容为Portrait,颜色为#DB7093

在这里插入图片描述

栅格布局

​ 栅格布局的总列数可以参考断点处,就是要设置好一共有多少行,还有每个栅格子元素占用多少行

​ 栅格子组件间距也很简单,就设置一下gutter就可以了,gutter: 10是水平间距,gutter: { x: 20, y: 50 } 是水平垂直间距

​ 排列方向有从左往右和从右往左

​ 而对于栅格子组件GridCol,有spanoffsetorder三个参数可以设置

span:子组件占栅格布局的列数,可以统一设置,也可以分设备类型设置不同占比

offset:就是偏移列数,就是可以起到拆列的作用

order:栅格子组件的序号,决定子组件排列次序。当子组件不设置order或者设置相同的order, 子组件按照代码顺序展示。当子组件设置不同的order时,order较小的组件在前,较大的在后。 当子组件部分设置order,部分不设置order时,未设置order的子组件依次排序靠前,设置了order的子组件按照数值从小到大排列。

动画

属性动画

​ 这个可以直接跟在组件的属性方法里面进行填写,不过只支持width、height、backgroundColor、opacity、scale、rotate、translate等部分通用属性变化时生效

 .animation({   duration: 2000,   curve: Curve.EaseOut,   iterations: 3,   playMode: PlayMode.Normal })

显式动画

​ 提供全局animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。

和前者不同的是,这里可以在全局对设定好的参数进行改变便可以触发动画的执行

 .onClick(() => {   if (this.flag) {     animateTo({duration: 2000,curve: Curve.EaseOut,iterations: 3,playMode: PlayMode.Normal,onFinish: () => {  console.info('play end')}     }, () => {this.widthSize = 100this.heightSize = 50     })   } else {     animateTo({}, () => {this.widthSize = 250this.heightSize = 100     })   }   this.flag = !this.flag })

转场动画

页面间转场

​ 在全局pageTransition方法内配置页面入场和页面退场时的自定义转场动效。

​ 官方例子:配置了当前页面的入场动画为淡入,退场动画为缩小。

// index.ets@Entry@Componentstruct PageTransitionExample1 {  @State scale1: number = 1  @State opacity1: number = 1  build() {    Column() {      Navigator({ target: 'pages/page1', type: NavigationType.Push }) { Image($r('app.media.bg1')).width('100%').height('100%')    // 图片存放在media文件夹下      }    }.scale({ x: this.scale1 }).opacity(this.opacity1)  }  // 自定义方式1:完全自定义转场过程的效果  pageTransition() {    PageTransitionEnter({ duration: 1200, curve: Curve.Linear })      .onEnter((type: RouteType, progress: number) => { this.scale1 = 1 this.opacity1 = progress      }) // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0% -- 100%)    PageTransitionExit({ duration: 1500, curve: Curve.Ease })      .onExit((type: RouteType, progress: number) => { this.scale1 = 1 - progress this.opacity1 = 1      }) // 退场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0% -- 100%)  }}
// page1.ets@Entry@Componentstruct AExample {  @State scale2: number = 1  @State opacity2: number = 1  build() {    Column() {      Navigator({ target: 'pages/index', type: NavigationType.Push }) { Image($r('app.media.bg2')).width('100%').height('100%')   // 图片存放在media文件夹下      }    }.width('100%').height('100%').scale({ x: this.scale2 }).opacity(this.opacity2)  }  // 自定义方式1:完全自定义转场过程的效果  pageTransition() {    PageTransitionEnter({ duration: 1200, curve: Curve.Linear })      .onEnter((type: RouteType, progress: number) => { this.scale2 = 1 this.opacity2 = progress      }) // 进场过程中会逐帧触发onEnter回调,入参为动效的归一化进度(0% -- 100%)    PageTransitionExit({ duration: 1500, curve: Curve.Ease })      .onExit((type: RouteType, progress: number) => { this.scale2 = 1 - progress this.opacity2 = 1      }) // 退场过程中会逐帧触发onExit回调,入参为动效的归一化进度(0% -- 100%)  }}

在这里插入图片描述

组件内转场

​ 组件内转场主要通过transition属性配置转场参数,在组件插入和删除时显示过渡动效,主要用于容器组件中的子组件插入和删除时,提升用户体验(需要配合animateTo才能生效,动效时长、曲线、延时跟随animateTo中的配置)。

​ 官方实例:点击消失时,在预览器中无法看到生效效果,但其实已经生效了,需要在开发板或真机中才能看到

// xxx.ets@Entry@Componentstruct TransitionExample {  @State flag: boolean = true  @State show: string = 'show'  build() {    Column() {      Button(this.show).width(80).height(30).margin(30) .onClick(() => {   // 点击Button控制Image的显示和消失   animateTo({ duration: 1000 }, () => {     if (this.flag) {this.show = 'hide'     } else {this.show = 'show'     }     this.flag = !this.flag   }) })      if (this.flag) { // Image的显示和消失配置为不同的过渡效果 Image($r('app.media.testImg')).width(300).height(300)   .transition({ type: TransitionType.Insert, scale: { x: 0, y: 1.0 } })   .transition({ type: TransitionType.Delete, rotate: { angle: 180 } })      }    }.width('100%')  }}

共享元素转场

​ 设置页面间转场时共享元素的转场动效

官方实例:点击图片跳转页面时,显示共享元素图片的自定义转场动效。

// xxx.ets@Entry@Componentstruct SharedTransitionExample {  @State active: boolean = false  build() {    Column() {      Navigator({ target: 'pages/PageB', type: NavigationType.Push }) { Image($r('app.media.ic_health_heart')).width(50).height(50)   .sharedTransition('sharedImage', { duration: 800, curve: Curve.Linear, delay: 100 })      }.padding({ left: 20, top: 20 })      .onClick(() => { this.active = true      })    }  }}
// PageB.ets@Entry@Componentstruct pageBExample {  build() {    Stack() {      Image($r('app.media.ic_health_heart')).width(150).height(150) .sharedTransition('sharedImage', { duration: 800, curve: Curve.Linear, delay: 100 })    }.width('100%').height('100%')  }}

在这里插入图片描述

路径动画

​ 设置组件进行位移动画时的运动路径

toggle作为参数,当它改变的时候,组件的位置会发生改变从而触发了动画的执行,而motionPath可以将它的路径规划出来。

在这里插入图片描述

弹窗

警告弹窗

​ 显示警告弹窗组件,可设置文本内容与响应回调

​ 里面可以填写一些与用户交互的信息,并通过确认或取消按钮触发一个回调,从而完成一定的目的

列表选择弹窗

​ 里面有可滑动选择的信息,并通过确认或取消按钮触发一个回调,从而完成一定的目的

自定义弹窗

​ 通过CustomDialogController类显示自定义弹窗。使用弹窗组件时,可优先考虑自定义弹窗,便于自定义弹窗的样式与内容。

​ 这可以给开发者自定义更多弹窗样式,开发出弹窗更加多的功能

日期滑动选择器弹窗

根据指定的日期范围创建日期滑动选择器,展示在弹窗上。

时间滑动选择器弹窗

以24小时的时间区间创建时间滑动选择器,展示在弹窗上。

文本滑动选择器弹窗

根据指定的选择范围创建文本选择器,展示在弹窗上。

手势处理

绑定手势方法

​ 为组件绑定不同类型的手势事件,并设置事件的响应方法。

​ 绑定方式有三种,gesture绑定手势,priorityGesture绑定优先识别手势,parallelGesture绑定可与子组件手势同时触发的手势(手势事件为非冒泡事件,通过这个可以改成冒泡事件)。另外,可以通过更改GestureMask的参数来选择是否屏蔽掉子组件的手势。最后,onAction为响应手势事件,即为Tap手势识别成功回调。

​ 手势类型有七种

名称 描述
TapGesture 点击手势,支持单次点击、多次点击识别。
LongPressGesture 长按手势。
PanGesture 平移手势,滑动最小距离为5vp时识别成功。
PinchGesture 捏合手势。
RotationGesture 旋转手势。
SwipeGesture 滑动手势,滑动最小速度为100vp/s时识别成功。
GestureGroup 手势识别组,多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。

每种手势类型都有一个fingers参数用来限制可以几指触发,另外还有各种独有的参数,有directionspeedangledistancedirectionrepeatrepeat

组合手势

手势识别组合,即多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。

mode设置组合手势识别模式,有顺序识别、并发识别和互斥识别

s时识别成功。 |
| GestureGroup | 手势识别组,多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。 |

每种手势类型都有一个fingers参数用来限制可以几指触发,另外还有各种独有的参数,有directionspeedangledistancedirectionrepeatrepeat

组合手势

手势识别组合,即多种手势组合为复合手势,支持连续识别、并行识别和互斥识别。

mode设置组合手势识别模式,有顺序识别、并发识别和互斥识别