鸿蒙一次开发,多端部署(二)从一个例子开始

本章通过一个天气应用,介绍一多应用的整体开发过程,包括UX设计、工程管理及调试、页面开发等。

UX设计

本示例中的天气应用包含主页、管理城市和添加城市三个页面,其中主页中又包含菜单和更新间隔两个弹窗,基本业务逻辑如下所示。

“一多”建议从最初的设计阶段开始就拉通多设备综合考虑。考虑实际智能终端设备种类繁多,设计师无法针对每种具体设备各自出一份UX设计图。“一多”建议从设备屏幕宽度的维度,将设备划分为四大类。设计师只需要针对这四大类设备做设计,而无需关心具体的设备形态。

设备类型屏幕宽度(vp)
超小设备[0, 320)
小设备[320, 600)
中设备[600, 840)
大设备[840, +∞)

说明:

  • vp是virtual pixel(虚拟像素)的缩写,是常用的长度单位,详见视觉基础小节中的介绍。
  • 此处基于设备屏幕宽度划分不同设备是为了读者方便理解。通常智能设备上的应用都是以全屏的形式运行,但随着移动技术的发展,当前部分智能设备支持应用以自由窗口模式运行(即用户可以通过拖拽等操作自由调整应用运行窗口的尺寸),故以应用窗口尺寸为基准进行划分更为合适,本文后续的响应式布局章节中将详细介绍相关内容。
  • OpenHarmony当前仅有默认设备和平板两种设备形态,IDE在创建OpenHarmony工程时也仅可以选择默认设备和平板。随着演进,其支持的设备形态会不断丰富,本文也会定期刷新相关介绍。

默认设备和平板对应于小设备、中设备及大设备,本示例以这三类设备场景为例,介绍不同设备上的UX设计。天气主页在不同设备上的设计图如下所示。

另外,大设备中天气主页还允许用户开启或者隐藏侧边栏。

从天气应用在各设备上的UX设计图中,可以观察到如下UX的一些“规律”:

  • 在不同的屏幕宽度下,应用的整体风格基本保持一致。
  • 在相近的屏幕宽度范围内,应用的布局基本不变;在不同的屏幕宽度范围内,应用的布局有较大差异。
  • 应用在小屏幕下显示的元素,是大屏幕中显示元素的子集。
    • 考虑到屏幕尺寸及显示效果,大屏幕中可以显示的元素数量一定不少于小屏幕。
    • 为充分利用屏幕尺寸优势,大屏幕可以有其独有的元素或设计(如本示例中的侧边栏)。

如此,既在各设备上体现了UX的一致性,也在各设备上体现了UX的差异性,从而既可以保障各设备上应用界面的体验,也可以最大程度复用界面代码。

在应用UX设计章节中,将详细介绍应用的UX设计规则。

工程管理及调试

在本文IDE使用章节中,将详细介绍一多的工程创建及管理等,本小节仅介绍最基础的工程创建及多设备预览调试。

工程创建

一多应用的工程创建过程,与传统应用并无较大差异。只需在工程创建过程中,注意在“Device Type”选项中勾选所有该应用期望运行的目标设备类型,保证后续该应用可以在所有目标设备上正确安装即可。

预览调试

在代码开发过程中,可以开启预览器,并打开“Multi-profile preview”开关,实时观察应用在不同设备下的表现。

特别的,还可以点击“+ New Profile”按钮,新增自定义预览器。

页面开发

天气应用中涉及较多的页面和弹窗,本小节以天气主页为例,简单介绍不同设备下的页面实现思路。

观察天气主页在不同设备上的UX设计图,可以进行如下设计:

  • 将天气主页划分为9个基础区域,如:

  • 基础区域9仅在大设备上显示,基础区域1-8虽然在各设备上始终展示但其尺寸及区域内的布局基本保持不变,可以结合自适应布局能力以自定义组件的形式分别实现这9个基础区域。

  • 基础区域1-8之间的布局在不同设备上有较大差异,可以使用响应式布局中的栅格布局能力实现组件间的布局效果。

  • 展开和隐藏侧边栏的功能可以通过侧边栏组件来实现。侧边栏是大设备上独有的,借助响应式布局中的媒体查询能力,控制仅在大设备上展示侧边栏即可。

主页基础区域

天气主页中的9个基础区域介绍及实现方案如下表所示。

编号简介实现方案
1标题栏自适应布局拉伸能力。
2天气概览Row和Column组件,并指定其子组件按照主轴起始方向对齐或居中对齐。
3每小时天气自适应布局延伸能力 。
4每日天气自适应布局延伸能力 。
5空气质量Canvas画布组件绘制空气质量图,并使用Row组件和Column组件控制内部元素的布局。
6生活指数自适应布局均分能力。
7日出日落Canvas画布组件绘制日出日落图 。
8应用信息Row和Column组件,并指定其子组件居中对齐。
9侧边导航栏综合运用自适应布局中的拉伸能力、占比能力和延伸能力 。

