鸿蒙 ArkUI Rating 评分组件:星级评价、半星支持与评分交互
023 - Rating 评分组件
本文配套演示工程见同目录
ohos/,包含五个可运行的 ArkTS 原生示例,覆盖基础评分、半星支持、商品评价(提交闭环)、历史评分展示、样式定制。所有示例均在 DevEco Studio + 模拟器验证通过。
1. 引言:五颗星星的重量
买东西前,你会先看什么?大概率是那个"4.8 分"和它旁边的一排星星。一条好评是普通人的主观感受,但一万条好评聚在一起,就成了一家店的信用。评分(Rating)大概是电商体系里"性价比"最高的组件——用户只需要点五下,商家就得到了一个可量化、可比较、可排序的质量信号。
评分之所以用星星,是人类几百年的共识:星级是"质量"的通用语言,酒店、电影、App、外卖,全世界都在用五颗星表达"这东西好不好"。它把复杂的质量感知压缩成 0~5 的整数(或半星),输入成本极低,信息密度极高。
在鸿蒙(HarmonyOS)的 ArkUI 声明式框架里,Rating 是"评分型"基础组件:一排星星,点击或拖动即改值,回调一个 0~stars 的数值。它有两种面孔——输入(用户打分)与展示(只读平均分),由 indicator 一个布尔值切换。理解 Rating,关键在于理解它交付的是数值、表达的是意愿:评分的值只是一个信号,商家看的是它的统计量。本文就从这排星星出发,把"能点"讲到"点得准、点得美、点得稳"。
1.1 Rating 在评价体系里的位置
评价类组件不止评分一种,把评价家族摆在一起,Rating 的边界才清楚:
| 组件 | 语义 | 输入方式 | 典型场景 |
|---|---|---|---|
Rating |
星级打分 | 点/拖星星 | 商品评价、服务打分 |
TextArea |
文字评价 | 键盘输入 | 评价详情、晒单 |
Toggle |
好评/差评 | 开关二态 | 一键点赞、踩 |
Select |
选项评价 | 下拉选择 | 评价标签选择 |
可以看到:Rating 负责"量"(打几分),TextArea 负责"质"(说了什么),Toggle 负责"方向"(好还是坏)——三者拼起来就是完整的评价闭环。多数场景的默认组合是"评分 + 文字",星级在前、文字在后,因为分值易统计、文字见真心。
1.2 心智模型:一排有刻度的星星
把 Rating 拆开看,它就四样东西:
- 值:
rating,当前评分,范围 0 ~stars; - 刻度:
stars(星星总数)与stepSize(步进精度)共同决定"能打出什么分"; - 面孔:
indicator,false可打分、true只读展示; - 反馈:
onChange,打分后回调数值。
四者的关系一句话:stars 定范围,stepSize 定精度,indicator 定面孔,onChange 定结果。把评分想成一把"只有星星刻度的尺子"——量程是星星数,最小刻度是 stepSize,用户每点一下,尺子就读出一个数。
1.3 一次打分发生了什么
用户在星星上点一下或拖动,框架做三件事:命中换算(把点击位置折算成 0~stars 的原始值)→ 精度吸附(按 stepSize 就近取整)→ 事件上报(onChange(value))。换算这一步值得记:设星星排宽 W、点击横坐标 x、星星数 S,原始值大致是:
vraw=xW×S v_{raw} = \frac{x}{W} \times S vraw=Wx×S
再按 stepSize 吸附成最终值。stepSize = 0.5 时 3.2 会吸附到 3.0 或 3.5,stepSize = 1 时只会是整数。stepSize 是评分精度的唯一开关——它决定用户能不能表达"3.5 分"这种中间意愿,后文 4.2 专门演示。
1.4 为什么评分是电商的"信任基础设施"
下单前看评分,本质上是在做一次"用别人的经验降低自己风险"的决策。评分组件把这个决策成本压到最低:一眼扫到数字、二眼看到星数、三眼滚到评价。它之所以成为电商标配,是因为它同时满足了三个角色:用户要快(点五下结束)、商家要准(千条评分统计出稳定均值)、平台要公(同量纲可比、可排序)。理解 Rating,等于理解了"信任是怎么被量化的"。本文就从这排星星的 API 出发,把"能点"讲到"点得准、点得美、点得稳"。
2. 环境准备
本文基于以下环境:
- DevEco Studio 5.0 及以上
- HarmonyOS SDK API 12(5.0.0)
- 模拟器:Phone(API 12)
演示工程目录结构:
ohos/
├── AppScope/ # 应用级配置
├── entry/ # 入口模块
│ └── src/main/ets/
│ ├── entryability/EntryAbility.ets
│ ├── pages/Index.ets
│ ├── model/ # 历史评分数据模型
│ └── components/ # 五个演示组件
└── oh-package.json5 # 模块依赖
说明:本文属于"通用版 HarmonyOS 原生"系列,示例以模拟器验证即可;若你使用 Flutter 专属版(需鸿蒙真机而非模拟器),请注意对应部署差异。
关于运行环境再补两点,避免新手卡在"跑不起来":
- 签名:模拟器调试可用 DevEco Studio 自动生成的调试证书;真机运行需在
Signing Configs里配好指纹与p12/cer/p7b文件。本文演示工程module.json5无特殊敏感权限,跑示例足够。 - 资源占位:编译需
AppScope/resources/base/media/app_icon.png与entry/.../media/icon.png两张图标。文章正文统一约定为占位资源,请自行放入对应 PNG;其余示例均为纯文本/色块/表情符号,不依赖额外图片。
这两步到位后,用 DevEco Studio 打开本 ohos/ 目录直接运行 entry 模块即可看到五个演示页。
3. 核心 API 逐层拆解
3.1 值与刻度:rating / stars
Rating 的构造参数只有两个,但语义要掰开:
Rating({ rating: 3.5, indicator: false })
.stars(5) // 星星总数,默认 5
.stepSize(0.5) // 步进精度,默认 0.5
rating:当前评分,取值范围 0 ~stars。它是"真相源",由@State托管,onChange回写;stars:星星总数,等于"满分的刻度"。默认 5 是全球惯例,特殊场景(如"10 分制")可改;stepSize:取值精度,默认 0.5。它决定"能不能打半星"——设1就只有整星,设0.1甚至可以打出 4.8 星。
三者合成一句:rating 是当前值、stars 是满分、stepSize 是精度。改 stars 会同时改变值域(10 星制下 6 星才算及格线),改 stepSize 只影响吸附粒度,两者独立。
3.2 精度吸附:stepSize 的取舍
stepSize 的选择是个产品决策,直接决定用户能表达多细的意愿:
| stepSize | 可表达的值 | 适合场景 |
|---|---|---|
| 1 | 0~5 整数 | 粗粒度打分(满意度 1-5 档) |
| 0.5 | 0~5 每半星 | 电商评价、服务评分(主流) |
| 0.1 | 0~5 任意小数 | 只读展示细腻均分(4.8 星) |
注意一个细节:stepSize 也影响只读展示。历史平均分 4.8 这种小数,若 stepSize = 1 只会显示 5 星全亮(4.8 吸附到 5),失真;配 stepSize = 0.1 才能让 4.8 星精确点亮四星半。所以"展示均分"的场景,stepSize 要调小——这是评分组件最容易踩的展示失真坑(6.2 详述)。
3.3 面孔切换:indicator
indicator 决定 Rating 是"输入"还是"展示":
Rating({ rating: this.rating, indicator: false }) // 可打分(默认)
Rating({ rating: 4.7, indicator: true }) // 只读展示
indicator = false(默认):星星可点可拖,onChange生效;indicator = true:星星只读,任何点击无效,onChange不触发——商品列表、详情页的平均分展示就是这个面孔。
一个实用技巧:提交后的"锁定"也可以靠它。用户打完分、点完提交,把 indicator 从 false 翻成 true,评分区瞬间从"可编辑"变成"只读"(4.3 的提交闭环就这么做),比"禁用点击 + 置灰"的 DIY 方案省一整段代码。
3.4 反馈事件:onChange
Rating 只有一个事件,签名极简:
.onChange((value: number) => {
this.rating = value; // 回写当前值
})
要点:回调参数是吸附后的最终值(已按 stepSize 取整),直接用即可,别再加工。评分没有"拖动过程 vs 松手"的阶段区分——点一下触发一次、拖动过程中持续触发。想做"拖动实时预览 + 松手确认"的反馈,直接用回调值驱动 UI 即可,不必分阶段。
3.5 样式定制:三色体系与尺寸
Rating 的视觉由"三色 + 尺寸"定制:
Rating({ rating: this.rating })
.starColor('#FFB800') // 已评星星颜色
.secondaryColor('#E0E0E0') // 未评星星颜色
.starBackgroundColor('#F0F4FA') // 星星底色(可选)
.width(200) // 整排宽度(星星自动等分)
.height(40) // 星星高度
要点:
starColor管"已评"、secondaryColor管"未评":一对对比色让"点亮了几颗"一目了然,金色 + 浅灰是最高频组合;- 宽高即星星大小:整排宽度按星星数等分,
width(200)+ 5 星 = 每颗 40 宽。想换星星图案,用starStyle传自定义图片资源($r引用),演示工程用颜色体系,接入真实业务时换资源即可。
配色原则就一条:已评要亮、未评要淡、对比要鲜明。评分区是用户"眼动交互"的高频区域,对比弱了,扫一眼看不出 4 星和 5 星的区别,信任感就淡了。
3.6 与兄弟组件的取舍再强调
回顾 1.1 的表格,把评价输入的选择判据收成三句话:
- 要星级量化 →
Rating; - 要文字描述 →
TextArea(005 篇); - 要方向二态(好评/踩) →
Toggle(017 篇)。
多数场景是"Rating + TextArea"的组合拳:星级打分量、文字表细节。把这条刻进肌肉记忆,评价表单就不会做成"只有星星、没有心声"的半成品。
4. 完整可运行代码
下面是五个演示组件的核心片段(完整工程见同目录 ohos/)。
4.1 入口与页面整合
EntryAbility.ets 走标准生命周期,onWindowStageCreate 里 loadContent('pages/Index')。Index.ets 用 Tabs 把五个演示分页,结构同 013 篇的容器写法,仅 tabBar 用文字区分五大演示:
Tabs({ barPosition: BarPosition.Start, index: this.currentIndex }) {
TabContent() { BasicDemo() }.tabBar('基础评分')
TabContent() { HalfStarDemo() }.tabBar('半星支持')
TabContent() { ReviewDemo() }.tabBar('商品评价')
TabContent() { HistoryDemo() }.tabBar('历史评分')
TabContent() { StyleDemo() }.tabBar('样式定制')
}
.barMode(BarMode.Scrollable)
.width('100%')
.height('100%')
4.2 基础评分:BasicDemo.ets
第一个演示把"值 + 刻度"讲透,顺带验证 stars 切换:
@State rating: number = 3;
@State starCount: number = 5;
Rating({ rating: this.rating })
.stars(this.starCount)
.stepSize(1)
.starColor('#FFB800')
.secondaryColor('#E0E0E0')
.width(200)
.height(40)
.onChange((value: number) => {
this.rating = value;
})
设计点:底部三个按钮在 5/7/10 星间切换,切换时同步重置 rating 到区间内合法值(如 10 星制给 6)——因为 rating 超出 stars 会被框架夹取,主动给合法初值更稳。stepSize = 1 只出整星,评分值域与 stars 完全一致:5 星制满分 5、10 星制满分 10,值域即业务语义。
4.3 半星支持:HalfStarDemo.ets
第二个演示把"评分精度"变成可见的对比——一个 Toggle 切换 stepSize:
@State rating: number = 3.5;
@State halfStep: boolean = true;
Rating({ rating: this.rating })
.stars(5)
.stepSize(this.halfStep ? 0.5 : 1)
.starColor('#FFB800')
.secondaryColor('#E0E0E0')
.width(220)
.height(44)
.onChange((value: number) => {
this.rating = value;
})
设计点:halfStep = true 时用户能打出 3.5 星,false 时只能 3 或 4。切换时同步把 rating 调到"新精度下合法"的值(3.5 → 4),避免出现"半星值 + 整星精度"的错位。半星的价值在于:"还行但不够好"有了安放处——3.5 星和 4 星的差距,正是"将就"与"满意"的分界线,这也是电商评价普遍开半星的核心理由。
4.4 商品评价:ReviewDemo.ets
第三个演示是本文的主菜——"评分 → 提交 → 锁定"的完整闭环:
@State rating: number = 0;
@State submitted: boolean = false;
private desc(): string {
const r = this.rating;
if (r <= 0) return '未评价';
if (r < 1.5) return '很差';
if (r < 2.5) return '一般';
if (r < 3.5) return '好';
if (r < 4.5) return '很好';
return '极好';
}
Rating({ rating: this.rating, indicator: this.submitted })
.stars(5)
.stepSize(0.5)
.starColor('#FFB800')
.secondaryColor('#E0E0E0')
.width(240)
.height(48)
.onChange((value: number) => {
this.rating = value;
})
if (!this.submitted) {
Button('提交评分')
.enabled(this.rating > 0) // 未评分置灰
.onClick(() => {
this.submitted = true;
promptAction.showToast({ message: `评分 ${this.rating.toFixed(1)} 星提交成功`, duration: 1500 });
})
}
设计点有三:
- 文字描述联动:
desc()把 0~5 映射成"很差/一般/好/很好/极好",颜色再按档位变色(高分绿、中分蓝、低分红)——评分从"抽象的星"变成"看得懂的话"; - 提交门槛:
rating = 0(未评)时提交按钮置灰,逼用户"至少打一分再提交",避免空评灌水; - 提交即锁定:点提交后
submitted = true,Rating的indicator同步翻真,评分区自动变只读;"重新评价"一键解锁重来。
这个演示把 Rating 的"输入面孔"与"展示面孔"无缝衔接:提交那一刻,用户刚打的分数就从"意愿"变成了"记录",indicator 就是那道门。
4.5 历史评分展示:HistoryDemo.ets
第四个演示是商品详情页的评分区——只读大分 + 商品列表均分:
private readonly avg: number = 4.7;
Rating({ rating: this.avg, indicator: true })
.stars(5)
.stepSize(0.1) // 小数均分要配小 step,避免 4.8 被吸附成 5
.starColor('#FFB800')
.secondaryColor('#E0E0E0')
.width(140)
.height(26)
ForEach(RATING_LIST, (item: RatingItem) => {
Row() {
Text(item.name)
Rating({ rating: item.rating, indicator: true })
.stars(5)
.stepSize(0.1)
.width(110)
.height(22)
Text(`${item.rating.toFixed(1)}`)
Text(`${item.count} 人`)
}
}, (item: RatingItem) => item.name)
设计点有两个:
- 大分 + 星 + 人数三件套:"4.7"大字、半亮星星、“基于 45620 条评价”,是电商评分区的标准配置——数字给结论、星星给直觉、人数给可信度;
stepSize = 0.1保真展示:4.8 星、4.3 星这类小数均分,只有小步进才能精确点亮对应比例,这是"展示失真坑"的正解(6.2 详解)。
4.6 样式定制:StyleDemo.ets
第五个演示把三色体系与尺寸定制全部摆出来:
Rating({ rating: this.gold })
.starColor('#FFB800').secondaryColor('#E0E0E0')
.width(180).height(40)
Rating({ rating: this.rose })
.starColor('#FF5C8A').secondaryColor('#F5D5E0')
.width(150).height(30)
Rating({ rating: this.blue })
.starColor('#4A90D9').secondaryColor('#E3E8F0')
.starBackgroundColor('#F0F4FA')
.width(150).height(30)
Rating({ rating: 4.5, indicator: true })
.width(120).height(24) // 只读小星星
设计点:经典金、玫粉、科技蓝三套配色 + 只读小星,演示"评分贴合品牌色与页面密度"的定制方式。starBackgroundColor 给星星加一层底色,适合浅色卡片上"星星太淡"的场景。
4.7 无障碍与评价防刷细节
容易被漏的两点:
- 无障碍:
Rating默认支持读屏,但读屏播报的是"评分 4 分",建议配合文字描述(如"很好")让视障用户获得完整语义;用.accessibilityText()自定义播报更佳; - 评价防刷:前端评分组件只负责"采集",防刷(一人一评、频控、风控)全部在服务端。前端可以做的只有"提交前本地校验"(未评分置灰)和"提交后锁定"(
indicator翻真)——把这两道做到,前端职责就圆满了。
5. 模拟器验证
本文所有示例在 DevEco Studio 模拟器(Phone API 12)验证通过。验证要点:
- 基础评分:5/7/10 星切换后值域同步变化,点击星星即时回显;
- 半星支持:
stepSize切换后 3.5 星可选/不可选,数值显示正确; - 商品评价:未评分提交按钮置灰;打分后描述文字随档位变色;提交后锁定只读、Toast 提示;重新评价可解锁;
- 历史评分:只读星星精确显示 4.8/4.6/4.7 等小数均分,不可点击;
- 样式定制:三套配色与大小尺寸正常渲染,只读小星不变形。
5.1 预期效果截图


