鸿蒙OS中有趣且有特色的一个功能 ———— 一多开发(媒体查询)

141 阅读6分钟
前些天参加了个鸿蒙的线下HDD大会,那几位鸿蒙的大佬讲的都很牛*,有一个挺吸引我的点:全场景体验////
我靠这不就是未来科技吗?我勒个大鸿蒙啊,什么是全场景呢,我来给你们介绍一下:

依靠分布式技术还有一次开发就能在多个终端进行部署的想法,打造出了一种全新的体验,形成了一个统一的系统、生态,实现了各个设备原生的互相连接。分布式软总线技术有了全面的改进,让设备之间原生的互相连接和一起工作的能力变得更强了,连接速度变快,消耗的电量还变少了。鸿蒙原生的应用有着天生就能在多个终端使用的特点,这样就减少了开发者做额外适配工作的负担。用户在使用有集成接续能力的鸿蒙原生应用时,可以在不同的设备之间毫无阻碍地切换使用,像移动会议、导航切换、在不同设备上一起创作这些场景都变得更加方便和高效了,而且还支持在不同设备之间复制粘贴、在手机上抠图、图库相互连通等功能。

后面又涉及到一个词:一多开发

“一多开发”通常指的是“一次开发,多端部署”。它是一种软件开发理念和方法,旨在让开发者能够通过一套代码工程,一次开发完成后,将应用高效地部署到多种不同的终端设备上。

以鸿蒙 OS 开发的“一次开发,多端部署”为例,其具有以下特点:

  • 定义和目标:一套代码工程,一次开发上架,多端按需部署。目标是支撑开发者快速高效地开发支持多种终端设备形态的应用,实现对不同设备的兼容,同时提供跨设备的流转、迁移和协同的分布式体验。

  • 解决的基础问题:需要解决不同设备间屏幕尺寸、色彩风格等差异导致的页面适配问题,以及不同设备系统能力差异带来的功能兼容问题。

  • 基础知识

    • 方舟开发框架:提供了两种开发范式,即基于 js 扩展的类 web 开发范式和基于 arkts 的声明式开发范式。声明式开发范式更适用于复杂度较大、团队合作度较高的程序开发;类 web 开发范式则更接近 web 前端开发者的使用习惯,主要适用于界面较为简单的中小型应用开发。声明式开发范式占用内存更少,更推荐使用。
    • 应用程序包结构:应用通常包含一个或多个 module,module 分为“ability”和“library”两种类型。“ability”类型的 module 编译后生成 hap 包,“library”类型的 module 编译后生成 har 包或 hsp 包。应用以 apppack 形式发布,包含一个或多个 hap 包,hap 包可分为 entry 和 feature 两种类型。entry 类型的 hap 是应用的主模块,同一设备类型只支持一个;feature 类型的 hap 用于实现应用的特性功能,可包含一个或多个,也可不包含。
  • 部署模型:有两种部署模型。部署模型 a 是在不同类型设备上通过一次编译生成相同的 hap(或 hap 组合);部署模型 b 则是生成不同的 hap(或 hap 组合)。对于相同泛类的设备,优先选择部署模型 a;对于不同泛类设备,优先选择部署模型 b。实际开发中,如果目标设备类型较多,往往是两种部署模型混合使用。

  • 工程结构:推荐使用“三层工程结构”,包括 common(公共能力层)、features(基础特性层)和 products(产品定制层)。common 层存放公共基础能力集合,可编译成一个或多个 har 包或 hsp 包,只可被 products 和 features 依赖。features 层存放基础特性集合,各个 feature 高内聚、低耦合、可定制,不需要单独部署的 feature 可编译为 har 包或 hsp 包,供 products 或其他 feature 使用;需要单独部署的 feature 通常编译为 feature 类型的 hap 包,和 products 下 entry 类型的 hap 包进行组合部署。products 层用于针对不同设备形态进行功能和特性集成,各个子目录各自编译为一个 entry 类型的 hap 包,作为应用主入口,且不可以横向调用。

在鸿蒙 OS 中,通过采用三层架构分层设计、多端设计 UI 自适应、交互事件归一以及一次上架按需部署等方式,可以实现“一次开发,多端部署”,提升开发效率,兼顾多设备的整体用户体验。

用通俗易懂的话来说呢,就是可以在移动端,无缝切换到智能家居,或者车载中。比如你手机正在导航想去一个地方,你要开车去,你走到车的旁边,会自动把手机的导航转移到车载屏幕上去。

这么牛*的东西怎么搞呢?现在我还没搞明白。。。“你自己没搞明白你来装什么b?”呃,虽然没有全搞明白不过我先给大家分享一下 一多开发中的媒体查询吧:

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

ok接下来上代码,需要的哥哥姐姐们可以直接cv

//我这里是做了一个封装,开发者们可以通过预览器来观察不同机型下的内容情况

//首先导入模块
import mediaquery from '@ohos.mediaquery'

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
    }
  }
}

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)
    }
  }
}

怎么用呢?

//自己重新建个页面吧以上内容先导入进来
import { xxxxxxxxxx } from 'xxxxxxxxxxxxx'

@Entry
@Component
  struct MediaQuerySample {
  @StorageLink('currentBreakpoint') private currentBreakpoint: string = "md";
  private breakpointSystem: BreakpointSystem = new BreakpointSystem()


aboutToAppear() {
//通过 aboutToAppear 调用前面页面的数据
// 注册媒体查询工具
  this.breakpointSystem.register()
}

aboutToDisappear(): void {
//同上
// 取消媒体查询工具,释放资源
    this.breakpointSystem.unregister()
  }
  build{
Column(){} 
}

ok 结束 预览器效果我就不发啦,大家可以发挥想象,宽、高、背景颜色、圆角尺寸、间距都可以改的!

好啦,下次见~

虽然一天什么也没干,不过辛苦我自己啦!