HarmonyOS一次开发多端部署三巨头之界面级一多开发

界面级一多开发

  • 引言
    • 1. 布局能力
      • 1.1 自适应布局
        • 1.1.1 拉伸能力
        • 1.1.2 均分能力
        • 1.1.3 占比能力
        • 1.1.4 缩放能力
        • 1.1.5延伸能力
        • 1.1.6 隐藏能力
        • 1.1.7 折行能力
      • 1.2 响应式布局
        • 1.2.1 断点和媒体查询
        • 1.2.2 栅格布局
    • 2. 视觉风格
      • 2.1 分层参数
      • 2.2 自定义资源
    • 3. 交互归一
    • 4. IDE多设备预览

引言

一次开发多端部署
定义:一套代码工程,一次开发上架,多端按需部署
目标:支撑开发者快速高效的开发多终端设备上的应用
为了实现一多开发的定义与目标,我们需要解决三个问题

  1. 页面如何适配:不同设备间的屏幕尺寸,色彩风格等存在差异。
  2. 功能如何兼容:不同设备的系统能力有差异,如智能穿戴设备,是否具有定位能力、智慧屏是否具有摄像头等。
  3. 工程如何组织:如何实现同一套代码,同时能部署到多种不同的设备上。

今天为大家带来的是界面级一多开发的具体实现。

1. 布局能力

  1. 自适应布局(Adaptive Layout):元素可以根据相对关系自动变化以适应外部容器变化的布局能力。当前开发框架提炼了其七种自适应布局能力,这些布局也可以独立使用,也可多种布局叠加使用。
  2. 响应式布局(ResponsiveLayout):元素可以根据特定的特征(如窗口宽度、屏幕方向等)触发变化以适应外部容器变化的布局能力,响应式布局依据断点、媒体查询、栅格等能力实现

1.1 自适应布局

1.1.1 拉伸能力

拉伸能力是指容器组件尺寸发生变化时,增加或减少的空间全部分配给容器组件内指定区域。本例中,页面有中间的内容区以及两侧留白区组成

Row() {
//通过flexGrow和flexShrink属性,将多余的的空间全部分配给图片,将不足的控件全部分配给两侧空白区域
    Row().width(150)
    .flexGrow(0).flexShrink(1)
    Image($r("app.media.image")).width(400)
    .flexGrow(1).flexShrink(0)
    Row().width(150)
    .flexGrow(0).flexShrink(1)
}
1.1.2 均分能力

均分能力是指容器组件发生变化时,增加或减少的空间均匀分配给容器组件内所有空白区域。本例中,父容器尺寸变化过程中,图标及文字的尺寸不变,图标间的间距及图标离左右边缘的的距离同时均等改变。

Column() {
    Row() {
        Foreach(this.list,(item: number) => {..})
    }.width('100%')
    //均匀分配父容器主轴方向的剩余空间
    .justifyContent(FlexAlign.spaceEvenly)
    //同上Row
    Row() {..}
}.width(this.rate * 100 + '%')
1.1.3 占比能力

占比能力是指子组件的宽高按照预设比例,随父容器发生变化。本例中,简单的播放器控制栏,其中“上一首”、“播放/暂停”、“下一首”的layoutWeight属性都设置为1,因此他们按照比例“1:1:1”的比例均分父容器主轴方向上的空间。

Row() {
    Column() {..}
    .layoutWeight(1)//设置子组件在父容器主轴上的布局权重
    Column() {..}
    .layoutWeight(1)//设置子组件在父容器主轴上的布局权重
    Column() {..}
    .layoutWeight(1)//设置子组件在父容器主轴上的布局权重
}
.width(this.rate * 100 + "%")
1.1.4 缩放能力

缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。例如本例中,Column组件随其Flex父组件尺寸变化而缩放的过程中,始终保持预设的宽高比,其中的图片也始终显示正常

Column() {
    Column() {
        Image($r('app.media.image'))
        .width('100%').height('100%')
    }
    .aspectRatio(1)//固定高宽比
}
.height(this.sliderHeight)
.width(this.sliderWidth)
1.1.5延伸能力

延伸能力是指容器组件内的子组件,按照其在列表的先后顺序,随容器组件变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。本例中,当父容器尺寸发生变化时,页面中显示的图标数量随之发生改变。

Row({ space: 10 }) {
    //通过List组件实现隐藏能力
    List( {space:10 }){...}
    .listDirection(Axis.Horizontal)
    .width('100%')
}
.width(this.rate * 100 + '%')
1.1.6 隐藏能力

隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。本例中,下面五个按键设置了不同的优先级,父组件宽度变化后,优先显示高优先级的元素。

Row() {
    Image($r('app.media.favorite'))
    .displayPriority(1)//布局优先级
    Image($r('app.media.down'))
    .displayPriority(2)//布局优先级
    Image($r('app.media.pause'))
    .displayPriority(3)//布局优先级
    Image($r('app.media.next'))
    .displayPriority(2)//布局优先级
    Image($r('app.media.list'))
    .displayPriority(1)//布局优先级
}
.width(this.rate * 100 + '%')
1.1.7 折行能力

折行能力是指容器组件发生尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。本例中,当父容器尺寸发生变化时,其中的内容做自适应换行。

在这里插入图片描述

Column() {
//通过Flex组件warp参数实现自适应执行
    Flex({
        warp: FlexWarp,
        direction: FlexDirection.Row
    }) {
        ForEach(this.imageList), (item: Resource) => {
            Image(item).width(183).height(138)
            })
    }
    .width(this.rate * 100 + '%')
}

1.2 响应式布局

1.2.1 断点和媒体查询

断点:将窗口宽度划分为不同的范围(即断点),监听窗口尺寸变化,当断点改变时同步调整页面布局。
注意:断点支持自定义,取值范围可修改,下表是常用的四个断点范围

在这里插入图片描述

媒体查询:媒体查询提供丰富的媒体特征监听能力,可以监听应用显示应用区域变化、横竖屏、深浅色、设备类型等

import { mediaquery } from "@kit.ArkUI";

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 enum BreakpointTypeEnum {
  SM = 'sm',
  MD = 'md',
  LG = 'lg',
  XL = 'xl'
}

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

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

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

以上是媒体查询和断点结合的工具类,目的是为了记录屏幕尺寸的变化,而我们需要使用这个工具类时,可以进行如下操作

//先引入工具类
import { BreakpointSystem } from '@ohos/utils';