天气主页涉及的内容较多,因篇幅限制,本小节仅介绍区域3(每小时天气)的实现,读者可以自行查看开源代码,了解其它基础区域的实现。

延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。随着可用显示区域的增加,用户可以看到的“每小时天气”信息也不断增加,故“每小时天气”可以通过延伸能力实现,其核心代码如下所示。

import { Forecast, getHoursData, MyDataSource, Style } from '@ohos/common';

@Component
export default struct HoursWeather {
  private hoursData: Forecast[] = getHoursData(0);
  @State hoursDataResource: MyDataSource = new MyDataSource(this.hoursData);

  build() {
    // 通过列表组件实现延伸能力
    List() {
      LazyForEach(this.hoursDataResource, (hoursItem:IDataSource) => {
        ListItem() {
          // 具体每个小时的天气情况
          Column() { 
              // ... 
            }
        }
      })
    }
    .height(Style.CARD_HEIGHT)
    .borderRadius(Style.NORMAL_RADIUS)
    .backgroundColor(Style.CARD_BACKGROUND_COLOR)
    // 将列表方向设置为水平方向
    .listDirection(Axis.Horizontal)
  }
}

城市天气详情

天气主页右侧的城市天气详情由区域1-8组成,区域1(标题栏)始终固定在页面顶部,区域2-8在不同设备下的布局不同且可以随页面上下滚动。本小节介绍如何实现城市天气详情中区域2~8的布局效果。

设备屏幕可能无法一次性显示区域2-8的所有内容,故需要在外层增加滚动组件(即Scroll组件)以支持上下滚动。不同设备下区域2-8的相对位置一共有三套不同的布局,可以借助响应式布局中的栅格布局实现这一效果。本示例中将栅格在不同场景下分别划分为4列、8列和12列,区域2-8在不同场景下的布局如下表所示。

说明: 为提升用户体验,大设备侧边栏隐藏状态下,每日天气与空气质量的相对顺序发生了改变。可以调整通过GridCol栅格子组件的order属性,实现目标效果。

import AirQuality from './AirQuality'; //组件请参考相关实例
import HoursWeather from './HoursWeather';
import IndexHeader from './IndexHeader';
import IndexEnd from './IndexEnd';
import LifeIndex from './LifeIndex';
import MultidayWeather from './MultidayWeather';
import SunCanvas from './SunCanvas';
import { CityListData, Style } from '@ohos/common';

@Component
export default struct HomeContent {
  private cityListData: CityListData | undefined = undefined;
  private index: number = 1;
  @Prop showSideBar: boolean;
  @State headerOpacity: number = 1;

  build() {
    // 支持滚动
    Scroll() {
      GridRow({
        columns: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 },
        gutter: { x: Style.GRID_GUTTER, y: Style.GRID_GUTTER },
        breakpoints: { reference: BreakpointsReference.WindowSize } }) {
        // 天气概览
        GridCol({ span: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 }, order: 1 }) {
          IndexHeader({ headerDate: this.cityListData.header, index: this.index })
            .opacity(this.headerOpacity)
        }
        // 每小时天气
        GridCol({ span: { sm: 4, md: 8, lg: 8 }, order: 2 }) {
          HoursWeather({ hoursData: this.cityListData.hoursData })
        }
        // 每日天气
        GridCol({ span: 4, order: {sm: 3, md: 3, lg: this.showSideBar ? 3 : 4} }) {
          MultidayWeather({ weekData: this.cityListData.weekData })
        }
        // 空气质量
        GridCol({ span: 4, order: {sm: 4, md: 4, lg: this.showSideBar ? 4 : 3} }) {
          AirQuality({ airData: this.cityListData.airData, airIndexData: this.cityListData.airIndex })
        }
        // 生活指数
        GridCol({ span: 4, order: 5 }) {
          LifeIndex({ lifeData: this.cityListData.suitDate })
        }
        // 日出日落
        GridCol({ span: 4, order: 6 }) {
          SunCanvas()
        }
        // 应用信息
        GridCol({ span: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 }, order: 7 }) {
          IndexEnd()
        }
      }
    }
    .width('100%')
  }
}

主页整体实现

综合考虑各设备下的效果,天气主页的根节点使用侧边栏组件:

  • 小设备和中设备既不展示侧边栏,也不提供控制侧边栏显示和隐藏的按钮。
  • 大设备默认展示侧边栏,同时提供控制侧边栏显示和隐藏的按钮。

