鸿蒙:使用Stack、ContentTable、Flex等组件和布局实现一个显示界面

效果展示

38d92b82951c466c9eea6d47f2e94dd3.png

一.概述

跟随官网继续HarmonyOS学习

本篇博文实现一个食物详情页的开发Demo

通过这个开发过程学习如何使用容器组件StackFlex和基本组件ImageText构建用户自定义组件,完成图文并茂的食物介绍

二.构建Stack布局

1.食物名称

创建Stack组件,Text子组件

Stack组件为堆叠组件,可以包含一个或多个子组件,其特点是后一个子组件覆盖前一个子组件。

@Entry
@Component
struct MyComponent {build() {Stack() {Text('Tomato').fontSize(26).fontWeight(500).fontColor(Color.White)}}
}

Previewer效果: 

34e2f012a9084c7f92a12bcabc48097f.png

2.食物图片

创建Image组件,指定Image组件的url

Text组件要在Image组件上方显示,所以先声明Image组件。

图片资源放在resources下的rawfile文件夹内,引用rawfile下资源时使用$rawfile('filename')的形式,filename为 rawfile 目录下的文件相对路径。

当前$rawfile仅支持Image控件引用图片资源

@Entry
@Component
struct MyComponent {build() {Stack() {Image($rawfile('Tomato.png'))Text('Tomato').fontSize(26).fontWeight(500)}}
}

Previewer效果: 

5feee84032c84f249fee04095d06f75c.png

 

3.通过资源访问图片

除指定图片路径外,也可以使用引用 媒体资源符$r 引用资源,需要遵循resources文件夹的资源限定词的规则。

右键resources文件夹,点击New>Resource Directory,选择Resource TypeMedia(图片资源)

注:新建的Resource Directory目录只能在base目录下,但是base目录默认是有media文件的

直接把Tomato.png放入media文件夹内,就可以通过$r('app.type.name')的形式引用应用资源了

Tomato.png即为 $r('app.media.Tomato')

代码:

