博客 / 詳情

返回

我的 HarmonyOS - Gauge 自學指南:從 0 到能上實戰的環形量規組件

1. Gauge 是什麼?

Gauge 是 ArkUI 信息展示類組件中的 數據量規圖表組件,可以把一個數值用 環形儀表盤 的方式展示出來。

典型場景:

  • 設備健康度 / 電量 / 評分展示;
  • CPU/內存佔用、網絡質量等系統指標可視化;
  • 運動完成度、睡眠質量等健康數據面板;
  • 任意「當前值 + 範圍(min~max)」的 KPI 儀表盤。

特性小結:

  • 支持 單色 / 漸變 / 分段多色 圓環;
  • 支持 起止角度 調整(不一定是整圓);
  • 支持中間插槽區域:當前值 + 輔助文本 / 圖標;
  • 支持 陰影、指針、自定義內容區、隱私模式 等擴展能力;
  • API 8 開始支持,後續版本增強了卡片、元服務、內容修改器等能力。

卡片 / 元服務支持:

  • ArkTS 卡片:API 9+(部分能力 API 18+)
  • 元服務:API 11+(部分能力 API 18+)

2. 快速上手:用最小代碼畫一個儀表盤

image.png

先來個「能跑起來」的最小示例:

// xxx.ets
@Entry
@Component
struct SimpleGaugeDemo {
  @State current: number = 50;