另外主页右侧的城市天气详情,支持左右滑动切换城市,可以使用Swiper组件实现目标效果。

  • 小设备和中设备开启Swiper组件的导航点,引导用户通过左右滑动切换不同城市。
  • 大设备中用户通过点击侧边栏中的城市列表即可高效的切换不同城市,此时需要关闭Swiper组件的导航点。
import HomeContent from './home/HomeContent'; //组件请参考相关实例
import IndexTitleBar from './home/IndexTitleBar';
import SideContent from './home/SideContent';
import { CityListData,  getCityListWeatherData } from '@ohos/common';

@Entry
@Component
struct Home {
  @State cityListWeatherData: CityListData[] = getCityListWeatherData();
  @State curBp: string = 'md';
  @State showSideBar: boolean = false;
  
  build() {
    SideBarContainer(SideBarContainerType.Embed) {
      // 左侧侧边栏
      SideContent({ showSideBar: $showSideBar })
      // 右侧内容区
      Flex({direction: FlexDirection.Column}) {
        // 基础区域1标题栏
        IndexTitleBar({ curBp: this.curBp, showSideBar: $showSideBar })
          .height(56)
        // 天气详情,通过Swiper组件实现左右滑动切换城市的效果
        Swiper() {
          ForEach(this.cityListWeatherData, (item:CityListData, index) => {
            HomeContent({ showSideBar: this.showSideBar, cityListData: item, index: index })
          })
        }
        // 大设备关闭导航点
        .indicator(this.curBp !== 'lg')
        .width('100%')
      }
    }
    .height('100%')
    .sideBarWidth('33.3%')
    // 通过状态变量,控制不同设备下侧边栏的显隐状态
    .showSideBar(this.showSideBar)
  }
}

最终,天气首页的运行效果如下图所示。

功能开发

应用开发不仅包含应用页面开发,还包括应用后端功能开发以及服务器端开发等。服务器端开发不在本文的讨论范围内,本小节仅介绍多设备上应用功能开发的注意事项。

如前文所示,本示例的目标运行设备是小设备、中设备和大设备,对应实际的设备类型为默认设备和平板等。这些设备运行的都是标准系统,其系统能力一致,所以无需做特别考虑。但是在超小设备(对应的实际设备类型为智能穿戴设备等)上,考虑CPU、内存、硬盘等硬件限制,往往会对系统进行裁剪。如果在应用后端功能开发时调用当前系统没有的能力,就可能会引发异常。

通常有两种方式解决上述问题:

  • 在应用安装包中描述其需要的系统能力,保证本应用仅被分发和安装到可以满足其诉求的系统中。
  • 在使用特定系统能力前,通过canIUse接口判断系统能力是否存在,进而执行不同的逻辑。

相关实例

针对天气应用,有以下相关实例可供参考:

天气应用:天气应用示例

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

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

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

相关文章

2024.3.21学习笔记

今日学习韩顺平java0200_韩顺平Java_对象机制练习_哔哩哔哩_bilibili 今日学习p246-p251 this关键词 java虚拟机会给每个对象分配this, 代表当前对象 this内存机制 this关键字可以用来访问类的属性、方法、构造器 this用以区分当前类的属性和局部变量 访问成员方法的语法…

《云计算:数字时代的引擎》

在数字化时代,云计算技术以其强大的计算能力和灵活的应用方式,成为推动各行各业发展的引擎。本文将围绕云计算的技术进展、技术原理、行业应用案例、面临的挑战与机遇以及未来趋势进行详细探讨。 云计算的技术进展 云计算的技术进展涵盖了多个方面&…

Redis入门到入坑(二)

Redis入门到入坑(二) Redis 数据持久化简介Rdb方式持久化Aof方式数据持久化 Redis事务处理Redis事务简介Redis事务控制实践 Redis架构设计Redis主从复制Redis哨兵模式Redis集群高可用 Redis在SpringBoot工程中的综合应用业务描述准备工作业务逻辑代码设计…

[ C++ ] STL---list的模拟实现

目录 结点类的模拟实现 迭代器类的模拟实现 构造函数 前置与后置 前置- -与后置 - - 与 !运算符重载 * 运算符重载 -> 运算符重载 普通迭代器总体实现代码 list类的实现 list类的成员变量 构造函数 迭代器 insert() erase() push_front/push_back…

C#探索之路基础篇(2):接口Interface的概念、实现、应用范围

文章目录 1 概念2 示例代码:2.1 简单接口的实现2.2 简单的使用接口2.3 使用接口呈现多态性2.4 通过接口实现一个数组迭代器2.5 通过接口来实现松耦合的关系2.6 使用接口实现可扩展、便利性 3 使用范围与时机4 注意事项 不知道大家在学习的过程中,有没有反…

AI原生安全 亚信安全首个“人工智能安全实用手册”开放阅览