5.2 模拟器与真机的差异
| 维度 | 模拟器表现 | 真机表现 | 是否需处理 |
|---|---|---|---|
| 点击评分 | 鼠标点击 | 手指点按 | 功能一致 |
| 拖动评分 | 鼠标拖拽 | 手指滑动 | 手感差异 |
| 星星渲染 | 一致 | 一致 | 无需 |
| 只读展示 | 一致 | 一致 | 无需 |
| 触控精度 | 鼠标更"点" | 手指更"滑" | 真机校准星间距 |
一句话:模拟器负责把"功能跑通、逻辑正确",真机负责把"手感校准、星距验收"。本文示例上真机功能应一致;手感类差异按上表逐项核对。
6. 调试与排错
6.1 点了星星值不变
按优先级排查:
rating没绑@State:状态不回写、星星不亮;onChange里没回写:事件只上报,必须this.rating = value;indicator误开:indicator = true时星星只读,点不动是预期行为——检查是不是把展示面孔用在了输入场景。
一句话:值要进 @State,回调要回写,面孔要对,三件事齐了,星星才"活"。
6.2 均分显示失真:4.8 显示成 5 星全亮
这是"展示失真坑":stepSize 太大(默认 0.5 都不够),4.8 被吸附到 5.0,五颗星全亮。解法:只读展示的 stepSize 调小到 0.1,让小数均分精确点亮对应比例。展示均分时,stepSize 的职责从"输入精度"变成"显示保真度",别用默认值裸奔。
6.3 切换星星数后值越界
stars 从 5 切到 10,rating 若还是 8(旧值)没问题;但从 10 切回 5,rating = 8 就超了值域,框架夹取到 5——表现是"明明打了 8 分,显示却是 5 星"。解法:切换 stars 时同步重置 rating 到新值域内(4.2 的按钮就这么做)。
6.4 拖动评分跳变
- 跳变:
stepSize = 1时拖动跨星跳变是正常的(精度设计),不是 bug; - 值对不上:
onChange里对value二次取整,或rating回写用了别的变量。回调参数就是吸附后的最终值,直接用,别加工。
6.5 半星切换后显示"半星残留"
stepSize 从 0.5 切到 1,rating = 3.5 这个半星值在新精度下不合法,显示可能停在 3.5。解法:切换精度的同时把 rating 吸附到新精度的合法值(4.3 的 3.5 → 4 就是标准姿势)。
6.6 评分区点击穿透
Rating 放在可点击卡片里(如"点卡片进详情"),星星的点击会被卡片吃掉或穿透。解法:星星区域用 .onClick 显式拦截(Rating 自带点击处理,通常不会穿透),若卡片有整块点击手势,把评分区提升层级或用空白 Blank 隔离。先把高频问题收成速查表:
-
点了星星值不变
- rating 未进 @State / onChange 未回写 / indicator 误开 4.8 显示成 5 星
- 只读 stepSize 调小到 0.1,保真展示均分 切星星数后值越界
- 切换 stars 时同步重置 rating 半星残留
- 切 stepSize 时把 rating 吸附到新精度合法值 点击被卡片吃掉
- 检查外层手势,评分区提升层级或隔离
7. 总结与扩展
7.1 本文知识地图
把 Rating 核心能力收成一张图,便于回顾:
7.2 评分交互的设计规范
把本文散落的原则收成五条,作为写评分的检查清单:
- 默认 5 星 + 半星:0.5 步进是电商评价主流,"还行"有处安放;
- 只读配小 step:展示均分用 0.1,4.8 不显示成 5;
- 文字描述联动:星级旁边挂"很好/一般"档位词,抽象变具体;
- 提交即锁定:
indicator翻真,评分区从输入变只读; - 防刷在服务端:前端只管采集与锁定,别在前端做"真校验"。
7.3 三个真实踩坑复盘
- 案例一:商品详情页 4.8 分显示五颗星全亮。
stepSize用了默认值,4.8 被吸附成 5。改为stepSize(0.1)后精确显示四星半。 - 案例二:切换 10 星制后评分"神秘归零"。
rating = 8是合法的,但用户再点一次、组件把 8 当新值吸附——实际是切回 5 星制时 8 越界被夹取成 5,来回切几次就乱了。切换时重置rating后稳定。 - 案例三:提交后还能拖动评分。只在
onClick里拦了提交按钮,忘了Rating本身还可点。indicator翻真后彻底锁死,问题消失。
这类问题共性:都不是组件坏了,而是"有没有把 Rating 当’一把带刻度的尺子’去设计"——值域、精度、面孔、反馈四件事照顾到,问题在写代码时就能消灭。
7.4 后续可沿三条线深入
- 与 TextArea 组合:评价表单"星级 + 文字"双件套,评分联动星级描述(005 篇);
- 与统计结合:评分分布条(5 星占 62% 的横向条形图)与均分加权计算,做详情页评分区;
- 与状态管理结合:
rating提升到视图模型,评价列表与详情页共享"我的评分"(051–075 篇)。
给一条量化的学习路线,按天推进即可:
回到开头:Rating 是一排有刻度的星星——rating 是当前值、stars 是满分、stepSize 是精度、indicator 是面孔。本文从这把"星星尺子"的心智模型出发,逐层拆了值、刻度、面孔、事件、样式五环,又用五个演示把它落到基础评分、半星、评价闭环、历史展示、样式五个真实场景。写 Rating 时若能始终记住"值进 @State、回调即最终值、展示配小 step、提交翻 indicator",那么无论商品评价、服务打分还是均分展示,都能点得准、点得美、点得稳。把这份理解带回项目,下一个"评分失准/显示失真"的工单,大概就能在写代码时消灭在萌芽里。
Rating 是 ArkUI 里最"轻"的组件之一:用户点五下就完成一次评价,可一旦它不亮、失真、锁不住,整个评价体系的信任就垮了。把本文五环吃透,你就能从容撑起从商品评价到评分统计的全部场景。
更多推荐


所有评论(0)