HarmonyOS学习路之开发篇—Java UI框架(自定义组件与布局 二)

news2024/12/23 14:56:18

自定义布局

当Java UI框架提供的布局无法满足需求时,可以创建自定义布局,根据需求自定义布局规则

常用接口

Component类相关接口

接口名称

作用

setEstimateSizeListener

设置测量组件的侦听器

setEstimatedSize

设置测量的宽度和高度

onEstimateSize

测量组件的大小以确定宽度和高度。

EstimateSpec.getChildSizeWithMode

基于指定的大小和模式为子组件创建度量规范。

EstimateSpec.getSize

从提供的度量规范中提取大小。

EstimateSpec.getMode

获取该组件的显示模式。

arrange

相对于容器组件设置组件的位置和大小

ComponentContainer类相关接口

接口名称

作用

setArrangeListener

设置容器组件布局子组件的侦听器

onArrange

通知容器组件在布局时设置子组件的位置和大小

如何实现自定义布局

使用自定义布局,实现子组件自动换行功能。

自定义布局的使用效果

 1. 创建自定义布局的类,并继承ComponentContainer,添加构造方法。

public class CustomLayout extends ComponentContainer {
    public CustomLayout(Context context) {
        this(context, null);
    }

    //如需支持xml创建自定义布局,必须添加该构造方法
    public CustomLayout(Context context, AttrSet attrSet) {
        super(context, attrSet);
    }
}

2. 实现ComponentContainer.EstimateSizeListener接口,在onEstimateSize方法中进行测量。

public class CustomLayout extends ComponentContainer
    implements ComponentContainer.EstimateSizeListener {

    ...

    public CustomLayout(Context context, AttrSet attrSet) {

        ...
        setEstimateSizeListener(this);
    }
    
    @Override
    public boolean onEstimateSize(int widthEstimatedConfig, int heightEstimatedConfig) {
        invalidateValues();

        //通知子组件进行测量
        measureChildren(widthEstimatedConfig, heightEstimatedConfig);

        //关联子组件的索引与其布局数据
        for (int idx = 0; idx < getChildCount(); idx++) {
            Component childView = getComponentAt(idx);
            addChild(childView, idx, EstimateSpec.getSize(widthEstimatedConfig));
        }

        //测量自身
        measureSelf(widthEstimatedConfig, heightEstimatedConfig);
        return true;
    }
    
    private void measureChildren(int widthEstimatedConfig, int heightEstimatedConfig) {
        for (int idx = 0; idx < getChildCount(); idx++) {
            Component childView = getComponentAt(idx);
            if (childView != null) {
                LayoutConfig lc = childView.getLayoutConfig();
                int childWidthMeasureSpec;
                int childHeightMeasureSpec;

                if (lc.width == LayoutConfig.MATCH_CONTENT) {
                    childWidthMeasureSpec = EstimateSpec.getSizeWithMode(lc.width, EstimateSpec.NOT_EXCEED);
                } else if (lc.width == LayoutConfig.MATCH_PARENT) {
                    int parentWidth = EstimateSpec.getSize(widthEstimatedConfig);
                    int childWidth = parentWidth - childView.getMarginLeft() - childView.getMarginRight();
                    childWidthMeasureSpec = EstimateSpec.getSizeWithMode(childWidth, EstimateSpec.PRECISE);
                } else {
                    childWidthMeasureSpec = EstimateSpec.getSizeWithMode(lc.width, EstimateSpec.PRECISE);
                }

                if (lc.height == LayoutConfig.MATCH_CONTENT) {
                    childHeightMeasureSpec = EstimateSpec.getSizeWithMode(lc.height, EstimateSpec.NOT_EXCEED);
                } else if (lc.height == LayoutConfig.MATCH_PARENT) {
                    int parentHeight = EstimateSpec.getSize(heightEstimatedConfig);
                    int childHeight = parentHeight - childView.getMarginTop() - childView.getMarginBottom();
                    childHeightMeasureSpec = EstimateSpec.getSizeWithMode(childHeight, EstimateSpec.PRECISE);
                } else {
                    childHeightMeasureSpec = EstimateSpec.getSizeWithMode(lc.height, EstimateSpec.PRECISE);
                }
                childView.estimateSize(childWidthMeasureSpec, childHeightMeasureSpec);
            }
        }
    }

    private void measureSelf(int widthEstimatedConfig, int heightEstimatedConfig) {
        int widthSpce = EstimateSpec.getMode(widthEstimatedConfig);
        int heightSpce = EstimateSpec.getMode(heightEstimatedConfig);
        int widthConfig = 0;
        switch (widthSpce) {
            case EstimateSpec.UNCONSTRAINT:
            case EstimateSpec.PRECISE:
                int width = EstimateSpec.getSize(widthEstimatedConfig);
                widthConfig = EstimateSpec.getSizeWithMode(width, EstimateSpec.PRECISE);
                break;
            case EstimateSpec.NOT_EXCEED:
                widthConfig = EstimateSpec.getSizeWithMode(maxWidth, EstimateSpec.PRECISE);
                break;
            default:
                break;
        }

        int heightConfig = 0;
        switch (heightSpce) {
            case EstimateSpec.UNCONSTRAINT:
            case EstimateSpec.PRECISE:
                int height = EstimateSpec.getSize(heightEstimatedConfig);
                heightConfig = EstimateSpec.getSizeWithMode(height, EstimateSpec.PRECISE);
                break;
            case EstimateSpec.NOT_EXCEED:
                heightConfig = EstimateSpec.getSizeWithMode(maxHeight, EstimateSpec.PRECISE);
                break;
            default:
                break;
        }
        setEstimatedSize(widthConfig, heightConfig);
    }
}

