花粉乐分享平台宣传视频
> 华为资讯 > 华为资讯 > 鸿蒙编程 > 4.10「HarmonyOS鸿蒙开发」自定义布局
4.10「HarmonyOS鸿蒙开发」自定义布局
来源:RubyHan
2022-08-19 20:24:38
745
管理
4.10【HarmonyOS鸿蒙开发】自定义布局
作者:韩茹 公司:程序咖(北京)科技有限公司 鸿蒙巴士专栏作家
当Java UI框架提供的布局无法满足设计需求时,可以创建自定义布局,根据需求自定义布局规则。 一、常用接口 Component类相关接口
接口名称 作用
setEstimateSizeListener 设置测量组件的侦听器。
onEstimateSize 测量组件的大小以确定宽度和高度。
setEstimatedSize 将测量的宽度和高度设置给组件。
EstimateSpec.getChildSizeWithMode 基于指定的大小和模式为子组件创建度量规范。
EstimateSpec.getSize 从提供的度量规范中提取大小。
EstimateSpec.getMode 获取该组件的显示模式。
arrange 相对于容器组件设置组件的位置和大小。

ComponentContainer类相关接口
接口名称 作用
setArrangeListener 设置容器组件布局子组件的侦听器。
onArrange 通知容器组件在布局时设置子组件的位置和大小。
二、如何实现自定义布局 使用自定义布局,将各子组件摆放到指定的位置。
  1. 创建自定义布局的类,并继承ComponentContainer,添加构造方法。
public class CustomLayout extends ComponentContainer { public CustomLayout(Context context) { super(context); }}
  1. 实现ComponentContainer.EstimateSizeListener接口,在onEstimateSize方法中进行测量。
public class CustomLayout extends ComponentContainer implements ComponentContainer.EstimateSizeListener { ... public CustomLayout(Context context) { ... setEstimateSizeListener(this); } @Override public boolean onEstimateSize(int widthEstimatedConfig, int heightEstimatedConfig) { // 通知子组件进行测量 measureChildren(widthEstimatedConfig, heightEstimatedConfig); int width = Component.EstimateSpec.getSize(widthEstimatedConfig); // 关联子组件的索引与其布局数据 for (int idx = 0; idx < getChildCount(); idx ) { Component childView = getComponentAt(idx); addChild(childView, idx, width); } setEstimatedSize( Component.EstimateSpec.getChildSizeWithMode(maxWidth, widthEstimatedConfig, 0), Component.EstimateSpec.getChildSizeWithMode(maxHeight, heightEstimatedConfig, 0)); return true; } private void measureChildren(int widthEstimatedConfig, int heightEstimatedConfig) { for (int idx = 0; idx < getChildCount(); idx ) { Component childView = getComponentAt(idx); if (childView != null) { measureChild(childView, widthEstimatedConfig, heightEstimatedConfig); } } } private void measureChild(Component child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { ComponentContainer.LayoutConfig lc = child.getLayoutConfig(); int childWidthMeasureSpec = EstimateSpec.getChildSizeWithMode( lc.width, parentWidthMeasureSpec, EstimateSpec.UNCONSTRAINT); int childHeightMeasureSpec = EstimateSpec.getChildSizeWithMode( lc.height, parentHeightMeasureSpec, EstimateSpec.UNCONSTRAINT); child.estimateSize(childWidthMeasureSpec, childHeightMeasureSpec); }}
  • 注意事项容器类组件在自定义测量过程不仅要测量自身,也要递归的通知各子组件进行测量。测量出的大小需通过setEstimatedSize设置给组件,并且必须返回true使测量值生效。
  1. 测量时,需要确定每个子组件大小和位置的数据,并保存这些数据。
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); maxHeight = Math.max(maxHeight, layout.positionY layout.height); }
  1. 实现ComponentContainer.ArrangeListener接口,在onArrange方法中排列子组件。
