HarmonyOS 鸿蒙Next一多开发

HarmonyOS 鸿蒙Next一多开发 媒体查询:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-layout-development-media-query

响应式布局:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/responsive-layout

一多开发主要包含两个层面

一次开发,多个设备终端都能适配运行。不同设备屏幕能看到不同布局方案

一次开发,根据不同终端设备打包为不同hap,在每一种终端设备中就能下载对应的安装包

同一套代码,我们可以根据屏幕带下不一致,实现不同页面布局

一多开发需要用到的技术:

1、媒体查询:根据不同的屏幕尺寸用户自己来决定如何布局

2、栅格系统:栅格系统相当于封装好组件,可以实现在页面布局中,根据屏幕大小决定元素排列规则

媒体查询

响应式布局,可以检测当前设备的大小,根据设备大小来决定如何进行元素排列。比如手机端占100%,在屏幕宽度啊 500vp的时候。动态控制元素占50%

使用媒体查询检测屏幕显示方式:

这个的demo只是媒体查询的一个条件。只判断了横屏还是竖屏,真正要实现页面上元素的检测,尺寸的检测,可以添加更多的条件

封装媒体查询工具

可以根据屏幕大小来自动识别我们的设备类型

设备尺寸当前我们主要分为:

断点名称 取值范围(vp)
xs [0, 320)
sm [320, 600)
md [600, 840)
lg [840, +∞)

封装工具按照上面的断点来实现页面变化,检测设备的类型

媒体查询常量

开发媒体查询的时候,会用到很多数字或者一些值

有必要将代码中常用的参数封装到常量文件中,这里我创建一个BasicConstants和BreakPointConstants ,放在hsp模块中

export class BasicConstants{
  static readonly FULL_WIDTH='100%'
  static readonly FULL_HEIGHT='100%'
  static readonly FULL_SIZE_SMALL='14vp'
  static readonly FULL_SIZE_NORMAL='16vp'
  static readonly FULL_SIZE_BIG='20vp'
  static readonly FULL_SIZA_LARGE='30vp'
}
export class BreakPointConstants {
  static readonly BREAKPOINT_SM: string = 'sm'
  // 折叠屏可以用md来表示
  static readonly BREAKPOINT_MD: string = 'md'
  //pad可以用lg来表示
  static readonly BREAKPOINT_LG: string = 'lg'
  //断点的数组
  static readonly BREAKPOINT_VALUE: Array<string> = ['320vp', '600vp', '840vp']
  // 在水平方向占4份
  static readonly COLUMN_SM: number = 4
  static readonly COLUMN_MD: number = 8
  static readonly COLUMN_LG: number = 12
  static readonly GUTTER_X: number = 12
  static readonly SPAN_SM: number = 4
  static readonly SPAN_MD: number = 6
  static readonly SPAN_LG: number = 8
  static readonly OFFSET_MD: number = 1
  static readonly OFFSET_LG: number = 2
  static readonly CURRENT_BREAKPOINT: string = 'currentBreakpoint'
  static readonly FONT_SIZE_SM: number = 14
  static readonly FONT_SIZE_MD: number = 16
  static readonly FONT_SIZE_LG: number = 18
  static readonly COVER_MARGIN_SM: number = 10
  static readonly COVER_MARGIN_MD: number = 30
  static readonly COVER_MARGIN_LG: number = 40
  static readonly RANGE_SM: string = '(320vp<=width<=600vp)'
  static readonly RANGE_MD: string = '(600vp<=width<=840vp)'
  static readonly RANGE_LG: string = '(840vp<=width)'
}

创建一个媒体查询公共代码

import { BreakPointConstants } from '../constants/BreakPointContants'
import { mediaquery } from '@kit.ArkUI'

export class BreakPointSystem{
  // 媒体查询,得到单位要将这个sm  md保存到全局,currentBreakPoint作为key
  private currentBreakpoint:string=BreakPointConstants.BREAKPOINT_SM
 // (1)屏幕大小条件查询
  private smListener=mediaquery.matchMediaSync(BreakPointConstants.RANGE_SM)
  private mdListener=mediaquery.matchMediaSync(BreakPointConstants.RANGE_MD)
  private lgListener=mediaquery.matchMediaSync(BreakPointConstants.RANGE_LG)

