鸿蒙HarmonyOS从零实现类微信app效果第一篇,基础界面搭建

news2024/12/28 4:15:58

最近鸿蒙HarmonyOS开发相关的消息非常的火,传言华为系手机后续将不再支持原生Android应用,所以对于原Android应用开发对应的Harmony版本也被一系列大厂提上了日程。作为一个名义上的移动端开发工程师((⊙o⊙)…,最近写python多过Android),当人不让要来学习一波。本次的学习计划是实现一个类微信app效果,计划将常规的app效果都实现一下,以便后续如果需要写Harmony应用,可以直接上手。

由于我本人有多年的开发经验和多种语言的开发经验,对于JavascriptTypeScript也写得比较多,所以对于TypeScript语法部分将不再过多说明,想快速了解到的同学可以直接查看我的快速入门TypeScript系列文章。同时,文章中设计到的我认为比较重要的知识点,会在文章中作说明。

  • TypeScript快速入门教程(一)、基础类型和变量声明
  • TypeScript快速入门教程(二)、面向对象知识(接口、类、抽象类)
  • TypeScript快速入门教程(三)、函数、范型使用
  • TypeScript快速入门教程(四)、联合类型 & 交叉类型 & 类型保护

功能拆分

在这里插入图片描述
上面只是一个简单的拆分示例,当我们拿到一个功能的时候,一定要先将页面进行拆分,当我们要实现的功能通过一个个子模块实现后,最终通过子模块的拼接,就可以得到一个完整的功能。

细节实现

今天第一课,先实现整体的界面搭建,最终的实现效果如下图。

在这里插入图片描述
当我们点击之后,可以切换上面的tab内容界面。

Harmony提供了很多种方式可以实现底部导航栏,真实项目使用的话,大家可以直接使用系统提供的方式即可。这里我采用的方式是自己用最基础的代码实现,这样也能联系到一些想要学习的功能,开箱即用是好的,但是也很容易让我们错过很多关键知识。

实现BottomNavigationItem

我们这里整体的底部是一个BottomNavigation,他是由四个BottomNavigationItem组合实现。首先定义一个实体类,用于存贮底部导航栏对象信息。

export class BottomNavigationEntity {
  /**
   * 底部导航tab标题
   */
  title: Resource;

  /**
   * 底部导航tab图片
   */
  image: Resource;

  /**
   * 底部导航tab图片,未选中
   */
  unCheckImage: Resource;

  /**
   * tab类型标志位
   */
  tag: number;

  constructor(tag: number, title: Resource, image: Resource, unCheckImage: Resource) {
    this.tag = tag;
    this.title = title;
    this.image = image;
    this.unCheckImage = unCheckImage;
  }
}

接下来的 在这里插入图片描述
组成是一个图标+一个文字组合而成,第一反应我们应该行到Column组件。

Column组件中,用于处理组件内容对其方式使用的话flex方式。
alignItems(value: HorizontalAlign): ColumnAttribute; # 水平方向
justifyContent(value: FlexAlign): ColumnAttribute; # 垂直方向
了解了这些之后,接下来看具体BottomNavigationItem的封装代码。

@Preview  # 方便单个view直接预览
@Component  # 标记是一个组件,可供其他组件引用
export default struct BottomNavigationItem {
  private navigationItem: BottomNavigationEntity;
  
  # 这里的Link是用于父组件和子组件进行通信	
  @Link currentIndex: number;

  build() {
    Column({ space: 5 }) {
    # 这里判断如果当前选中的item是当前的这个,则使用选中状态图片
      Image(this.currentIndex === this.navigationItem.tag ? this.navigationItem.image : this.navigationItem.unCheckImage)
        .width(24)
        .height(24)
      Text(this.navigationItem.title)
        .fontSize(14)
        .fontColor(this.currentIndex === this.navigationItem.tag ? Color.Green : 0x333333)
    }
  }
}

代码是不是非常简单。对于@Link你如果现在不太清楚,也没有关系,我最终会专门进行一个讲解。

实现BottomNavigation

@Preview
@Component
export default struct BottomNavigation {
  @Link currentItemIndex: number;

