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

这篇具有很好参考价值的文章主要介绍了HarmonyOS学习路之开发篇—Java UI框架(自定义组件与布局 一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

HarmonyOS提供了一套复杂且强大的Java UI框架,其中Component提供内容显示,是界面中所有组件的基类。ComponentContainer作为容器容纳Component或ComponentContainer对象,并对它们进行布局。

Java UI框架也提供了一部分Component和ComponentContainer的具体子类,即常用的组件(比如:Text、Button、Image等)和常用的布局(比如:DirectionalLayout、DependentLayout等)。如果现有的组件和布局无法满足设计需求,例如仿遥控器的圆盘按钮、可滑动的环形控制器等,可以通过自定义组件和自定义布局来实现。

自定义组件是由开发者定义的具有一定特性的组件,通过扩展Component或其子类实现,可以精确控制屏幕元素的外观,也可响应用户的点击、触摸、长按等操作。

自定义布局是由开发者定义的具有特定布局规则的容器类组件,通过扩展ComponentContainer或其子类实现,可以将各子组件摆放到指定的位置,也可响应用户的滑动、拖拽等事件。

自定义组件

当Java UI框架提供的组件无法满足设计需求时,可以创建自定义组件,根据设计需求添加绘制任务,并定义组件的属性及事件响应,完成组件的自定义。

常用接口

接口名

作用

setEstimateSizeListener

设置测量组件的侦听器。

setEstimatedSize

设置测量的宽度和高度。

onEstimateSize

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

EstimateSpec.getChildSizeWithMode

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

EstimateSpec.getSize

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

EstimateSpec.getMode

获取该组件的显示模式。

addDrawTask

添加绘制任务。

onDraw

通过绘制任务更新组件时调用。

如何实现自定义组件

下面以自定义圆环组件为例,介绍自定义组件的通用配置方法:在屏幕中绘制圆环,并实现点击改变圆环颜色的功能。

在界面中显示的自定义圆环组件

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

1. 创建自定义组件的类,并继承Component或其子类,添加构造方法。

示例代码如下

public class CustomComponent extends Component{
    public CustomComponent(Context context) {
        this(context, null);
    }

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

2. 实现Component.EstimateSizeListener接口,在onEstimateSize方法中进行组件测量,并通过setEstimatedSize方法通知组件。

示例代码如下:

public class CustomComponent extends Component implements Component.EstimateSizeListener {
    //240为组件默认大小
    public int width = 240;
    public int height = 240;

    public CustomComponent(Context context, AttrSet attrSet) {
        ...
        // 设置测量组件的侦听器
        setEstimateSizeListener(this);
    }

    ...

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        int widthSpce = EstimateSpec.getMode(widthEstimateConfig);
        int heightSpce = EstimateSpec.getMode(heightEstimateConfig);

        int widthConfig = 0;
        switch (widthSpce) {
            case EstimateSpec.UNCONSTRAINT:
            case EstimateSpec.PRECISE:
                width = EstimateSpec.getSize(widthEstimateConfig);
                widthConfig = EstimateSpec.getSizeWithMode(width, EstimateSpec.PRECISE);
                break;
            case EstimateSpec.NOT_EXCEED:
                widthConfig = EstimateSpec.getSizeWithMode(width, EstimateSpec.PRECISE);
                break;
            default:
                break;
        }

        int heightConfig = 0;
        switch (heightSpce) {
            case EstimateSpec.UNCONSTRAINT:
            case EstimateSpec.PRECISE:
                height = EstimateSpec.getSize(heightEstimateConfig);
                heightConfig = EstimateSpec.getSizeWithMode(height, EstimateSpec.PRECISE);
                break;
            case EstimateSpec.NOT_EXCEED:
                heightConfig = EstimateSpec.getSizeWithMode(height, EstimateSpec.PRECISE);
                break;
            default:
                break;
        }
        setEstimatedSize(widthConfig, heightConfig);
        return true;
    }
}
  • 注意事项
    1. 自定义组件测量出的大小需通过setEstimatedSize通知组件,并且必须返回true使测量值生效。
    2. setEstimatedSize方法的入参携带模式信息,可使用Component.EstimateSpec.getSizeWithMode方法进行拼接。
  • 测量模式

    测量组件的宽高需要携带模式信息,不同测量模式下的测量结果也不相同,需要根据实际需求选择适合的测量模式。

        测量模式信息

模式

作用

UNCONSTRAINT

父组件对子组件没有约束,表示子组件可以任意大小。

PRECISE

父组件已确定子组件的大小。

NOT_EXCEED

已为子组件确定了最大大小,子组件不能超过指定大小。

3. 自定义xml属性,通过构造方法中携带的参数attrSet,可以获取到在xml中配置的属性值,并应用在该自定义组件中。

示例代码如下:

public class CustomComponent extends Component implements Component.EstimateSizeListener {
    private static final String ATTR_RING_WIDTH = "ring_width";

    private static final String ATTR_RING_RADIUS = "ring_radius";

    private static final String ATTR_DEFAULT_COLOR = "default_color";

    private static final String ATTR_PRESSED_COLOR = "pressed_color";

    public float ringWidth = 20f; //圆环宽度

    public float ringRadius = 100f; //圆环半径

    public Color defaultColor = Color.YELLOW; //默认颜色

    public Color pressedColor = Color.CYAN; //按压态颜色   
 
    public CustomComponent(Context context, AttrSet attrSet) {
     ...

    //初始化xml属性
        initAttrSet(attrSet);
    }

    private void initAttrSet(AttrSet attrSet) {
        if (attrSet == null) return;
        if (attrSet.getAttr(ATTR_DEFAULT_COLOR).isPresent()) {
            defaultColor = attrSet.getAttr(ATTR_DEFAULT_COLOR).get().getColorValue();
        }
        if (attrSet.getAttr(ATTR_RING_WIDTH).isPresent()) {
            ringWidth = attrSet.getAttr(ATTR_RING_WIDTH).get().getDimensionValue();
        }
        if (attrSet.getAttr(ATTR_RING_RADIUS).isPresent()) {
            ringRadius = attrSet.getAttr(ATTR_RING_RADIUS).get().getDimensionValue();
        }
        if (attrSet.getAttr(ATTR_PRESSED_COLOR).isPresent()) {
            pressedColor = attrSet.getAttr(ATTR_PRESSED_COLOR).get().getColorValue();
        }
    }   
}

4. 实现Component.DrawTask接口,在onDraw方法中执行绘制任务,该方法提供的画布Canvas,可以精确控制屏幕元素的外观。在执行绘制任务之前,需要定义画笔Paint。

示例代码如下:

public class CustomComponent extends Component implements Component.DrawTask,Component.EstimateSizeListener {
    // 绘制圆环的画笔
    private Paint circlePaint;    
    
    public CustomComponen(Context context, AttrSet attrSet) {
        ...

        // 初始化画笔
        initPaint();

        // 添加绘制任务
        addDrawTask(this);
    }

    private void initPaint(){
        circlePaint = new Paint();
        circlePaint.setColor(defaultColor);
        circlePaint.setStrokeWidth(ringWidth);
        circlePaint.setStyle(Paint.Style.STROKE_STYLE);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        int x = width / 2;
        int y = height / 2;
        canvas.drawCircle(x, y, ringRadius, circlePaint);
    }
    ...
}

5. 实现Component.TouchEventListener或其他事件的接口,使组件可响应用户输入。

示例代码如下

public class CustomComponent extends Component implements Component.DrawTask, Component.EstimateSizeListener, Component.TouchEventListener {
    ...
    public CustomComponent(Context context, AttrSet attrSet) {
        ...

        // 设置TouchEvent响应事件
        setTouchEventListener(this);
    }
    
    ...

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                circlePaint.setColor(pressedColor);
                invalidate();
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                circlePaint.setColor(defaultColor);
                invalidate();
                break;
        }
        return true;
    }
}