  // 定义一个公共函数,目的保存当前屏幕的检测结果
  // sm md lg 应用状态
  private updateCurrentBreakPoint(breakPoint:string){
    if(this.currentBreakpoint!==breakPoint){
      this.currentBreakpoint=breakPoint
      // 将应用存储
      AppStorage.setOrCreate<string>(BreakPointConstants.CURRENT_BREAKPOINT,this.currentBreakpoint)
    }
  }

  //(2)给监听器绑定change事件
  private isBreakPointSM=(mediaQueryResult:mediaquery.MediaQueryResult)=>{
    if(mediaQueryResult.matches){
      // 将sm的单位保存起来
      this.updateCurrentBreakPoint(BreakPointConstants.BREAKPOINT_SM)
    }
  }

  private isBreakPointMD=(mediaQueryResult:mediaquery.MediaQueryResult)=>{
    if(mediaQueryResult.matches){
      // 将MD的单位保存起来
      this.updateCurrentBreakPoint(BreakPointConstants.BREAKPOINT_MD)
    }
  }

  private isBreakPointLG=(mediaQueryResult:mediaquery.MediaQueryResult)=>{
    if(mediaQueryResult.matches){
      // 将LG的单位保存起来
      this.updateCurrentBreakPoint(BreakPointConstants.BREAKPOINT_LG)
    }
  }
  // 这个函数外面要调用
  public register(){
    this.smListener=mediaquery.matchMediaSync(BreakPointConstants.RANGE_SM)
    this.smListener.on('change',this.isBreakPointSM)
    this.mdListener=mediaquery.matchMediaSync(BreakPointConstants.RANGE_MD)
    this.mdListener.on('change',this.isBreakPointMD)
    this.lgListener=mediaquery.matchMediaSync(BreakPointConstants.RANGE_LG)
    this.lgListener.on('change',this.isBreakPointLG)
  }
  // 解除事件的绑定,为了优化代码
  public unregister(){
    this.smListener.off('change',this.isBreakPointSM)
    this.mdListener.off('change',this.isBreakPointMD)
    this.lgListener.off('change',this.isBreakPointLG)
  }
}

页面中使用

import { BreakPointSystem } from "common"

@Entry
@Component
struct MainIndex {
  private breakPointSystem = new BreakPointSystem()
  @StorageProp('currenBreakPoint') currenBreakPoint: string = 'sm'

  aboutToAppear(): void {
    // 进入页面想要注册监听器
    this.breakPointSystem.register()
  }

  aboutToDisappear(): void {
    this.breakPointSystem.unregister()
  }

  build(){
    Column() {
      Text(`当前的屏幕大小为${this.currenBreakPoint}`)
        .fontSize(30)
    }
    .height('100%')
    .width('100%')
  }
}

Grid网格布局

网格适用于页面上规则的行列元素排列

主要涉及:日历的布局、计算器、商品等

核心知识点

@Builder grid(){
  Grid(){
    ForEach(this.activityTitle,(item:string,index:number)=>{
      GridItem(){
        Text(`${item}`)
        .fontColor(Color.White)
      }
      .backgroundColor(Color.Blue)
    },(item:string)=>item)
  }
  // 想让元素滚动只需要设置rowsTemplate或者columnsTemplate某一个属性,另外一遍就可以实现
  .rowsTemplate('1fr 1fr')
  .columnsTemplate('1fr 3fr 1fr')
  .rowGap(10)
  .columnsGap(10)
  .width('100%')
  .height(180)
  .border({
    width:1,
    color:Color.Red
  })
}

Grid:代表网格容器。里面必须存放的是GridItem元素。

GridItem:无需涉及宽和高。在Grid容器一旦设置行列过后。默认撑满这个容器

rowsTemplate:代表列元素设置的单位。fr也是代表占的大小

columnTemplate:代表列元素设置的单位。fr也是代表占的大小

rowsGap:设置行与行之间的间隙

columnsGap:设置列与列之间的间隙

layoutDirection:可以控制元素排列过程中的显示方向。row和column

网格数据合并

