在 UI 设计中,圆环(Ring)是一种常见的视觉元素,用以展示进度、刻度或装饰效果。通过组合现有的 Circle 组件,我们可以轻松地实现一个可定制的圆环控件,并支持外部传参来设置半径、环宽、环色及填充色。下面将分步介绍如何创建这样一个自定义组件。


1. 创建 Ring 组件骨架

首先,定义一个导出的组件 Ring,让系统识别它并生成相应的生命周期钩子。

@Component export 
struct Ring {
  build() {
    // 待填充:组合布局
  }
}
  • @Component:标记这是一个组件,必须实现 build()
  • export:允许在其他模块中 import 并使用。
  • struct Ring:组件本质上是一个结构体。

2. 组合两个 Circle 实现基础圆环

通过 Stack 将两个圆堆叠:

  • 底层大圆充满父布局,作为环的外径。
  • 顶层小圆居中显示,绘制出“镂空”效果。
@Component export 
struct Ring {
  build() {
    Stack({ alignContent: Alignment.Center }) {
      // 外圆:环的外边界
      Circle()
        .width('100%')
        .height('100%')

      // 内圆:环的镂空部分
      Circle()
        .width(83)
        .height(83)
        .fill(Color.White)
    }
    .width(90)
    .height(90)
  }
}

此时虽然能看到一个圆环,但它的大小和颜色固定,无法外部定制。


3. 定义可配置属性:RingAttribute

为了让 Ring 支持动态配置,我们需要先定义一个属性类 RingAttribute,提前声明所有可传参数及其默认值,并提供一个静态方法 filter 来保证合理性:

class RingAttribute {
  radius: number = 45;                                  // 半径,默认45
  width: number  = 5;                                   // 环宽,默认5
  color: Color | number | string | Resource = '#000000'; // 环色,默认黑色
  solid: Color | number | string | Resource = '#ffffff'; // 填充色,默认白色

  /** 参数过滤,缺省时补全默认值 */
  public static filter(attr: RingAttribute): RingAttribute {
    if (!attr) {
      return new RingAttribute();
    }
    const def = new RingAttribute();
    attr.radius ??= def.radius;
    attr.width  ??= def.width;
    attr.color  ??= def.color;
    attr.solid  ??= def.solid;
    return attr;
  }
}
  • **radius**:外圆半径。
  • **width**:环的厚度。
  • **color**:环的边框颜色。
  • **solid**:环内部的填充色。

4. 在 Ring 组件中使用属性并做校验

引入上述属性类后,需在组件的 aboutToAppear() 钩子中先行过滤参数,再在 build() 中根据其值动态绘制:

@Component export 
struct Ring {
  public ringAttribute: RingAttribute = null;

  /** 在 build 前校验并补全参数 */
  private aboutToAppear() {
    this.ringAttribute = RingAttribute.filter(this.ringAttribute);
  }

  build() {
    const r = this.ringAttribute.radius;
    const w = this.ringAttribute.width;
    Stack({ alignContent: Alignment.Center }) {
      // 外圆:用 ringAttribute.color
      Circle()
        .width(r * 2)
        .height(r * 2)
        .strokeWidth(w)
        .stroke(this.ringAttribute.color)

      // 内圆:用 ringAttribute.solid
      Circle()
        .width(r * 2 - w * 2)
        .height(r * 2 - w * 2)
        .fill(this.ringAttribute.solid)
    }
    .width(r * 2)
    .height(r * 2)
  }
}
  • aboutToAppear() 中调用 filter,确保所有属性都有有效值。
  • build() 方法根据 radiuswidth 等动态设置 Circle 的尺寸和样式。

5. 使用 Ring 并传递参数

完成组件封装后,便可在页面中像使用系统组件一样引用,并将配置项通过构造参数传入:

import { Ring } from '../common/widgets/ring_widget.ets';

@Entry @Component 
struct ComponentTest {
  build() {
    Column({ space: 10 }) {
      Row({ space: 5 }) {
        Ring()  // 默认样式

        Ring({ ringAttribute: {  // 自定义样式
          radius: 40,
          width: 8,
          color: Color.Green,
          solid: '#aabbcc'
        }})

        Ring({ ringAttribute: {  // 再一版自定义
          radius: 50,
          width: 10,
          color: Color.Red,
          solid: Color.Pink
        }})
      }
    }
    .padding(10)
    .width('100%')
    .height('100%')
  }
}

运行效果便是三个不同大小、颜色和环宽的圆环组件并排展示。


小结

  • 组合现有控件:利用 CircleStack 便可快速搭建圆环。
  • 属性驱动:通过自定义的 RingAttribute,支持外部传参并在生命周期前校验。
  • 可复用性:组件以标准方式导出后,可在任意页面直接使用并定制。

掌握上述思路后,你可以轻松地基于系统组件组合出各种可定制的图形控件——不仅限于圆环,还可以是刻度盘、环形进度或装饰性边框。下篇文章将进一步介绍如何用 CanvasMiniCanvas 自绘来实现同样的圆环效果。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