注意:

  1. 需要更新UI显示时,可调用invalidate()方法。
  2. 示例中展示TouchEventListener为响应触摸事件,除此之外还可实现ClickedListener响应点击事件、LongClickedListener响应长按事件等。

6. 在xml文件中创建并配置自定义组件

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

    <!-- 请根据实际包名和文件路径引入-->
    <com.huawei.harmonyosdemo.custom.CustomComponent
        ohos:height="300vp"
        ohos:width="match_parent"
        ohos:background_element="black"
        ohos:clickable="true"
        custom:default_color="gray"
        custom:pressed_color="red"
        custom:ring_width="20vp"
        custom:ring_radius="120vp"/>
</DirectionalLayout>

场景示例

利用自定义组件,绘制环形进度控制器,可通过滑动改变当前进度,也可响应进度的改变,UI显示的样式也可通过设置属性进行调整。

自定义环形进度控制器

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

示例代码如下:

public class CustomControlBar extends Component implements Component.DrawTask,
    Component.EstimateSizeListener, Component.TouchEventListener {
    private final static String ATTR_UN_FILL_COLOR = "unfill_color";

    private final static String ATTR_FILL_COLOR = "fill_color";

    private final static String ATTR_CIRCLE_WIDTH = "circle_width";

    private final static String ATTR_COUNT = "count";

    private final static String ATTR_CURRENT_PROGRESS = "current_progress";

    private final static String ATTR_SPLIT_SIZE = "split_size";

    private final static String ATTR_CIRCLE_RADIUS = "circle_radius";

    private final static String ATTR_CENTER_PIXELMAP = "center_pixelmap";

    private final static float CIRCLE_ANGLE = 360.0f;

    private final static int DEF_UNFILL_COLOR = 0xFF808080;

    private final static int DEF_FILL_COLOR = 0xFF1E90FF;

    public int width = 240;

    public int height = 240;

    // 圆环轨道颜色
    private Color unFillColor = new Color(DEF_UNFILL_COLOR);

    // 圆环覆盖颜色
    private Color fillColor = new Color(DEF_FILL_COLOR);

    // 圆环宽度
    private int circleWidth = 30;

    // 画笔
    private final Paint paint;

    // 个数
    private int count = 10;

    // 当前进度
    private int currentCount = 0;

    // 间隙值
    private int splitSize = 10;

    // 内圆的正切方形
    private final RectFloat centerRectFloat = new RectFloat();

    // 中心绘制的图片
    private PixelMap image = null;

    private int radius = 100;

    // 原点坐标
    private Point centerPoint;

    // 进度改变的事件响应
    private ProgressChangeListener listener;

    public CustomControlBar(Context context) {
        this(context, null);
    }

    public CustomControlBar(Context context, AttrSet attrSet) {
        super(context, attrSet);
        paint = new Paint();
        initAttrSet(attrSet);
        setEstimateSizeListener(this);
        if (!isClickable()) setClickable(true);
        setTouchEventListener(this);
        addDrawTask(this);
        listener = null;
    }

    // 初始化属性值
    private void initAttrSet(AttrSet attrSet) {
        if (attrSet == null) return;
        if (attrSet.getAttr(ATTR_UN_FILL_COLOR).isPresent()) {
            unFillColor = attrSet.getAttr(ATTR_UN_FILL_COLOR).get().getColorValue();
        }
        if (attrSet.getAttr(ATTR_FILL_COLOR).isPresent()) {
            fillColor = attrSet.getAttr(ATTR_FILL_COLOR).get().getColorValue();
        }
        if (attrSet.getAttr(ATTR_CIRCLE_WIDTH).isPresent()) {
            circleWidth = attrSet.getAttr(ATTR_CIRCLE_WIDTH).get().getDimensionValue();
        }
        if (attrSet.getAttr(ATTR_COUNT).isPresent()) {
            count = attrSet.getAttr(ATTR_COUNT).get().getIntegerValue();
        }
        if (attrSet.getAttr(ATTR_CURRENT_PROGRESS).isPresent()) {
            currentCount = attrSet.getAttr(ATTR_CURRENT_PROGRESS).get().getIntegerValue();
        }
        if (attrSet.getAttr(ATTR_SPLIT_SIZE).isPresent()) {
            splitSize = attrSet.getAttr(ATTR_SPLIT_SIZE).get().getIntegerValue();
        }
        if (attrSet.getAttr(ATTR_CIRCLE_RADIUS).isPresent()) {
            radius = attrSet.getAttr(ATTR_CIRCLE_RADIUS).get().getDimensionValue();
        }
        if (attrSet.getAttr(ATTR_CENTER_PIXELMAP).isPresent()) {
            Element element = attrSet.getAttr(ATTR_CENTER_PIXELMAP).get().getElement();
            if (element instanceof PixelMapElement) {
                image = ((PixelMapElement) element).getPixelMap();
            }
        }
    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        int widthSpce = EstimateSpec.getMode(widthEstimateConfig);
        int heightSpce = EstimateSpec.getMode(heightEstimateConfig);

        int widthConfig = 0;
        switch (widthSpce) {
            case EstimateSpec.UNCONSTRAINT:
            case EstimateSpec.PRECISE:
                width = EstimateSpec.getSize(widthEstimateConfig);
                widthConfig = EstimateSpec.getSizeWithMode(width, EstimateSpec.PRECISE);
                break;
            case EstimateSpec.NOT_EXCEED:
                widthConfig = EstimateSpec.getSizeWithMode(width, EstimateSpec.PRECISE);
                break;
            default:
                break;
        }

        int heightConfig = 0;
        switch (heightSpce) {
            case EstimateSpec.UNCONSTRAINT:
            case EstimateSpec.PRECISE:
                height = EstimateSpec.getSize(heightEstimateConfig);
                heightConfig = EstimateSpec.getSizeWithMode(height, EstimateSpec.PRECISE);
                break;
            case EstimateSpec.NOT_EXCEED:
                heightConfig = EstimateSpec.getSizeWithMode(height, EstimateSpec.PRECISE);
                break;
            default:
                break;
        }
        System.out.println("WYT_width:" + width + "   height:" + height + "     width_spec:" + widthSpce + "     height_spec:" + heightSpce);
        setEstimatedSize(widthConfig, heightConfig);
        return true;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        paint.setAntiAlias(true);
        paint.setStrokeWidth(circleWidth);
        paint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        paint.setStyle(Paint.Style.STROKE_STYLE);
        int min = Math.min(width, height);
        radius = (min >> 1) - circleWidth;
        centerPoint = new Point(width >> 1, height >> 1);
        drawCount(canvas);
        if (image != null) {
            int inRadius = radius - (circleWidth >> 1);
            centerRectFloat.left = (float) (width / 2 - Math.sqrt(2) * inRadius);
            centerRectFloat.top = (float) (height / 2 - Math.sqrt(2) * inRadius);
            centerRectFloat.right = (float) (width / 2 + Math.sqrt(2) * inRadius);
            centerRectFloat.bottom = (float) (height / 2 + Math.sqrt(2) * inRadius);

            // 如果图片比较小,那么根据图片的尺寸放置到正中心
            Size imageSize = image.getImageInfo().size;
            if (imageSize.width < Math.sqrt(2) * inRadius) {
                centerRectFloat.left = (width - imageSize.width * 1.0f) / 2;
                centerRectFloat.top = (height - imageSize.height * 1.0f) / 2;
                centerRectFloat.right = (width + imageSize.width * 1.0f) / 2;
                centerRectFloat.bottom = (height + imageSize.height * 1.0f) / 2;
            }
            canvas.drawPixelMapHolderRect(new PixelMapHolder(image), centerRectFloat, paint);
        }
    }

    private void drawCount(Canvas canvas) {
        float itemSize = (CIRCLE_ANGLE - count * splitSize) / count;

        RectFloat oval = new RectFloat(centerPoint.getPointX() - radius, centerPoint.getPointY() - radius,
            centerPoint.getPointX() + radius, centerPoint.getPointY() + radius);

        paint.setColor(unFillColor);
        for (int i = 0; i < count; i++) {
            Arc arc = new Arc((i * (itemSize + splitSize)) - 90, itemSize, false);
            canvas.drawArc(oval, arc, paint);
        }

        paint.setColor(fillColor);
        for (int i = 0; i < currentCount; i++) {
            Arc arc = new Arc((i * (itemSize + splitSize)) - 90, itemSize, false);
            canvas.drawArc(oval, arc, paint);
        }
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
            case TouchEvent.POINT_MOVE:
                MmiPoint absPoint = touchEvent.getPointerPosition(touchEvent.getIndex());
                Point point = new Point(absPoint.getX(), absPoint.getY());
                System.out.println("wyt_centerPoint:" + centerPoint + "   point:" + point);
                double angle = calcRotationAngleInDegrees(centerPoint, point);
                double multiple = angle / (CIRCLE_ANGLE / count);
                if ((multiple - (int) multiple) > 0.4) {
                    currentCount = (int) multiple + 1;
                } else {
                    currentCount = (int) multiple;
                }
                if (listener != null) {
                    listener.onProgressChangeListener(currentCount);
                }
                invalidate();
                break;
        }
        return true;
    }

    public interface ProgressChangeListener {
        void onProgressChangeListener(int Progress);
    }

    // 计算centerPt到targetPt的夹角,单位为度。返回范围为[0, 360),顺时针旋转。
    private double calcRotationAngleInDegrees(Point centerPt, Point targetPt) {
        double theta = Math.atan2(targetPt.getPointY()
            - centerPt.getPointY(), targetPt.getPointX()
            - centerPt.getPointX());
        theta += Math.PI / 2.0;
        double angle = Math.toDegrees(theta);
        if (angle < 0) {
            angle += CIRCLE_ANGLE;
        }
        return angle;
    }

    public Color getUnFillColor() {
        return unFillColor;
    }

    public CustomControlBar setUnFillColor(Color unFillColor) {
        this.unFillColor = unFillColor;
        return this;
    }

    public Color getFillColor() {
        return fillColor;
    }

    public CustomControlBar setFillColor(Color fillColor) {
        this.fillColor = fillColor;
        return this;
    }

    public int getCircleWidth() {
        return circleWidth;
    }

    public CustomControlBar setCircleWidth(int circleWidth) {
        this.circleWidth = circleWidth;
        return this;
    }

    public int getCount() {
        return count;
    }

    public CustomControlBar setCount(int count) {
        this.count = count;
        return this;
    }

    public int getCurrentCount() {
        return currentCount;
    }

    public CustomControlBar setCurrentCount(int currentCount) {
        this.currentCount = currentCount;
        return this;
    }

    public int getSplitSize() {
        return splitSize;
    }

    public CustomControlBar setSplitSize(int splitSize) {
        this.splitSize = splitSize;
        return this;
    }

    public PixelMap getImage() {
        return image;
    }

    public CustomControlBar setImage(PixelMap image) {
        this.image = image;
        return this;
    }

    public void build() {
        invalidate();
    }

    public void setProgressChangerListener(ProgressChangeListener listener) {
        this.listener = listener;
    }
}

 在xml中创建该自定义组件,并设置其属性。文章来源地址https://www.toymoban.com/news/detail-489858.html

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    xmlns:custom="http://schemas.huawei.com/res/custom"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:orientation="vertical">
   
    <!-- 请根据实际包名和文件路径引入-->
    <com.huawei.harmonyosdemo.custom.CustomControlBar
        ohos:id="$+id:custom_control_bar"
        ohos:height="200vp"
        ohos:width="match_parent"
        ohos:background_element="black"
        ohos:top_margin="50vp"
        custom:center_pixelmap="$media:icon"
        custom:circle_radius="80vp"
        custom:circle_width="15vp"
        custom:count="10"
        custom:current_progress="5"
        custom:fill_color="#1e90ff"
        custom:split_size="13"
        custom:unfill_color="gray"/>  