  build() {
    Row({ space: 5 }) {
      //  这里通过对结合遍历,生成BottomNavigationItem进行填充BottomNavigation
      ForEach(navigationViewModel.getNavigationList(), (item: BottomNavigationEntity, index: number) => {
        # 对于这里的$currentItemIndex写法可以先将疑问留着,后续结合Link一并说明
        BottomNavigationItem({ navigationItem: item, currentIndex: $currentItemIndex })
          .onClick(() => {
          	#  点击后更新选中的item,以实现刷新界面的效果
            this.currentItemIndex = index
          })
      })
    }
    .width('100%')
    .height(65)
    .padding({
      top: 5,
      bottom: 5
    })
    .justifyContent(FlexAlign.SpaceAround)
    .backgroundColor(0xF3EEEA)
  }
}

实现WechatMainFrame

整体的界面组合使用RelativeContainer进行组合,将BottomNavigation固定于屏幕的底部,内容区域底部在BottomNavigation之上,顶部和屏幕顶部对其,使其填充满BottomNavigation之上的部分。内容区域使用Stack将所有的内容层叠展示,切换到哪个展示,则使用visibility方法设置该页面展示即可。

@Entry
@Component
struct WechatMainFrame {
  @State currentCheckIndex: number = 0;

  build() {
    RelativeContainer() {
      BottomNavigation({ currentItemIndex: $currentCheckIndex })
        .alignRules({
          bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
          left: { anchor: "__container__", align: HorizontalAlign.Start }
        })
        .id("bottomNavigation")

      Stack() {
        HomeFragment().visibility(this.currentCheckIndex == 0 ? Visibility.Visible : Visibility.Hidden)
        ContactFragment().visibility(this.currentCheckIndex == 1 ? Visibility.Visible : Visibility.Hidden)
        DiscoverFragment().visibility(this.currentCheckIndex == 2 ? Visibility.Visible : Visibility.Hidden)
        MeFragment().visibility(this.currentCheckIndex == 3 ? Visibility.Visible : Visibility.Hidden)
      }
      .width('100%')
      .height('100%')
      .alignRules({
        left: { anchor: "__container__", align: HorizontalAlign.Start },
        right: { anchor: "__container__", align: HorizontalAlign.End },
        bottom: { anchor: "bottomNavigation", align: VerticalAlign.Top },
        top: { anchor: "__container__", align: VerticalAlign.Top }
      })
      .id("contentPanel")
    }
    .width('100%').height('100%')
  }
}

入口页面EntryAbility

export default class EntryAbility extends UIAbility {
  ...
  onWindowStageCreate(windowStage: window.WindowStage) {
    // Main window is created, set main page for this ability
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/WechatMainFrame', (err, data) => {
      if (err.code) {
        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
        return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
    });
  }
  ...

至此整个页面的框架结构完成了。

关于@Link相关的说明

关于更详细的内容,可以看官方文章说明。@Link装饰器:父子双向同步

我们对于视图更新,可以使用@State 标记变量,但是@State不能进行跨文件使用。这个时候@Link的实现就弥补了@State的不足。使用@Link的话。子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。

  • @Link装饰的变量与其父组件中的数据源共享相同的值。
  • @Link装饰器不能在@Entry装饰的自定义组件中使用。
  • @Link子组件从父组件初始化@State的语法为Comp({ aLink: this.aState })。同样Comp({aLink: $aState})也支持。
    在这里插入图片描述
    下面我们回到上面的代码中。结合代码进行分析。
    当我们在BottomNavigation.onClick(() => { this.currentItemIndex = index })在点击之后,会更改@Link currentItemIndex: number;触发界面ui的更改。而BottomNavigationItem({ navigationItem: item, currentIndex: $currentItemIndex })中,我们需要把选中的item的index值传递给BottomNavigationItem本身。而作为传递的值,则需要使用$标记。这样点击之后会将BottomNavigationItem的值也触发更改,以达到更改布局效果。BottomNavigationItem的判断也会根据这个值变化而变化。