@Entry
@Component
struct MyComponent {build() {Stack() {Image($r('app.media.Tomato')).objectFit(ImageFit.Contain).height(357)//Image($rawfile('Tomato.png'))Text('Tomato').fontSize(26).fontWeight(500)}}
}

Previewer: 

e3297d18775a46dcae3c8fba449f2caa.png

4.Image组件objectFit属性

示例中imageobjectFit属性设置为ImageFit.Contain
即保持图片长宽比的情况下,使图片完整地显示在边界内。

ImageobjectFit默认属性是ImageFit.Cover
即在保持长宽比的情况下放大或缩小,使其填满整个显示边界。

如果要想Image填满了整个屏幕,原因如下:
    1.Image没有设置宽高。
    2.objectFit属性使用默认值ImageFit.Cover

5.设置Stack布局属性

Stack默认为居中对齐,本示例中修改为底部起始端对齐
设置Stack构造参数alignContentAlignment.BottomStart

AlignmentFontWeight一样,都是框架提供的内置枚举类型

代码:

@Entry
@Component
struct MyComponent {build() {Stack({ alignContent: Alignment.BottomStart }) {Image($r('app.media.Tomato')).objectFit(ImageFit.Contain).height(357)//Image($rawfile('Tomato.png'))Text('Tomato').fontSize(26).fontWeight(500)}}
}

Previewer:  

fe28ca1159ef4d879955177cfe18a768.png

6.调整Text组件的外边距margin

margin属性调整组件外边距

(1).margin(Length),即上、右、下、左四个边的外边距都是Length

(2).margin { top?: Length,
                    right?: Length,
                    bottom?: Length,
                    left?:Length },即分别指定四个边的边距

代码:

@Entry
@Component
struct MyComponent {build() {Stack({ alignContent: Alignment.BottomStart }) {Image($r('app.media.Tomato')).objectFit(ImageFit.Contain).height(357)Text('Tomato').fontSize(26).fontWeight(500).margin({left: 26, bottom: 17.4})}   }
}

Previewer:

8509562c2d0542e6933b8586e782ec8b.png

6.调整组件间的结构,语义化组件名称

创建页面入口组件为FoodDetail,在FoodDetail中创建Column
设置水平方向上居中对齐 alignItems(HorizontalAlign.Center)

MyComponent组件名改为FoodImageDisplay,为FoodDetail的子组件 

Column是子组件竖直排列的容器组件,本质为线性布局,所以只能设置交叉轴方向的对齐

代码:

@Component
struct FoodImageDisplay {build() {Stack({ alignContent: Alignment.BottomStart }) {Image($r('app.media.Tomato')).objectFit(ImageFit.Contain)Text('Tomato').fontSize(26).fontWeight(500).margin({ left: 26, bottom: 17.4 })}.height(357)}
}@Entry
@Component
struct FoodDetail {build() {Column() {FoodImageDisplay()}.alignItems(HorizontalAlign.Center)}
}

Previewer:

3c7653ab992b4f8a9d23fb5b12497f65.png

三.构建Flex布局

Flex:弹性布局

使用Flex弹性布局来构建食物的食物成分表,

弹性布局在本场景的优势在于可以免去多余的宽高计算,通过比例来设置不同单元格的大小,更加灵活。

1.新建ContentTable组件

新建ContentTable组件,使其成为页面入口组件FoodDetail的子组件。

代码:

@Component
struct FoodImageDisplay {build() {Stack({ alignContent: Alignment.BottomStart }) {Image($r('app.media.Tomato')).objectFit(ImageFit.Contain).height(357)Text('Tomato').fontSize(26).fontWeight(500).margin({ left: 26, bottom: 17.4 })}}
}@Component
struct ContentTable {build() {}
}@Entry
@Component
struct FoodDetail {build() {Column() {FoodImageDisplay()ContentTable()}.alignItems(HorizontalAlign.Center)}
}

Previewer:

ContentTable子组件是空的,还没填充内容,当前Previewer效果与上一节一样。

2.创建Flex组件展示Tomato两类成分

一类是热量Calories:卡路里(Calories);

一类是营养成分Nutrition,包含:蛋白质(Protein)、
                                                      脂肪(Fat)、
                                                      碳水化合物(Carbohydrates)
                                                      维生素C(VitaminC)。

先创建热量这一类
新建Flex组件,高度为280,上、右、左内边距为30,
包含三个Text子组件分别代表:类别名(Calories)
                                                  含量名称(Calories)
                                                  含量数值(17kcal)
Flex组件默认为水平排列方式。

ContentTable代码:

@Component
struct ContentTable {build() {Flex() {Text('Calories').fontSize(17.4).fontWeight(FontWeight.Bold)Text('Calories').fontSize(17.4)Text('17kcal').fontSize(17.4)}.height(280).padding({ top: 30, right: 30, left: 30 })}
}

Previewer:

501da9cb100245a6bae2d7d7d108a657.png

3.调整布局,设置各部分占比

分类名占比(layoutWeight)为1,

成分名和成分含量一共占比(layoutWeight)2。

成分名和成分含量位于同一个Flex中,成分名占据所有剩余空间flexGrow(1)。

ContentTable代码:

@Component
struct ContentTable {build() {Flex() {Text('Calories').fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex() {Text('Calories').fontSize(17.4).flexGrow(1)Text('17kcal').fontSize(17.4)}.layoutWeight(2)}.height(280).padding({ top: 30, right: 30, left: 30 })}
}

Previewer:

9ca5951920fa48509f45d094cc408cbe.png

4.仿照热量分类创建营养成分分类

营养成分部分(Nutrition)包含:
                  蛋白质(Protein)、
                  脂肪(Fat)、
                  碳水化合物(Carbohydrates)
                  维生素C(VitaminC)

设置外层Flex为竖直排列 FlexDirection.Column
在主轴方向(竖直方向)上等距排列 FlexAlign.SpaceBetween
在交叉轴方向(水平轴方向)上首部对齐排列 ItemAlign.Start

ContentTable代码:

@Component
struct ContentTable {build() {Flex({ direction: FlexDirection.Column,justifyContent: FlexAlign.SpaceBetween,alignItems: ItemAlign.Start }) {Flex() {Text('Calories').fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex() {Text('Calories').fontSize(17.4).flexGrow(1)Text('17kcal').fontSize(17.4)}.layoutWeight(2)}Flex() {Text('Nutrition').fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex() {Text('Protein').fontSize(17.4).flexGrow(1)Text('0.9g').fontSize(17.4)}.layoutWeight(2)}Flex() {Text(' ').fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex() {Text('Fat').fontSize(17.4).flexGrow(1)Text('0.2g').fontSize(17.4)}.layoutWeight(2)}Flex() {Text(' ').fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex() {Text('Carbohydrates').fontSize(17.4).flexGrow(1)Text('3.9g').fontSize(17.4)}.layoutWeight(2)}Flex() {Text(' ').fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex() {Text('vitaminC').fontSize(17.4).flexGrow(1)Text('17.8mg').fontSize(17.4)}.layoutWeight(2)}}.height(280).padding({ top: 30, right: 30, left: 30 })}
}

Previewer:

38d92b82951c466c9eea6d47f2e94dd3.png

5.优化代码

可以发现,每个成分表中的成分单元其实都是一样的UI结构

2c75982c6a0849be90ac1400fa46ee09.png

可以通过自定义@Builder函数对代码进行精简

使用自定义@Builder抽象出相同的UI结构
@Builder修饰的方法和Componentbuild方法都是为了声明一些UI渲染结构,遵循一样的ArkTS语法。

可以定义一个或者多个 @Builder修饰的方法,但Componentbuild方法必须只有一个

ContentTable内声明@Builder修饰的IngredientItem方法,用于声明分类名、成分名称和成分含量UI描述。

@Component
struct ContentTable {@Builder IngredientItem(title:string, name: string, value: string) {Flex() {Text(title).fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex({ alignItems: ItemAlign.Center }) {Text(name).fontSize(17.4).flexGrow(1)Text(value).fontSize(17.4)}.layoutWeight(2)}}
}

ContentTablebuild方法内调用IngredientItem接口,
需要用this去调用该Component作用域内的方法,以此来区分全局的方法调用。

@Component
struct ContentTable {......build() {Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Start }) {this.IngredientItem('Calories', 'Calories', '17kcal')this.IngredientItem('Nutrition', 'Protein', '0.9g')this.IngredientItem('', 'Fat', '0.2g')this.IngredientItem('', 'Carbohydrates', '3.9g')this.IngredientItem('', 'VitaminC', '17.8mg')}.height(280).padding({ top: 30, right: 30, left: 30 })}
}

ContentTable组件全代码如下:

@Component
struct ContentTable {@BuilderIngredientItem(title:string, name: string, value: string) {Flex() {Text(title).fontSize(17.4).fontWeight(FontWeight.Bold).layoutWeight(1)Flex() {Text(name).fontSize(17.4).flexGrow(1)Text(value).fontSize(17.4)}.layoutWeight(2)}}build() {Flex({ direction: FlexDirection.Column,justifyContent: FlexAlign.SpaceBetween,alignItems: ItemAlign.Start }) {this.IngredientItem('Calories', 'Calories', '17kcal')this.IngredientItem('Nutrition', 'Protein', '0.9g')this.IngredientItem('', 'Fat', '0.2g')this.IngredientItem('', 'Carbohydrates', '3.9g')this.IngredientItem('', 'VitaminC', '17.8mg')}.height(280).padding({ top: 30, right: 30, left: 30 })}
}

Previewer:

本小节只是优化代码,实现效果与上一小节相同

四.结束语

Stack布局Flex布局已完成食物的图文展示和营养成分表,构建出了第一个普通视图的食物详情页

下一篇博文将继续跟随官网,开发食物分类列表页,并完成食物分类列表页面和食物详情页面的跳转和数据传递。

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

运行ps显示msvcp140.dll丢失怎么恢复?msvcp140.dll快速解决的4个不同方法

msvcp140.dll无法继续执行代码的主要原因有以下几点 系统缺失:msvcp140.dll是Visual Studio 2015编译的程序默认的库文件,如果系统中没有这个库文件,那么在运行相关程序时就会出现找不到msvcp140.dll的错误提示。 文件损坏:如果…

左支座零件的机械加工工艺规程及工艺装备设计【计算机辅助设计与制造CAD】

wx供重浩:创享日记 对话框发送:左支座 获取完整CAD工程源文件论文报告说明书等 一、论文目录 二、论文部分内容 设计任务 1.完成左支座零件—毛坯合图及左支座零件图 2.完成左支座零件工艺规程设计 3.完成左支座零件加工工艺卡 4.机床专用夹具装备总图 …

基于SSM的“鲜花”电子商务平台设计与实现

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…

YOLO免费数据集网站收集

目录 Roboflow Universe: Open Source Computer Vision Community Find Open Datasets and Machine Learning Projects | Kaggle ​编辑 【火焰和烟雾图像数据集】-计算机视觉数据集-极市开发者平台 (cvmart.net) 开放数据集- 飞桨AI Studio星河社区 - 人工智能学习与实训社…

AVL树和红黑树

AVL树和红黑树 一、AVL树1. 概念2. 原理AVL树节点的定义插入不违反AVL树性质违反AVL树性质左单旋右单旋左右双旋右左双旋总结 删除 3. 验证代码4. AVL树完整实现代码 二、红黑树1. 概念2. 性质3. 原理红黑树节点的定义默认约定插入情况一 (u存在且为红)情…

【机器学习13】生成对抗网络

1 GANs的基本思想和训练过程 生成器用于合成“假”样本, 判别器用于判断输入的样本是真实的还是合成的。 生成器从先验分布中采得随机信号,经过神经网络的变换, 得到模拟样本; 判别器既接收来自生成器的模拟样本, 也接…

SPASS-曲线估计

基本概念 曲线估计(曲线拟合、曲线回归)则是研究两变量间非线性关系的一种方法,选定一种用方程表达的曲线,使得实际数据与理论数据之间的差异尽可能地小。如果曲线选择得好,那么可以揭示因变量与自变量的内在关系&…

【最新Tomcat】IntelliJ IDEA通用配置Tomcat教程(超详细)

前言 IntelliJ IDEA是一个强大的集成开发环境,能够大大简化Java应用程序的开发和部署过程。而Tomcat作为一个流行的Java Web服务器,其与IntelliJ IDEA的整合能够提供便捷的开发环境,让开发人员更专注于代码的创作与优化。 在配置IntelliJ IDE…

【心得】基于flask的SSTI个人笔记

目录 计算PIN码 例题1 SSTI的引用链 例题2 SSTI利用条件: 渲染字符串可控,也就说模板的内容可控 我们通过模板 语法 {{ xxx }}相当于变相的执行了服务器上的python代码 利用render_template_string函数参数可控,或者部分可控 render_…

日志维护库:loguru

在复杂的项目中,了解程序的运行状态变得至关重要。在这个过程中,日志记录(logging)成为我们追踪、调试和了解代码执行的不可或缺的工具。在python语言中常用logging日志库,但是logging日志库使用相对繁琐,在…

创新案例|云服务平台HashiCorp是如何构建开源社区实现B2B增长飞轮

社区文化是HashiCorp企业文化的重要组成部分。虽然众多公司声称自己是社区驱动,但实际付诸行动的很少。与众不同的是,HashiCorp从一开始就将社区视为战略方针的核心,这也影响和塑造了公司今天的发展方向。社区不仅是执行策略之一,…

Java多线程(3)

Java多线程(3) 深入剖析Java线程的生命周期,探秘JVM的线程状态! 线程的生命周期 Java 线程的生命周期主要包括五个阶段:新建、就绪、运行、阻塞和销毁。 **新建(New):**线程对象通过 new 关键字创建&…