@Entry
@Component
struct GridExample{
  @State numbers:String[]=['0','1','2','4','5','6','7','8','9']
  layoutOptions:GridLayoutOptions={
    // 主要控制页面中GridItem  比例1:1
    regularSize:[1,1],
    //[0,0,1,1]---->[rowStart,columnStart,rowSpan,columnSpan]] 其中rowStart为行起始位置,columnStart为列起始位置,无单位。rowSpan为GridItem占用的行数,columnSpan为GridItem占用的列数,无单位。
    onGetRectByIndex:(index:number)=>{
      if(index==0){
        return [0,0,1,2]
      }else if(index==1){
        return [0,1,2,1]
      }else{
        return [0,0,1,1]
      }
    }
  }

  build(){
    Column({space:5}){
      Grid(null,this.layoutOptions){
        ForEach(this.numbers,(item:string)=>{
          GridItem(){
            Text(item)
            .fontSize(16)
            .backgroundColor(0xF9CF93)
            .textAlign(TextAlign.Center)
          }.backgroundColor(Color.Pink)
        },(item:string)=>item)
      }
      .columnsTemplate('1fr 1fr 1fr')
      .rowsTemplate('1fr 1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .width('90%')
      .backgroundColor(0xFAEEE0)
      .height(400)
    }.width('100%').marin({top:5})
  }
}

栅格系统

栅格系统是目前提供一种响应式布局方案

基础代码

@Entry
@Component
struct Index{
  @State bgColors:Color[]=[Color.Red,Color.Oriange,Color.Yellow,Color.Green,Color.Pink,Color.Gray,Color.Blue,Color.Brown,Color.Pink,Color.Gray,Color.Blue,Color.Brown]

  build(){
    GridRow(){
      FoeEach(this.bgColor,(item:Color)=>{
         GridCol(){
           Text(`${index}`)
            .backgroundColor(item)
            .width(40)
            .lineHeight(50)
         }
      },(item:color)=>item)
    }
  }
}

GridRow 代表一行,里面必须存放GridCol

默认一行可以最多显示12个元素,代表12列栅格布局

栅格布局是一种涉及流程,很多框架都会采用。每一家框架设计区别:比如antd 24列

自定义设置一行最多显示多少列。Columns属性来控制

GridROw({columns:3}){}

可以指定根据不同的屏幕尺寸设计不同的元素排列个数,代表sm单位的屏幕,一行最多显示4个,md单位的屏幕一行最多显示8个

GridRow({columns:{sm:4,md:8}}){}

自定义断点

GridRow({columns:{sm:4,md:8},
    breakpoints:{value:['200vp','300vp','400vp','500vp','600vp']}
}){}

breakpoints:可以允许用户根据屏幕来自定义断点值。

默认情况下:官方提供4个断点,最多可以支持6个断点。xl和xxl是允许扩展的

断点名称 取值范围(vp)
xs [0, 320)
sm [320, 600)
md [600, 840)
lg [840, +∞)

direction:可以设置容器里面子元素排列顺序,主要是Row和RowReverse

GridRow({columns:{sm:4,md:8},
    breakpoints:{value:['200vp','300vp','400vp','500vp','600vp']},
    direction:GridRowDirection.RowReverse
}){}

gutter:设置子元素在水平方向排列过程中,默认间距

GridRow({columns:{sm:4,md:8},
    breakpoints:{value:['200vp','300vp','400vp','500vp','600vp']},
    gutter:10
}){}

GridCol参数

span参数可以设置指定每一份占几个单元格

GridCol({span:{sm:2,md:3}})
{
    Text(`${index}`)
    .backGroundColor(item)
    .height(50)
    .width('100%'))
}

可以通过属性来控制当前盒子偏移份数。相当于margin-left这个属性

GridCol({
    span:{sm:2,md:3}},
    offset:1
){}

更多关于HarmonyOS 鸿蒙Next一多开发的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next一多开发的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next是华为推出的新一代操作系统,支持“一多开发”理念,即一次开发,多端部署。开发者可以使用统一的开发框架和工具,编写一次代码,即可在手机、平板、智能手表、智能家居等多种设备上运行。这大大提高了开发效率,降低了维护成本。HarmonyOS Next还提供了丰富的API和开发工具,支持多种编程语言,如Java、JS、C/C++等,帮助开发者快速构建跨设备的应用。

回到顶部