注意:

  1. 容器类组件在自定义测量过程不仅要测量自身,也要递归的通知各子组件进行测量。
  2. 测量出的大小需通过setEstimatedSize通知组件,并且必须返回true使测量值生效。

3. 测量时,需要确定每个子组件大小和位置的数据,并保存这些数据。

    private int xx = 0;

    private int yy = 0;

    private int maxWidth = 0;

    private int maxHeight = 0;

    private int lastHeight = 0;

    // 子组件索引与其布局数据的集合
    private final Map<Integer, Layout> axis = new HashMap<>();

    private static class Layout {
        int positionX = 0;
        int positionY = 0;
        int width = 0;
        int height = 0;
    }

    ...

    private void invalidateValues() {
        xx = 0;
        yy = 0;
        maxWidth = 0;
        maxHeight = 0;
        axis.clear();
    }
    private void addChild(Component component, int id, int layoutWidth) {
        Layout layout = new Layout();
        layout.positionX = xx + component.getMarginLeft();
        layout.positionY = yy + component.getMarginTop();
        layout.width = component.getEstimatedWidth();
        layout.height = component.getEstimatedHeight();
        if ((xx + layout.width) > layoutWidth) {
            xx = 0;
            yy += lastHeight;
            lastHeight = 0;
            layout.positionX = xx + component.getMarginLeft();
            layout.positionY = yy + component.getMarginTop();
        }
        axis.put(id, layout);
        lastHeight = Math.max(lastHeight, layout.height + component.getMarginBottom());
        xx += layout.width + component.getMarginRight();
        maxWidth = Math.max(maxWidth, layout.positionX + layout.width + component.getMarginRight());
        maxHeight = Math.max(maxHeight, layout.positionY + layout.height + component.getMarginBottom());
    }

4. 实现ComponentContainer.ArrangeListener接口,在onArrange方法中排列子组件。

public class CustomLayout extends ComponentContainer
    implements ComponentContainer.EstimateSizeListener,
    ComponentContainer.ArrangeListener {

    ...
    
    public CustomLayout(Context context
, AttrSet attrSet
) {

        ...
        setArrangeListener(this);
    }
    @Override
    public boolean onArrange(int left, int top, int width, int height) {

        // 对各个子组件进行布局
        for (int idx = 0; idx < getChildCount(); idx++) {
            Component childView = getComponentAt(idx);
            Layout layout = axis.get(idx);
            if (layout != null) {
                childView.arrange(layout.positionX, layout.positionY, layout.width, layout.height);
            }
        }
        return true;
    }
}