不断涌现的AI技术新应用和大模型技术革新,让我们感叹从没有像今天这样,离人工智能的未来如此之近。 追逐AI原生?企业组织基于并利用大模型技术探索和开发AI应用的无限可能,迎接生产与业务模式的全面的革新。 我们更应关心AI安全原…

机器学习——决策树(四)后剪枝

观前提示:这是本人决策树相关的第四篇博文,前3篇的内容如下: 1、建造训练集的决策树【完成结点类编写和建树过程】 2、用验证集评估模型、选出泛化较好的数据划分方式训练模型 3、预剪枝 读者可根据需要从上方《机器学习》专栏中查阅对应…

【论文笔记】RobotGPT: Robot Manipulation Learning From ChatGPT

【论文笔记】RobotGPT: Robot Manipulation Learning From ChatGPT 文章目录 【论文笔记】RobotGPT: Robot Manipulation Learning From ChatGPTAbstractI. INTRODUCTIONII. RELATED WORK1. LLMs for Robotics2. Robot Learning III. METHODOLOGY1. ChatGPT Prompts for Robot …

基于Python3的数据结构与算法 - 16 链表

目录 链表 1. 创建链表 2. 链表的插入和删除 3. 双链表 4. 链表总结 链表 链表是由一系列节点组成的元素集合。每个节点包含两部分,数据域item和指向下一个节点得指针next。通过节点之间的相互连接,最终串联成一个链表。 class Node:def __init…

数据结构——循环队列的实现

💞💞 前言 hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥个人主页&#x…

Python 小而精Web开发框架Flask精通指南

文章目录 Flask 简介说明Flask 核心依赖Flask 常用扩展Flask 快速启动工作流程代码示例Flask 快速启动控制台Flask 快速启动效果 Flask 启动参数Flask 路由定义Flask 支持的 HTTP 请求方式:路由装饰器中的参数 Flask 路由参数Flask 路由蓝图路由蓝图的优点路由蓝图的…

痛失offer的八股

java面试八股 mysql篇: 事物的性质: 事物的性质有acid四特性。 a:automic,原子性,要么全部成功,要么全部失败,mysql的undolog,事物在执行的时候,mysql会进行一个快照读…

获取KEGG通路的基因列表 做单细胞GSEA、GSVA分析

使用KEGG通路的基因列表进行单细胞GSEA GSVA分析的过程,我们需要遵循以下步骤: 获取KEGG通路的基因列表:这通常涉及使用专门的R包,如KEGGREST或biomaRt,来查询KEGG数据库并检索特定通路的基因列表。 准备单细胞表达数…

详解JS原型与原型链的关系

1、构造函数原型prototype (1)、构造函数通过原型分配的函数是所有对象所共享的; (2)、JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象; (3)、注意这个prototype就是一个对象,这个对象的所有属性…

Scikit-Learn逻辑回归(二)

Scikit-Learn逻辑回归二:多项式与正则化 1、多项式回归回顾1.1、逻辑回归为什么要使用多项式1.2、多项式回归及原理 2、逻辑回归与多项式 1、多项式回归回顾 本文接上篇:Scikit-Learn逻辑回归(一) 上篇中,我们详细介绍了逻辑回归的概念、原理…

使用 React antd 的ProFormSelect组件 搜索查询 多选的写法

使用 React antd 的ProFormSelect组件 搜索查询 多选的写法 需求:需要一个搜索框,可以选择员工,(员工人数多无法一次性获取,全部放入options中),所以需要使用搜索功能,而且是可以多…

XR“黑话”

MTP(Motion-To-Photon Latency):实际人体发生运动到图像显示到屏幕上的时间延迟。早期一些vr产生晕动症的主要原因。 ATW(Asynchronous Timewarp):主要解决两个问题,一是延迟,二是补…

CSS弹性盒模型(学习笔记)

一、厂商前缀 1.1 作用 解决浏览器对C3新特性的兼容,不同的浏览器厂商,定义了自己的厂商前缀 1.2 语法 浏览器 厂商前缀内核(渲染引擎):解析htmlcssjs谷歌 -webkit-blink苹果-webkit-webkit欧朋-o-blink火狐 -moz-geckoIE-ms- trid…

OpenCV4.9.0开源计算机视觉库安装教程

返回:OpenCV系列文章目录(持续更新中......) 引言:OpenCV系列文章中的安装部分今天全部完成了,为了读者更方便阅读,大家可以按下列索引前往,成文较为仓促有错漏在所难免,欢迎大家指正…

服务器运行一段时间后

自己记录一下。 一、查看目录占用情况 df -h 命令查看磁盘空间 du -ah --max-depth=1 / 查看根目录下各个文件占用情况 二、mysql日志清空 这个日志是可以清空的 echo > /usr/local/mysql/data/syzl-db2.log #将文件清空 说明: 这个文件这么大是因为,开启 …