  build() {
    Column({ space: 16 }) {
      Gauge({ value: this.current, min: 0, max: 100 }) {
        // 中心區域:簡單顯示當前值
        Column() {
          Text(`${this.current}`)
            .fontSize(32)
            .fontWeight(FontWeight.Medium)
            .textAlign(TextAlign.Center)
        }
        .width('100%')
        .height('100%')
      }
      .width('60%')
      .height('40%')
      .startAngle(210)          // 起始角度(類似 7 點鐘方向)
      .endAngle(150)            // 終止角度(類似 5 點鐘方向)
      .colors(Color.Green)      // 單色圓環
      .strokeWidth(16)          // 圓環厚度

      Button('隨機一個值')
        .onClick(() => {
          this.current = Math.floor(Math.random() * 100);
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

這個 demo 幫你搞清楚幾個點:

  • Gauge({ value, min, max }) 創建組件;
  • 組件內部可以放一個子組件(一般用 Text / Column 搭數值+輔助文案);
  • startAngle / endAngle 決定「開口方向」;
  • colors + strokeWidth 決定「長什麼樣」。

3. GaugeOptions:value / min / max 怎麼用?

創建 Gauge 時,推薦總是把 value / min / max 顯式寫上:

Gauge({
  value: 60,  // 當前值(指針指向)
  min: 0,     // 最小值
  max: 100    // 最大值
})

幾點行為要記一下:

  • value 不在 [min, max] 範圍內時,會 強制按 min 處理
  • min / max 默認值:0 / 100
  • max < min 時,會退回默認 [0, 100]
  • min / max 支持負數(可以做「温度 / 虧盈」這類區間)。

實戰習慣:

  • 界面上展示的文案可以有自己的格式(例如「60%」/「60 分」),
  • value / min / max 建議統一用「純數值」,方便邏輯複用。

4. 核心屬性速查

4.1 value:動態更新指針位置

.value(v: number)
  • 作用:動態修改當前數據值;
  • 常見用法:綁定 @State,配合按鈕 / 定時器更新。
Gauge({ value: this.current, min: 0, max: 200 })
  .value(this.current)   // 一般直接改 State 即可

4.2 startAngle / endAngle:控制開口方向

.startAngle(angle: number)
.endAngle(angle: number)
  • 角度説明:

    • 0 度:時鐘「12 點方向」;
    • 順時針為正角度。
  • 默認:startAngle(0)endAngle(360),整圓。
  • 注意:起止角度差太小 會畫出很奇怪的圖形,建議保證有一個可見的弧度(比如 > 60°)。

常見佈局:

  • 儀表盤樣式:startAngle(210)endAngle(150)(一個扇形)。
  • 半圓:startAngle(180)endAngle(0)

4.3 colors:單色、漸變、多段漸變

colors(
  colors: ResourceColor 
        | LinearGradient 
        | Array<[ResourceColor | LinearGradient, number]>
)

從 API 11 開始,規則是:

  1. 單色環

    .colors('#64BB5C')
  2. 漸變環(整圈漸變)

    .colors(
      new LinearGradient([
        { color: '#64BB5C', offset: 0 },
        { color: '#F7CE00', offset: 0.5 },
        { color: '#E84026', offset: 1 }
      ])
    )
  3. 分段漸變環(最多 9 段)
    每一段是 [顏色, 權重],權重控制該顏色佔的比例:

    .colors([
      [Color.Green, 3],
      [Color.Yellow, 2],
      [Color.Red, 1]
    ])

注意點:

  • 段數最多 9 段,多了不顯示;
  • 同一段的權重 ≤ 0 會被忽略;
  • 所有權重都是 0 時,圓環不顯示;
  • 傳錯顏色類型會退回到默認告警色 "0xFFE84026"

4.4 strokeWidth:環形厚度

.strokeWidth(length: Length)  // vp,不能用百分比
  • 默認:4vp
  • 不能小於 0,小於 0 就按默認;
  • 最大值是圓環半徑,超過則按最大值處理。

實戰建議:

  • 儀表盤類場景:12~24vp 的厚度比較常見;
  • 卡片小尺寸 Gauge:8~12vp 更精緻。

4.5 description:底部説明區域

.description(value: CustomBuilder)
  • API 11+:支持設置説明內容;
  • 適合放「最大/最小值説明」「單位提示」「小圖標」。

示例(文本説明):

@Builder
function descBuilder() {
  Text('日活在線用户數')
    .fontSize(12)
    .fontColor('#99000000')
    .textAlign(TextAlign.Center)
}

Gauge({ value: 60, min: 0, max: 100 })
  .description(descBuilder)

説明:

  • 若説明區域內容使用百分比寬高,基準範圍為圓環直徑的某個矩形區域(大概在圓環底部居中);
  • description(null) 表示不顯示説明;
  • 若不設置 description,是否顯示最大最小值與 min/max 設置有關:

    • 設置了 min/max(或其中一個):默認展示 min/max 文本;
    • 都沒設置時:不顯示説明內容。

4.6 trackShadow:環形陰影

.trackShadow(value: GaugeShadowOptions)

GaugeShadowOptions 繼承自 MultiShadowOptions,你可以理解成「多層陰影配置」。

示例:

.trackShadow({
  radius: 7,
  offsetX: 7,
  offsetY: 7
})

説明:

  • 陰影顏色與 圓環顏色一致
  • null 表示不啓用陰影。

4.7 indicator:指針樣式 & 自定義指針

.indicator(value: GaugeIndicatorOptions | null)

GaugeIndicatorOptions

  • icon: ResourceStr

    • 自定義指針圖標(僅支持 svg);
    • 不配則用系統默認三角形指針;
  • space: Dimension

    • 指針與圓環外邊的距離(vp,非百分比);
    • 默認:8vp

示例(移除指針,僅用圓環表示):

.indicator(null)

示例(自定義 svg 指針):

// $r('app.media.indicator') 為 svg 資源
.indicator({
  space: 10,
  icon: $r('app.media.indicator')
})

4.8 privacySensitive:隱私模式

.privacySensitive(isPrivacySensitiveMode: Optional<boolean>)
  • 卡片能力:API 12+;
  • 開啓後:

    • 指針會指向 0 位置;
    • 最大最小值文本會被遮罩;
    • 圓環以灰色或底色顯示。

示例:

Gauge({ value: 80, min: 0, max: 100 })
  .privacySensitive(true)
場景:工資、消費額度、健康指標等隱私信息,在「卡片 / 小窗」裏特別好用。

4.9 contentModifier:自定義內容區(進階)

.contentModifier(modifier: ContentModifier<GaugeConfiguration>)
  • 用於「在 Gauge 上再套一層內容繪製邏輯」;
  • GaugeConfiguration 裏包含:

    • value:當前值
    • min:最小值
    • max:最大值

簡單理解:
系統會把 GaugeConfiguration 傳給你,實現 ContentModifier 接口後,你可以在 applyContent() 中決定內容長什麼樣。

極簡示例:

image.png

@Builder
function SimpleGaugeContent(config: GaugeConfiguration) {
  Column({ space: 8 }) {
    Text(`當前:${config.value}`)
      .fontSize(18)
      .fontWeight(FontWeight.Medium)
    Text(`範圍:${config.min} ~ ${config.max}`)
      .fontSize(12)
      .fontColor('#99000000')
  }
  .width('100%')
  .height('100%')
  .justifyContent(FlexAlign.Center)
  .alignItems(HorizontalAlign.Center)
}

class MyGaugeModifier implements ContentModifier<GaugeConfiguration> {
  applyContent(): WrappedBuilder<[GaugeConfiguration]> {
    return wrapBuilder(SimpleGaugeContent);
  }
}

@Entry
@Component
struct GaugeWithModifier {
  @State value: number = 30;

  build() {
    Column({ space: 16 }) {
      Gauge({ value: this.value, min: 0, max: 100 })
        .contentModifier(new MyGaugeModifier())
        .width('60%')
        .height('40%')
        .colors(Color.Blue)
        .strokeWidth(14)

      Row({ space: 12 }) {
        Button('減').onClick(() => {
          if (this.value > 0) this.value--;
        })
        Button('加').onClick(() => {
          if (this.value < 100) this.value++;
        })
      }
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

5. 實戰示例合集

下面挑幾個典型場景:多色、單色、輔助文本、自定義指針、隱私模式。

5.1 多段漸變儀表盤 + 中心數值 + 輔助文案

image.png

@Entry
@Component
struct MultiColorGaugeDemo {
  private segments = [
    [new LinearGradient([{ color: '#C1E4BE', offset: 0 }, { color: '#64BB5C', offset: 1 }]), 3],
    [new LinearGradient([{ color: '#FCEB99', offset: 0 }, { color: '#F7CE00', offset: 1 }]), 2],
    [new LinearGradient([{ color: '#F5B5C2', offset: 0 }, { color: '#E84026', offset: 1 }]), 1]
  ] as Array<[LinearGradient, number]>;

  @State value: number = 50;

  build() {
    Column({ space: 16 }) {
      Gauge({ value: this.value, min: 0, max: 100 }) {
        Column({ space: 4 }) {
          Text(`${this.value}`)
            .fontSize(32)
            .fontWeight(FontWeight.Medium)
            .textAlign(TextAlign.Center)

          Text('系統健康度')
            .fontSize(12)
            .fontColor('#99000000')
            .textAlign(TextAlign.Center)
        }
        .width('100%')
        .height('100%')
      }
      .startAngle(210)
      .endAngle(150)
      .colors(this.segments)
      .strokeWidth(18)
      .trackShadow({ radius: 6, offsetX: 4, offsetY: 4 })
      .width('80%')
      .height('50%')
      .padding(12)

      Slider({ value: this.value, min: 0, max: 100 })
        .onChange(value => this.value = Math.round(value))
        .width('80%')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

5.2 單色 Gauge + 圖標説明(類似「打卡時長」)

@Entry
@Component
struct SingleColorGaugeDemo {
  @State value: number = 75;

  @Builder
  descImage() {
    // 使用系統時鐘圖標,僅為示例,可替換為自己的資源
    Image($r('sys.media.ohos_ic_public_clock'))
      .width(48)
      .height(48)
  }

  build() {
    Column({ space: 24 }) {
      Gauge({ value: this.value, min: 0, max: 120 }) {
        Column({ space: 4 }) {
          Text(`${this.value} min`)
            .fontSize(28)
            .fontWeight(FontWeight.Medium)
            .textAlign(TextAlign.Center)
        }
        .width('100%')
        .height('100%')
      }
      .startAngle(210)
      .endAngle(150)
      .colors('#CCA5D61D')        // 單色
      .strokeWidth(18)
      .description(this.descImage) // 使用圖片作為説明區
      .width('70%')
      .height('45%')
      .padding(16)

      Button('模擬累積 5 分鐘')
        .onClick(() => {
          this.value = Math.min(this.value + 5, 120);
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

5.3 使用子組件做「主值 + 輔助文本」佈局

@Entry
@Component
struct GaugeWithHelperTextDemo {
  @State score: number = 88;

  build() {
    Column() {
      Gauge({ value: this.score, min: 0, max: 100 }) {
        Column() {
          Text(`${this.score}`)
            .fontSize(40)
            .fontWeight(FontWeight.Bold)
            .textAlign(TextAlign.Center)
            .margin({ top: '30%' })

          Text('綜合評分')
            .fontSize(14)
            .fontColor($r('sys.color.ohos_id_color_text_secondary'))
            .textAlign(TextAlign.Center)
        }
        .width('100%')
        .height('100%')
      }
      .startAngle(210)
      .endAngle(150)
      .colors(new LinearGradient([
        { color: '#64BB5C', offset: 0 },
        { color: '#F7CE00', offset: 0.5 },
        { color: '#E84026', offset: 1 }
      ]))
      .strokeWidth(18)
      .trackShadow({ radius: 6, offsetX: 4, offsetY: 4 })
      .description(null)       // 不用默認 min/max 説明
      .width('80%')
      .height('50%')
      .padding(16)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

5.4 自定義 svg 指針

// 指針 svg 示例(放到 app.media.indicator.svg 等資源中)
/*
<svg width="200" height="200" viewBox="0 0 100 100">
  <path d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z"
        stroke="black" stroke-width="3" fill="white"/>
</svg>
*/

@Entry
@Component
struct GaugeCustomIndicatorDemo {
  build() {
    Column() {
      Gauge({ value: 50, min: 0, max: 100 })
        // 注意替換為你自己的 svg 資源
        .indicator({ space: 10, icon: $r('app.media.indicator') })
        .startAngle(210)
        .endAngle(150)
        .colors('#CCA5D61D')
        .strokeWidth(18)
        .width('70%')
        .height('45%')
        .padding(18)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

5.5 隱私模式 Gauge(卡片場景)

@Entry
@Component
struct GaugePrivacyDemo {
  build() {
    Scroll() {
      Column({ space: 24 }) {
        Text('消費額度(隱私示例)')
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .margin({ top: 16 })

        Gauge({ value: 80, min: 0, max: 100 })
          .startAngle(225)
          .endAngle(135)
          .colors(Color.Red)
          .strokeWidth(18)
          .trackShadow({ radius: 7, offsetX: 7, offsetY: 7 })
          .privacySensitive(true)     // 開啓隱私模式
          .width('80%')
          .height('50%')
          .padding(18)
      }
      .width('100%')
      .alignItems(HorizontalAlign.Center)
    }
  }
}

6. 常見坑 & 實戰建議

  1. 起止角度設置不當

    • 起止角度差太小 → 圓環幾乎看不到,或者圖樣畸形;
    • 常見推薦:儀表盤式用 210° ~ 150°、或 225° ~ 135°
  2. 分段漸變段數太多

    • 最多 9 段,多於部分直接被忽略;
    • 設計上也不建議超過 5 段,太花會影響可讀性。
  3. strokeWidth 過大

    • 厚度最大值是半徑,超過會被「截斷」;
    • 小尺寸卡片裏,厚度過大容易壓縮中間內容區。
  4. 指針圖標格式錯誤

    • 只支持 svg
    • 非 svg 會退回系統默認三角形指針。
  5. 隱私模式效果看不到

    • privacySensitive(true) 需要 卡片框架支持,普通頁面裏可能看不到預期效果。
  6. 內容區排版

    • 中心區域佈局完全由你控制,但要注意:

      • 儘量保持在中間 / 居中;
      • 字號不要過大,以免在小屏設備上溢出;
    • 可以配合 maxFontSize / minFontSize 做自適應。

希望這篇文章能對大家學習鴻蒙有幫助~歡迎交流~指正~

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.