5. 在xml文件中创建此布局,并添加若干子组件。

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">

    <!--请根据实际包名与文件路径引入-->
    <com.huawei.harmonyosdemo.custom.CustomLayout
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:background_element="#555555">

        <Text
            ohos:height="200"
            ohos:width="match_parent"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="match_parent * 200"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>

        <Text
            ohos:height="100"
            ohos:width="300"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="item2"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>

        <Text
            ohos:height="100"
            ohos:width="300"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="item3"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>

        <Text
            ohos:height="100"
            ohos:width="300"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="item4"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>

        <Text
            ohos:height="100"
            ohos:width="500"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="500 * 100"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>

        <Text
            ohos:height="100"
            ohos:width="300"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="item6"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>

        <Text
            ohos:height="600"
            ohos:width="600"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="600 * 600"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>
        <Text
            ohos:height="100"
            ohos:width="300"
            ohos:background_element="#727272"
            ohos:margin="10"
            ohos:text="item8"
            ohos:text_alignment="center"
            ohos:text_color="white"
            ohos:text_size="40"/>
    </com.huawei.harmonyosdemo.custom.CustomLayout>
</DirectionalLayout>

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

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

相关文章

极速了解GPT生态

第一部分&#xff1a; 1、chatGPT:一个大语言模型&#xff0c;可以通过API去访问&#xff0c;下面很多是根据API去访问&#xff0c;然后来进行集成。 2、Vector store&#xff0c;你也可以叫是Vector search&#xff0c;主要目就是存储各种向量&#xff0c;然后去计算向量的各…

【Linux】基础IO——文件描述符:缓冲区的理解

上个月学校考试&#xff0c;进行课程复习&#xff0c;一直没有更新博客&#xff0c;现考试结束&#xff0c;继续保持更新&#xff0c;欢迎大家关注&#xff01; 目录 1 模仿C库自主封装简单的文件接口2 对缓冲区的理解2.1 数据刷新到磁盘的过程分析2.2 如何强制刷新内核 1 模仿…

00后是真的卷不过,工作没两年,跳槽到我们公司起薪17K都快接近我了

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&…

go+vue自建运维管理平台

文章目录 鲁班运维平台容器管理集群管理namespace管理节点管理工作负载存储管理网络管理配置管理事件中心 kuboard 鲁班运维平台 这个平台和spug很像&#xff0c;感觉就像是spug运维平台的容器版本。 但是如果是容器平台则选择的余地很大&#xff0c;优秀的如kubersphere、kub…

NeRF+SLAM论文阅读笔记

CVPR 2023 Co-SLAM: Joint Coordinate and Sparse Parametric Encodings for Neural Real-Time SLAM input&#xff1a; RGB-D contribution&#xff1a; 1.场景表示&#xff1a;多分辨率哈希网格&#xff08;加速&保留高频特征&#xff09; 2.编码方式&#xff1a;one-b…

STM32 实现简单定时任务调度器,动态创建任务,两种思路实现流水灯

代码实现和硬件没关系&#xff0c;所以并不限于STM32&#xff0c;Arduino 之类的其他地方也能用&#xff0c;只要有一个能获取时间的函数就行&#xff0c;或者说&#xff0c;只要有一个会随着时间自动增加的变量就行&#xff0c;时间单位无所谓&#xff0c;所以确实想的话&…

排它锁和共享锁.md

介绍 排它锁&#xff08;Exclusive&#xff09;&#xff0c;又称为X 锁&#xff0c;写锁。 共享锁&#xff08;Shared&#xff09;&#xff0c;又称为S 锁&#xff0c;读锁。 X和S锁之间有以下的关系&#xff1a; SS可以兼容的&#xff0c;XS、SX、XX之间是互斥的 显式加锁…

Django-带参数的路由编写(一)【不用正则表达式匹配的简单带参数路由】

在某urls.py文件有如下的路由配置语句&#xff1a; urlpatterns [path(app2/show/<int:id>/,views.show_id), ]语句&#xff1a; path(app2/show/<int:id>/,views.show_id),中的<int:id>就是带参数的URL中的参数部分&#xff0c;其语法格式如下&#xff1a…

PPT中如何做出透视圆的效果?

看两个例子 一个是上部这种垂直的圆环。 一个是下部这种圆。 它们都据有一定的透视感,上部用于表示流量,下部用于表示出“某一领域”的意镜。 向下延展的圆环透视效果 先说这个扁平的圆的例子,它有4个圆,画的技巧如下: 就是4个圆环;把4个圆环互相叠加;把上和下在“中…