点击之后,除了对BottomNavigation的状态更新之外,还需要对内容区域进行判断展示不同的界面。因此BottomNavigation@Link currentItemIndex: number;又要和WechatMainFrame @State currentCheckIndex: number = 0;进行双向绑定BottomNavigation({ currentItemIndex: $currentCheckIndex })。最终当我们点击BottomNavigationonclick的时候,就会向上和WechatMainFrame双向绑定更改内容区域,也会和BottomNavigationItem双向绑定更改底部导航展示。

由于我自己也是在边学边实现功能逻辑,既要写文章,还要实现代码功能,所以更新大体上控制在2~3天更新一篇,文章中尽可能会将我觉得比较重要的知识点拎出来说明。对于看完还不太清楚的,可以私信或者查阅其他文章了解,知识的获取不应该被局限,希望我的文章给你带来帮助。谢谢阅读。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows配置IP-SAN(iSCSI)

之前写了《Linux配置IP-SAN(iSCSI)》,现在简单记录Windows配置IP-SAN(iSCSI),基本过程都是一样的。一些原理请参考《Linux配置IP-SAN(iSCSI)》,更详细一些。 目录 一、确…

Pytorch教程(代码逐行解释)

0、配准环境教程 1、开始导入相应的包 import torch from torch import nn from torch.utils.data import DataLoader from torchvision import datasets from torchvision.transforms import ToTensortorch是pytorch的简写 torch.utils.data import DataLoader 是用于读取数…

java实现冒泡排序

冒泡排序是一种简单的排序算法&#xff0c;以下是Java实现示例代码&#xff1a; public static void bubbleSort(int[] array) {int n array.length;for (int i 0; i < n - 1; i) {for (int j 0; j < n - i - 1; j) {// 如果前面的元素比后面的元素大&#xff0c;就交…

H5游戏源码分享-网页版2048小游戏

H5游戏源码分享-网页版2048小游戏 玩过的都懂 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>分享2048到朋友圈&#xff0c;将免费参加南山郡8.17号啤酒狂欢节&#xff01;</title><link href"style/main…

Spring核心

Spring Framework Spring的两个核心IOC控制反转IOC容器依赖注入DIIOC容器实现注解管理BeanBean对象定义Bean对象获取 AOP面向切面编程 添加依赖入门案例注解通过Spring创建Java bean对象 xml管理Bean案例main下创建bean.XMl文件 DI依赖注入案例创建Spring配置文件 bean-di.xml …

25.4 MySQL 函数

1. 函数的介绍 1.1 函数简介 在编程中, 函数是一种组织代码的方式, 用于执行特定任务. 它是一段可以被重复使用的代码块, 通常接受一些输入(参数)然后返回一个输出. 函数可以帮助开发者将大型程序分解为更小的, 更易于管理的部分, 提高代码的可读性和可维护性.函数在编程语言…

线程有哪些状态

线程的生命周期 线程在Java中有以下几种状态&#xff1a; 新建&#xff08;New&#xff09;&#xff1a;初始化状态就绪&#xff08;Runnable&#xff09;&#xff1a;可运行、运行状态阻塞&#xff08;Blocked&#xff09;&#xff1a;等待状态&#xff0c;无时限等待&#…

Vue3-TypeScript-Threejs:导入外部的glb格式3D模型

一、直接上代码&#xff0c;在vue3-typescript-threejs 项目 导入外部的glb格式3D模型 极简代码&#xff0c;快速理解 <template><div ref"container"></div></template><script lang"ts" setup>import { onMounted, ref …

您的计算机已被Mallox勒索病毒感染?恢复您的数据的方法在这里!

尊敬的读者&#xff1a; 随着科技的迅速发展&#xff0c;网络安全问题日益凸显&#xff0c;其中勒索病毒是一种极具威胁性的恶意软件。在这些勒索病毒中&#xff0c;.mallox 勒索病毒尤为突出&#xff0c;它能够加密用户的数据文件&#xff0c;要求支付赎金才能解密。本文将介…

高效使用 PyMongo 进行 MongoDB 查询和插入操作