</DirectionalLayout>

到了这里,关于HarmonyOS学习路之开发篇—Java UI框架(自定义组件与布局 一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • HarmonyOS学习路之方舟开发框架—方舟开发框架(ArkUI)概述

    方舟开发框架(简称ArkUI)为HarmonyOS应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能(组件、布局、动画以及交互事件),以及实时界面预览工具等,可以支持开发者进行可视化界面开发。 UI: 即用户界面。开发者可以将应用的用户界面设计为多个功能

    2024年02月16日
    浏览(49)
  • HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 一)

    ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在 TypeScript (简称 TS )生态基础上做了进一步扩展,继承了 TS 的所有特性,是 TS 的超集。因此,在学习 ArkTS 语言之前,建议开发者具备 TS 语言开发能力。 当前, ArkTS 在 TS 的基础上主要扩展了如下能力: 基本语法:

    2024年02月16日
    浏览(69)
  • HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 五)

    如果每个组件的样式都需要单独设置,在开发过程中会出现大量代码在进行重复样式设置,虽然可以复制粘贴,但为了代码简洁性和后续方便维护,我们推出了可以提炼公共样式进行复用的装饰器@Styles。 @Styles装饰器可以将多条样式设置提炼成一个方法,直接在组件声明的位

    2024年02月17日
    浏览(55)
  • HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 三)

    在开始之前,先明确自定义组件和页面的关系: 自定义组件: @Component 装饰的 UI 单元,可以组合多个系统组件实现 UI 的复用。 页面:即应用的 UI 页面。可以由一个或者多个自定义组件组成, @Entry 装饰的自定义组件为页面的入口组件,即页面的根节点,一个页面有且仅能有

    2024年02月16日
    浏览(62)
  • HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 二)

    在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。在进行 UI 界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离,后续版本演进等因素。因此,将UI和部分业务逻辑封装成

    2024年02月04日
    浏览(54)
  • HarmonyOS学习路之方舟开发框架—学习ArkTS语言(基本语法 四)

    当创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题,ArkUI引入了@BuilderParam装饰器,@BuilderParam用来装饰指向@Builder方法的变量

    2024年02月17日
    浏览(53)
  • HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 六)

    AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。 和LocalStorage不同的是,LocalStorage是页面级的,通常应用于页面内的数据共享。而对于AppStorage,是应用级的全局状态共享。 AppStorage是在应用启动

    2024年02月20日
    浏览(54)
  • HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 二)

    @Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。 @Prop装饰的变量和父组件建立单向的同步关系: @Prop变量允许在本地修改,但修改后的变化不会同步回父组件。 当父组件中的数据源更改时,与之相关的@Prop装饰的变

    2024年02月14日
    浏览(48)
  • HarmonyOS学习路之开发篇—流转

    随着全场景多设备生活方式的不断深入,用户拥有的设备越来越多,每个设备都能在适合的场景下提供良好的体验,例如:手表可以提供及时的信息查看能力,电视可以带来沉浸的观影体验。但是,每个设备也有使用场景的局限,例如:在电视上输入文本相对手机来说是非常

    2024年02月15日
    浏览(46)
  • HarmonyOS鸿蒙基于Java开发: Java UI 自定义布局

    当Java UI框架提供的布局无法满足需求时,可以创建自定义布局,根据需求自定义布局规则。 Component类相关接口  表1  Component类相关接口 接口名称 作用 setEstimateSizeListener 设置测量组件的侦听器 setEstimatedSize 设置测量的宽度和高度 onEstimateSize 测量组件的大小以确定宽度和高度

    2024年02月19日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包