当前位置: 首页 > news >正文

HarmonyOS NEXT 关于鸿蒙的一多开发(一次开发,多端部署) 1+8+N

官方定义

定义:一套代码工程,一次开发上架,多端按需部署。

目标:支撑开发者快速高效的开发支持多种终端设备形态的应用,实现对不同设备兼容的同时,提供跨设备的流转、迁移和协同的分布式体验。

什么是1+8+N:1个系统HarmonyOS+8个常用终端(手机、平板、折叠屏、2in1、车机、手表等)+N个不同的物联网设备(智能家居等等)

为什么要做一多开发

        随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的潜在用户群体。但是如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。HarmonyOS系统面向多终端提供了“一次开发,多端部署”(后文中简称为“一多”)的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。

一多的主要问题

        一多开发虽然听上去那么便利,但也一定会带来一些技术问题,主要是三个问题:

为了解决这三个问题,分别从不同的方式进行解决

  1. 页面适配问题:界面级一多
  2. 功能兼容问题:功能级一多
  3. 工程如何组织:工程级一多

界面级一多

界面级一多主要解决的问题是:

  • 不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。

可以通过两中方式解决:

  • 自适应布局
  • 响应式布局

自适应布局是通过一些组件的自适应能力,来解决在小幅度的屏幕大小改变。如果屏幕变化跨度特别大,还是需要使用响应式布局。

自适应布局共有七种

针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。

自适应布局类别自适应布局能力使用场景实现方式
自适应拉伸拉伸能力容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域Flex布局的flexGrow和flexShrink属性
均分能力容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域Row组件、Column组件或Flex组件的justifyContent属性设置为FlexAlign.SpaceEvenly
自适应缩放占比能力子组件的宽或高按照预设的比例,随容器组件发生变化。

基于通用属性的两种实现方式:

- 将子组件的宽高设置为父组件宽高的百分比

- layoutWeight属性

缩放能力子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变布局约束的aspectRatio属性
自适应延伸延伸能力容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。

基于容器组件的两种实现方式:

- 通过List组件实现

- 通过Scroll组件配合Row组件或Column组件实现

隐藏能力容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏。相同显示优先级的子组件同时显示或隐藏布局约束的displayPriority属性
自适应折行折行能力容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,自动换行Flex组件的wrap属性设置为FlexWrap.Wrap

响应式布局 

        自适应布局可以保证窗口尺寸在【一定范围内变化】时,页面的显示是正常的。但是将窗口尺寸【变化较大】时(如窗口宽度从400vp变化为1000vp),仅仅依靠自适应布局可能出现图片异常放大或页面内容稀疏、留白过多等问题,此时就需要借助响应式布局能力调整页面结构。

        响应式布局是指页面内的元素可以根据特定的特征(如窗口宽度、屏幕方向等)自动变化以适应外部容器变化的布局能力。

        响应式布局中最常使用的特征是窗口宽度,可以将窗口宽度划分为不同的范围(下文中称为断点)。当窗口宽度从一个断点变化到另一个断点时,改变页面布局(如将页面内容从单列排布调整为双列排布甚至三列排布等)以获得更好的显示效果。

三种响应式布局能力:

响应式布局能力

简介

断点

将窗口宽度划分为不同的范围(即断点),监听窗口尺寸变化,当断点改变时同步调整页面布局。

媒体查询

媒体查询支持监听窗口宽度、横竖屏、深浅色、设备类型等多种媒体特征,当媒体特征发生改变时同步调整页面布局。

栅格布局

栅格组件将其所在的区域划分为有规律的多列,通过调整不同断点下的栅格组件的参数以及其子组件占据的列数等,实现不同的布局效果。

断点

不同的断点取值范围

断点名称

取值范围(vp

设备

xs

[0, 320)

手表等超小屏

sm

[320, 600)

手机竖屏

md

[600, 840)

手机横屏,折叠屏

lg

[840, +∞)

平板,2in1 设备

系统提供了多种方法,判断应用当前处于何种断点,进而可以调整应用的布局。常见的监听断点变化的方法如下所示:

  • 获取窗口对象并监听窗口尺寸变化(了解)
  • 通过媒体查询监听应用窗口尺寸变化(掌握
  • 借助栅格组件能力监听不同断点的变化(掌握
  • 通过窗口对象,监听窗口尺寸变化(了解)

媒体查询

这里官网对通过媒体查询监听断点的功能做简单的封装,点击跳转。

这里做了更简化的版本

import { mediaquery } from '@kit.ArkUI'

interface Breakpoint {
  name: string
  size: number
  mediaQueryListener?: mediaquery.MediaQueryListener
}

export const BreakpointKey: string = 'currentBreakpoint'

export class BreakpointSystem {
  private currentBreakpoint: string = 'md'
  private breakpoints: Breakpoint[] = [
    { name: 'xs', size: 0 }, { name: 'sm', size: 320 },
    { name: 'md', size: 600 }, { name: 'lg', size: 840 }
  ]

  public register() {
    this.breakpoints.forEach((breakpoint: Breakpoint, index) => {
      let condition: string
      if (index === this.breakpoints.length - 1) {
        condition = '(' + breakpoint.size + 'vp<=width' + ')'
      } else {
        condition = '(' + breakpoint.size + 'vp<=width<' + this.breakpoints[index + 1].size + 'vp)'
      }
      console.log(condition)
      breakpoint.mediaQueryListener = mediaquery.matchMediaSync(condition)
      breakpoint.mediaQueryListener.on('change', (mediaQueryResult) => {
        if (mediaQueryResult.matches) {
          this.updateCurrentBreakpoint(breakpoint.name)
        }
      })
    })
  }

  public unregister() {
    this.breakpoints.forEach((breakpoint: Breakpoint) => {
      if (breakpoint.mediaQueryListener) {
        breakpoint.mediaQueryListener.off('change')
      }
    })
  }

  private updateCurrentBreakpoint(breakpoint: string) {
    if (this.currentBreakpoint !== breakpoint) {
      this.currentBreakpoint = breakpoint
      AppStorage.set<string>(BreakpointKey, this.currentBreakpoint)
      console.log('on current breakpoint: ' + this.currentBreakpoint)
    }
  }
}

/*
 定义一个接口类型
 键: 断点值
 值: 泛型
*/
declare interface BreakPointTypeOption<T> {
  xs?: T
  sm?: T
  md?: T
  lg?: T
  xl?: T
  xxl?: T
}

/*
 对外导出一个类
 在实例化的时候接收一个泛型
*/
export class BreakPointType<T> {
  // 选项对象
  options: BreakPointTypeOption<T>

  constructor(option: BreakPointTypeOption<T>) {
    this.options = option
  }

  getValue(currentBreakPoint: string) {
    if (currentBreakPoint === 'xs') {
      return this.options.xs
    } else if (currentBreakPoint === 'sm') {
      return this.options.sm
    } else if (currentBreakPoint === 'md') {
      return this.options.md
    } else if (currentBreakPoint === 'lg') {
      return this.options.lg
    } else if (currentBreakPoint === 'xl') {
      return this.options.xl
    } else if (currentBreakPoint === 'xxl') {
      return this.options.xxl
    } else {
      return undefined
    }
  }
}

栅格布局

栅格是多设备场景下通用的辅助定位工具,通过将空间分割为有规律的栅格。栅格可以显著降低适配不同屏幕尺寸的设计及开发成本,使得整体设计和开发流程更有秩序和节奏感,同时也保证多设备上应用显示的协调性和一致性,提升用户体验。

  1. GridRow breakpoints属性 和 的 onBreakpointChange 事件
  2. GridRow 的 gutter属性、GridCol 的 offset 属性
  3. GridRow的 columns 属性、GridCol 的 span 属性

功能级一多

主要是应用如何解决设备系统能力差异的兼容问题。暂时用的比较少。

基本利用canIUse去查询设备是否具有某个能力如:拍照,定位,蓝牙等。

工程级一多

这部分对程序员来说非常重要,一个一多项目,要想更高效,更利于团队配合,就要好好思考,如果做项目结构分层。

一多模式下,官方推荐在开发过程中采用"三层工程架构",其实就是把项目拆分成不同类型的模块,再通过模块之间的引用组合,最终实现应用功能,拆分规范如下:

  • commons(公共能力层):用于存放公共基础能力合集,比如工具库,公共配置等
  • features(基础特性层):用于存放应用中相对独立的各个功能的UI以及业务逻辑实现
  • products(产品定制层):用于针对不同设备形态进行功能和特性集成,作为应用入口

根据一个更具体的 手机-折叠屏-平板 三终端项目的话,应该如下设计

products:只是一个入口,应该不负责具体的业务,可以写业务

features:写具体业务,把每个业务拆分成具体的模块 N个,方便维护

commons: 提供基础组件-基础工具-基础类型- 架构组-技术平台组

那么不同的工程架构要用到什么包呢?

首先先了解都有哪几种包

包的分类

  • hap- 可以有ability,可以有页面,可以有组件,可以有资源,不同平台的主包(手机包、平板包、手表包)
  • hsp-动态共享包。运行时复用- 可以实现按需打包,最常用分包(用户模块包、购物车模块包、收获地址包,各种页面包)
  • har- 静态共享包。编译态复用,常见于三方仓库包(请求库包、各种工具包)

还有一些注意点,har包是在引用的时候重复拷贝,如果项目中不是发布到三方库或二方库的话,可以使用hsp包,他在引用的时候赋值地址,不会重复拷贝。

相关文章:

  • 前端技术(28) : 拖拽、粘贴和点击浏览文件上传
  • iOS rootless无根越狱检测方案
  • Python中的JSON转换:全面指南与最佳实践
  • ESLint报错:Could not find config file.
  • Git合并删除原理
  • Centos与Ubuntu系统的对比分析
  • C++进制转换的方法
  • LinuxI/O多路转接(select、poll、epoll)
  • 23种设计模式-模板方法(Template Method)设计模式
  • 基于无线的分布式温度采集报警系统设计(论文+源码)
  • SpringCould微服务架构之Docker(3)
  • QML学习 —— 17、“DelayButton 延迟按钮“之“一键三连“示例(附完整源码)
  • vue2项目eslint提示<template v-for> key should be placed on the <template> tag
  • vue 3 深度指南:从基础到全栈开发实践
  • Git 基础入门:从概念到实践的版本控制指南
  • 【PostgreSQL内核学习 —— (sort算子)】
  • 练习:求质数
  • Nacos Config Service 和 Naming Service 各自的核心功能是什么?
  • SpringCloud微服务框架搭建详解(基于Nacos)
  • Scala
  • 上海市网站建设公司/网络营销管理
  • 销售网站开发步骤/深圳搜索排名优化
  • 市场营销成功案例分析/珠海网站seo
  • wordpress主题博客主题/seo关键词优化公司
  • 网站做担保交易/站长之家工具查询
  • 做网站开发的想接私活/在线培训管理系统