插入到集合中&#xff1a; 要将记录&#xff08;在MongoDB中称为文档&#xff09;插入到集合中&#xff0c;使用insert_one()方法。insert_one()方法的第一个参数是一个包含文档中每个字段的名称和值的字典。 import pymongomyclient pymongo.MongoClient("mongodb://l…

笔试题之指针和数组的精讲

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

Ubuntu 和 Windows 文件互传

FTP 服务 FTP 采用 Internet 标准文件传输协议 FTP 的用户界面&#xff0c; 向用户提供了一组用来管理计算机之间文件传输的应用程序。在开发的过程中会频繁的在 Windows 和 Ubuntu 下进行文件传输&#xff0c;比如在 Windwos 下进行代码编写&#xff0c;然后将编写好的代码拿到…

JavaEE初阶(18)(JVM简介:发展史,运行流程、类加载:类加载的基本流程,双亲委派模型、垃圾回收相关:死亡对象的判断算法,垃圾回收算法,垃圾收集器)

接上次博客&#xff1a;初阶JavaEE&#xff08;17&#xff09;Linux 基本使用和 web 程序部署-CSDN博客 目录 JVM 简介 JVM 发展史 JVM 运行流程 JVM的内存区域划分 JVM 执行流程 堆 堆的作用 JVM参数设置 堆的组成 垃圾回收 堆内存管理 类加载 类加载的基本流…

Windows conan环境搭建

Windows conan环境搭建 1 安装conan1.1 安装依赖软件1.1.1 python安装1.1.2 git bash安装1.1.3 安装Visual Studio Community 20191.1.3.1 选择安装的组件1.1.3.2 选择要支持的工具以及对应的SDK 1.1.4 vscode安装 1.3 验证conan功能1.4 查看conancenter是否包含poco包1.5 查看…

SQL 日期函数

在数据库中&#xff0c;日期和时间是经常需要处理的数据类型之一。SQL提供了许多内置的日期函数&#xff0c;用于对日期和时间进行操作、计算和比较。这些函数可以帮助我们提取日期的各个部分&#xff08;如年份、月份、日、小时、分钟等&#xff09;&#xff0c;执行日期的转换…

第一百七十二回 SegmentedButton组件

文章目录 1. 概念介绍2. 使用方法2.1 SegmentedButton2.2 ButtonSegment 3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"SearchBar组件"相关的内容&#xff0c;本章回中将 介绍SegmentedButton组件.闲话休提&#xff0c;让我们一起Tal…

抖斗音_快块手直播间获客助手+采集脚本+引流软件功能介绍

软件功能&#xff1a; 支持同时采集多个直播间&#xff0c;弹幕&#xff0c;关*注&#xff0c;礼*物&#xff0c;进直播间&#xff0c;部分用户手*号,粉*丝团采集 不支持采集匿*名直播间 设备需求&#xff1a; 电脑&#xff08;win10系统&#xff09; 文章分享者&#xff1…

【Linux】第十五站:环境变量

文章目录 一、进程相关的一些概念1.一些常见的概念2.对于并发3.**进程切换** 二、环境变量1.PATH环境变量2.HOME环境变量3.SHELL环境变量4.env5.系统调用接口与环境变量6.什么是环境变量&#xff1f;7.命令行参数8.main函数的第三个命令行参数9.如何验证环境变量是可以被继承的…

java实现选择排序

图解 以下是Java实现选择排序的示例代码&#xff1a; public class SelectionSort {public static void selectionSort(int[] arr) {int n arr.length;// 遍历未排序部分的数组for (int i 0; i < n - 1; i) {// 在未排序部分中查找最小元素的下标int minIndex i;for (in…

MySQL 人脸向量,欧几里得距离相似查询

前言 如标题&#xff0c;就是通过提取的人脸特征向量&#xff0c;写一个欧几里得 SQL 语句&#xff0c;查询数据库里相似度排前 TOP_K 个的数据记录。做法虽然另类&#xff0c;业务层市面上有现成的面部检索 API&#xff0c;技术层现在有向量数据库。 用 MySQL 关系型存储 128 …