struct Index {
..
//给BreakpointSystem实例化
@StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD;
..
//在页面的生命周期中注册监听和取消监听
aboutToAppear() {
  this.breakpointSystem.register();
}

aboutToDisappear() {
  this.breakpointSystem.unregister();
}
build() {
1.2.2 栅格布局

根据设备的水平宽度,将不同的屏幕尺寸划分为不同数量的栅格,来实现屏幕的自适应。且栅格和栅格之间可以设置一个间距,本例中为12vp

在这里插入图片描述

  • 可以调节布局占栅格的数量(设置参数cpan)、偏移量(设置参数offset),来实现栅格的适配。
  • 可以修改断点的取值范围,支持启用最多六个断点(设置breakpoints和value参数)。

@Entry
@Component
struct LoginPage {
    aStorageProp('currentDeviceSize')currentDeviceSize: string = CommonConstants.SM;
    build(){
        GridRow({
            columns:{sm:4,md:8,lg:12 },
            gutter:{x:'12vp'}) {
            Gridcol({
                span:sm:4,md:6,lg:8
                offset:{sm:0,md:1,lg:2} {
                Column(){
                    // Title component
                    LoginTitle()
                    //Bottom component
                    LoginBottom()
                }
            }
        }
        .backgroundColor($r(#F1F3F5))
    }
    onPageShow(){
        MultipleDevicesutils.register();
    }
}

总结

  • 通过设置GridCol的span属性分配组件所占栅格列数
  • 通过设置GridCol的offset、GridRow的gutter等属性改变间距实现最佳效果

2. 视觉风格

2.1 分层参数

为了保证各组件有相同风格的默认样式,或者为了保证HarmonyOS系统应用有统一的风格。UX定义了一套系统资源,预置在系统中,开发者可以直接使用

在这里插入图片描述

使用了分层参数后,系统选择了深色模式,字体和背景也能自适应

@Entry
@Component
struck Index {
    build() {
        Row() {
            Column() {
                Text('分层参数')
                .fontColor($r('sys.color.ohos_id_color_primary'))
                .fontSize($r('sys.float.ohos_id_text_size_headline3'))
            }
        }
        .backgroundColor($r('sys.color.ohos_id_color_background'))
    }
}

在这里插入图片描述

2.2 自定义资源

开发者可以在resources目录中通过限定词目录来定义不同设备状态的资源,资源可以按照“key-value”的形式自定义。应用在运行态选择使用某资源时,系统会根据设备状态优先从相匹配的目录中寻找资源。

3. 交互归一

对于不同类型的智能设备,用户可能有不同的交互方式,如通过触摸屏、鼠标、触控板等。针对不同来自不同输入设备的相同输入,通过交互归一提供给开发者统一的API。交互归一后开发者无需关注当前设备和输入设备类型,只需在交互归一事件接口中做逻辑响应即可。

以缩放交互为例,通过多指触控的张合来完成缩放动作,在多设备场景下,缩放交互会出现多种不同的操作输入方式,如表所示。在开发接口上,这些缩放操作都统一为PinchGesture的API事件。

Image()
.scale({ x: this.scaleValue, y: this.scaleValue, z: 1 })
.gesture(
    //双指捏合触发该手势事件
    PinchGesture({ fingers: 2 })
    .onActionStart((event?: GestureEvent)=>{})
    .onActionUpdate((event?: GestureEvent)=>{
        this.scaleValue = this.pinchValue * event.scale
    })
    .onActionEnd(()=>{
        this.pinchValue = this.scaleValue
    })
)

4. IDE多设备预览

IDE预览器支持多设备预览,在平常代码的书写中可以提供开发者更好的预览体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/908090.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(58)LMS自适应滤波算法与系统辨识的MATLAB仿真

文章目录 前言一、LMS算法的基本步骤二、LMS算法的一些主要应用1. 通信系统2. 信号分离与增强3. 控制系统4. 生物医学信号处理5. 机器学习与模式识别6. 其他应用 三、LMS算法用于系统辨识的MATLAB仿真四、仿真结果 前言 LMS&#xff08;Least Mean Squares&#xff0c;最小均方…

bootstrap应用1——计算n从1-100000的每个整数,第j个观测在自助法样本里的概率。

计算n从1-100000的每个整数&#xff0c;第j个观测在自助法样本里的概率。 pr function(n) return(1 - (1 - 1/n)^n) x 1:10000 plot(x, pr(x))

AI-基本概念-向量、矩阵、张量

1 需求 需求&#xff1a;Tensor、NumPy 区别 需求&#xff1a;向量、矩阵、张量 区别 2 接口 3 示例 4 参考资料 【PyTorch】PyTorch基础知识——张量_pytorch张量-CSDN博客

【设计模式】策略模式定义及其实现代码示例

文章目录 一、策略模式1.1 策略模式的定义1.2 策略模式的参与者1.3 策略模式的优点1.4 策略模式的缺点1.5 策略模式的使用场景 二、策略模式简单实现2.1 案例描述2.2 实现代码 三、策略模式的代码优化3.1 优化思路3.2 抽象策略接口3.3 上下文3.4 具体策略实现类3.5 测试 参考资…

2025年PMP考试的3A好考吗?

确实&#xff0c;PMP正式抛弃第六版用第七版教材了&#xff0c;但是考纲还是跟24年一样的&#xff0c;情景题多&#xff0c;考的比之前灵活&#xff0c;但是 3A 的人也不少&#xff0c;按照机构的计划来学习并没有很难&#xff0c;给大家说说我的备考经历吧&#xff0c;希望对你…

VScode + PlatformIO 了解

​Visual Studio Code Visual Studio Code&#xff08;简称 VS Code&#xff09;是一款由微软开发且跨平台的免费源代码编辑器。该软件以扩展的方式支持语法高亮、代码自动补全&#xff08;又称 IntelliSense&#xff09;、代码重构功能&#xff0c;并且内置了工具和 Git 版本…

完美日记营销模式对开源 AI 智能名片 2 + 1 链动模式 S2B2C 商城小程序的启示

摘要&#xff1a;本文通过分析完美日记在营销中利用社会基础设施升级红利、网红与新流量平台、KOL 和私域流量等策略取得成功的案例&#xff0c;探讨其对开源 AI 智能名片 2 1 链动模式 S2B2C 商城小程序在营销推广、用户获取与留存、提升复购率等方面的启示&#xff0c;为商城…

Failed to install Visual Studio Code update

当关闭vsCode的时候&#xff0c;出现了下面的报错&#xff1a; 可能是之前将vscode文件换了位置导致的&#xff0c;并且vscode在桌面的图标也变成了下面这个&#xff1a; 解决方法&#xff1a; 找到上图路径的log文件并打开&#xff1a; 搜索电脑中的Code.exe文件 并粘贴到上…

python在word的页脚插入页码

1、插入简易页码 import win32com.client as win32 from win32com.client import constants import osdoc_app win32.gencache.EnsureDispatch(Word.Application)#打开word应用程序 doc_app.Visible Truedoc doc_app.Documents.Add() footer doc.Sections(1).Footers(cons…

Rust 力扣 - 73. 矩阵置零

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用两个变量记录矩阵初始状态的第一行与第一列是否存在0 然后我们遍历矩阵&#xff08;跳过第一行与第一列&#xff09;&#xff0c;如果矩阵中元素为0则将该元素映射到矩阵第一行与矩阵第一列的位置置为0…

Python | Leetcode Python题解之第537题复数乘法

题目&#xff1a; 题解&#xff1a; class Solution:def complexNumberMultiply(self, num1: str, num2: str) -> str:real1, imag1 map(int, num1[:-1].split())real2, imag2 map(int, num2[:-1].split())return f{real1 * real2 - imag1 * imag2}{real1 * imag2 imag1…

tauri开发中如果取消了默认的菜单项,复制黏贴撤销等功能也就没有了,解决办法

取消默认的菜单项&#xff1a;清除tauri默认的菜单项&#xff0c;让顶部的菜单menu不显示-CSDN博客 就是通过配置空菜单&#xff0c;让菜单不显示&#xff0c;但是这个引发的问题就是复制黏贴撤销等功能也就没有了&#xff0c;解决办法&#xff1a; 新增加编辑下的子菜单&…

STM32F103C8T6学习笔记3--按键控制LED灯

1、实验内容 S4、S5分别接PB12和PB13&#xff0c;实验要求&#xff0c;按下S4&#xff0c;D1亮&#xff0c;D2灭&#xff1b;按下S5&#xff0c;D2亮&#xff0c;D1灭。 由于按键学习的是GPIO口的输入功能&#xff0c;和输出功能的配置略有区别。本次通过按键触发相应功能没有…

微服务核心——网关路由

目录 前言 一、登录存在的问题归纳 二、*微服务网关整体方案 三、认识微服务网关 四、网关鉴权实现 五、OpenFeign微服务间用户标识信息传递实现 六、微服务网关知识追问巩固 前言 本篇文章具体讲解微服务中网关的实现逻辑、用于解决什么样的问题。其中标题中标注* 涉…

如何压缩pdf文件的大小?5分钟压缩pdf的方法推荐

如何压缩pdf文件的大小&#xff1f;在现代办公和学习中&#xff0c;PDF文件因其稳定性和广泛的兼容性被广泛使用。然而&#xff0c;随着文件内容的增多&#xff0c;制作好的PDF文件常常变得过大&#xff0c;给使用带来了诸多不便。无论是电子邮件附件的发送&#xff0c;还是在线…

entos7离线安装xrdp和图形化桌面

1、查看Linux系统环境 cat /etc/os-release NAME"CentOS Linux" VERSION"7 (Core)" ID"centos" ID_LIKE"rhel fedora" VERSION_ID"7" PRETTY_NAME"CentOS Linux 7 (Core)" ANSI_COLOR"0;31" CPE_NAME…

RSA算法简介(原理,举例)

目录 RSA算法原理 1. 密钥生成 步骤&#xff1a; 2. 加密 3. 解密 RSA算法示例 示例步骤 加密示例 解密示例 RSA算法是一种非对称加密算法&#xff0c;由Ron Rivest、Adi Shamir和Leonard Adleman在1977年提出。RSA算法的安全性基于大整数因子分解的难度&#xff0c;是…

海鲜图像分割系统:图像技术

海鲜图像分割系统源码&#xff06;数据集分享 [yolov8-seg-C2f-DAttention&#xff06;yolov8-seg-C2f-SCcConv等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Globa…

[react]10、react性能优化

1、列表&key 一、React更新流程 React在props或state发生改变时&#xff0c;会调用React的render方法&#xff0c;会创建一颗不同的树。React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI。 同层节点之间相互比较&#xff0c;不会垮节点比较;不同类型的节点&am…

Android 托管 Github Action 发布 Github Packages ,实现 Mvn 免费自动化托管

自从多年前 JCenter 关闭服务之后&#xff0c;GSY 项目版本就一直发布在 Jitpack 上&#xff0c;如今每个月也都有大概 10w 左右下载&#xff0c;但是近年来时不时就会出现历史版本丢失的问题&#xff0c;而且有时候还不是某个具体版本丢失&#xff0c;而是版本里的某几个依赖突…