public class CustomLayout extends ComponentContainer implements ComponentContainer.EstimateSizeListener, ComponentContainer.ArrangeListener { ... public CustomLayout(Context context) { ... 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; }}
  1. 在onStart方法中添加此布局,在布局中添加若干子组件,并在界面中显示。
package com.example.hanrucustomlayout.slice;import ohos.aafwk.ability.AbilitySlice;import ohos.aafwk.content.Intent;import ohos.agp.colors.RgbColor;import ohos.agp.components.Button;import ohos.agp.components.Component;import ohos.agp.components.DirectionalLayout;import ohos.agp.components.element.ShapeElement;import ohos.agp.utils.Color;public class MainAbilitySlice extends AbilitySlice { @Override public void onStart(Intent intent) { super.onStart(intent);// super.setUIContent(ResourceTable.Layout_ability_main); DirectionalLayout myLayout= new DirectionalLayout(getContext()); DirectionalLayout.LayoutConfig config = new DirectionalLayout.LayoutConfig( DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_PARENT); myLayout.setLayoutConfig(config); CustomLayout customLayout = new CustomLayout(this); for (int idx = 0; idx < 15; idx ) { System.out.println("--->" idx); customLayout.addComponent(getComponent(idx 1)); } ShapeElement shapeElement = new ShapeElement(); RgbColor COLOR_LAYOUT_BG = new RgbColor(85,85,85); shapeElement.setRgbColor(COLOR_LAYOUT_BG); customLayout.setBackground(shapeElement); DirectionalLayout.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig(DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_CONTENT); customLayout.setLayoutConfig(layoutConfig); myLayout.addComponent(customLayout); super.setUIContent(myLayout); } //创建子组件 private Component getComponent(int idx) { Button button = new Button(getContext()); ShapeElement shapeElement = new ShapeElement(); RgbColor COLOR_BTN_BG = new RgbColor(114,114,114); shapeElement.setRgbColor(COLOR_BTN_BG); button.setBackground(shapeElement); button.setTextColor(Color.WHITE); DirectionalLayout.LayoutConfig layoutConfig = new DirectionalLayout.LayoutConfig(300, 100); if (idx == 1) { layoutConfig = new DirectionalLayout.LayoutConfig(1080, 200); button.setText("1080 * 200"); } else if (idx == 6) { layoutConfig = new DirectionalLayout.LayoutConfig(500, 100); button.setText("500 * 100"); } else if (idx == 8) { layoutConfig = new DirectionalLayout.LayoutConfig(600, 600); button.setText("600 * 600"); } else { button.setText("Item" idx); } layoutConfig.setMargins(10, 10, 10, 10); button.setLayoutConfig(layoutConfig); return button; }} 效果图:

花粉社群VIP加油站

2
点赞
赏礼
赏钱
0
收藏
免责声明:本文仅代表作者个人观点,与花粉乐分享无关。其原创性以及文中陈述文字和内容未经本网证实,对本文以及其中全部或者 部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
凡本网注明 “来源:XXX(非花粉乐分享)”的作品,均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对 其真实性负责。
如因作品内容、版权和其它问题需要同本网联系的,请在一周内进行,以便我们及时处理。
QQ:2443165046 邮箱:info@hflfx.com
关于作者
华为乐分享..(万蜂敬仰)
文章
461
主题
0
关注
0
粉丝
0
点击领取今天的签到奖励!
签到排行
随手拍
54个圈友 0个话题
华为手机随手拍,记录生活点滴之美好
华为P30pro
51个圈友 0个话题
这里是华为P30pro手机交流圈,欢迎华为P30pro用户进群交流
体验官
60个圈友 2个话题
华为花粉体验官,体验官专属的交流群
登录后查看您创建的圈子
登录后查看您创建的圈子
所有圈子
杭州互联网违法和不良信息举报平台 网络110报警服务 浙ICP备17046585号
2
0
分享
请选择要切换的马甲:

个人中心

每日签到

我的消息

内容搜索