2023年网络安全保姆级入门学习路线,建议收藏!

作为一个工作多年的网络安全渗透工程师&#xff0c;我知道对于零基础小白来说&#xff0c;网络安全可能是一个非常陌生而且有些恐怖的领域。但是不用担心&#xff0c;只要你愿意花费时间和精力去学习&#xff0c;你也能成为一个优秀的网络安全专家。 网络安全学习路线 首先&a…

顺序队列和链队列

队列也是一种线性结构&#xff0c;不同于栈的是队列为先进先出的数据结构&#xff0c;遵循一边入队一边出队。 顺序队列的底层使用的是数组&#xff0c;因此需预先申请一块足够大的内存空间初始化顺序队列。除此之外&#xff0c;为了满足顺序队列中数据从队尾进&#xff0c;队头…

接口测试和功能测试的区别

目录 前言&#xff1a; 一、测试目的不同 二、测试内容不同 三、测试重点不同 四、总结 前言&#xff1a; 接口测试和功能测试是软件测试中的两种不同类型。接口测试侧重于测试不同模块之间的接口&#xff0c;而功能测试则注重测试完整的业务功能。 一、测试目的不同 接…

Vue中如何进行文件打印与PDF导出

Vue中如何进行文件打印与PDF导出 在Vue应用中&#xff0c;有时候需要将页面内容打印出来或者导出为PDF格式&#xff0c;以满足用户的需求。本文将介绍如何在Vue应用中实现文件打印和PDF导出的功能。 文件打印 文件打印是指将页面内容输出到打印机上&#xff0c;将其打印成纸质…

Vue中如何进行地图热点展示与交互(如热力图)

Vue中如何进行地图热点展示与交互&#xff08;如热力图&#xff09; 随着大数据和可视化技术的发展&#xff0c;地图热点展示越来越受到人们的关注。在Vue应用中&#xff0c;我们通常需要实现地图热点的展示和交互&#xff0c;以便更好地呈现数据和分析结果。本文将介绍在Vue中…

MySQL的高级操作(每一次「欢喜」都值得纪念)

文章目录 一、案例扩展二、克隆表1、方法一2、方法二 三、清空表四、创建临时表七、补充七、补充 一、案例扩展 use kgc; create table if not exists info ( id int(4) zerofill primary key auto_increment, #指定主键的第二种方式 name varchar(10) not null default 匿…

eclipse中java代码在控制台输出的中文内容是乱码怎么解决

eclipse中创建了一个maven工程&#xff0c;用System.out在控制台输出内容&#xff0c;但中文内容显示乱码&#xff1a; 解决方法&#xff1a; 右键单击工程&#xff0c;选择Run As->Run Configurations: 点击Common这个tab页&#xff0c;Encoding选择Use system encoding&…

分布式定时任务框架 PowerJob

业务背景 1.1 为什么需要使用定时任务调度 &#xff08;1&#xff09;时间驱动处理场景&#xff1a;整点发送优惠券&#xff0c;每天更新收益&#xff0c;每天刷新标签数据和人群数据。 &#xff08;2&#xff09;批量处理数据&#xff1a;按月批量统计报表数据&#xff0c;批…

vue练习

附加练习-1.帅哥美女走一走 目标: 点击按钮, 改变3个li的顺序, 在头上的就到末尾. 提示: 操作数组里的顺序, v-for就会重新渲染li 代码演示 <template><div><ul><li v-for"item in myArr" :key"item">{{ item }}</li></…

GCC命令与参数详解

GCC 命令与参数详解 无论是 C 还是 C 程序&#xff0c;将其从源代码转变为可执行代码的过程&#xff0c;具体可分为预处理 Preprocessing&#xff0c;编译 Compilation&#xff0c;汇编 Assembly&#xff0c;链接 Linking 这四个阶段。 默认情况下 GCC 指令会直接将源代码历经…

websocket实时通信【纯后端——JAVA】

本文主要介绍一下websoket的实时通信&#xff0c;这里只有java的代码&#xff0c;通过在线网站 http://www.websocket-test.com/测试即可 1. 导包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocke…