HarmonyOS7 SliderStepMarks 教程:用刻度滑块做评分和百分比选择
文章目录
前言
很多刚接触 HarmonyOS7 的同学,第一次用 Slider 都会把它理解成“拖一拖拿到一个数字”。这话不算错,但只说到了一半。
真正做页面的时候,你很快就会发现,不是所有数字都适合让用户随便拖。像评分、档位、百分比这类值,很多时候本来就是离散的,用户需要的不是“任意值”,而是“固定几个可选结果”。
这时候,带刻度的滑块就特别好用。
这篇文章就用这个案例,带你把两个常见场景讲透:
- 一个是 1 到 5 星的评分选择。
- 一个是 0% 到 100% 的进度档位选择。
你把这篇看懂,后面再写亮度调节、筛选阈值、等级选择这类页面,会轻松很多。
先看这个案例到底做了什么

这个页面表面上只有两个滑块,但它其实在演示两种很典型的离散输入:
- 上面的滑块表示评分,范围是
1 ~ 5,步长是1。 - 下面的滑块表示百分比,范围是
0 ~ 100,步长是25。
也就是说,用户并不是在拖一个“连续变化”的值,而是在几个固定档位之间选择。
这正是 showSteps(true) 有意义的地方。
如果没有刻度,用户虽然也能拖动,但对“当前到底停在哪个档位”不会那么直观。加上刻度以后,页面会一下子变得更像一个真实控件,而不是纯演示效果。
这种场景为什么适合用刻度滑块
先别急着背 API,先想业务。
比如下面这些场景:
| 场景 | 适合原因 |
|---|---|
| 星级评分 | 结果通常只有 1 星到 5 星,天然是离散值 |
| 百分比档位选择 | 比如 0%、25%、50%、75%、100% 这种固定粒度 |
| 音量/亮度分级 | 可以按固定段位调,而不是完全自由拖动 |
| 筛选阈值 | 比如价格等级、距离范围、风险等级 |
这些场景有一个共同点:
用户最终要的不是“尽量精确的一个值”,而是“落在某个明确档位上”。
所以如果你做的是这类页面,Slider + 步长 + 刻度 会比普通自由滑动更合适。
先抓住这个案例里的两个核心状态
这份代码里最关键的状态就两个:

@State value1: number = 3
@State value2: number = 50
它们分别负责:
value1:保存当前评分值value2:保存当前百分比值
你可以把它们理解成两个“结果仓库”。
只要用户一拖滑块,新的值就会写进这两个状态里。状态一改,界面上的文案也会跟着变。
为什么这里要用 @State
因为滑块是可以交互的。
用户每次拖动,页面都要立即更新:
- 上面的“评分: 3 星”要变成新的值
- 下面的“进度: 50%”也要变成新的值
如果不用 @State,你改了值,页面不会自动刷新。
所以在 ArkUI 里,只要某个值会随着用户操作变化,并且变化后要反映到界面上,它通常就应该是状态。
先看完整代码
先把完整代码看一遍,后面讲解时你更容易对得上:
/**
* SliderStepMarks - Slider 刻度标记
*/
import { PRESET_COLORS, generateListItems, PAGE_BG_COLOR, PANEL_BG_COLOR, ACCENT_COLOR, MUTED_TEXT_COLOR } from './types'
@Entry
@Component
struct SliderStepMarks {
@State isShow: boolean = true
@State value1: number = 3
@State value2: number = 50
build() {
Column() {
if (this.isShow) {
Column() {
Text('Slider 刻度标记').fontSize(16).fontWeight(FontWeight.Bold).margin({ bottom: 16 })
Text(`评分: ${this.value1.toFixed(0)} 星`).fontSize(14).margin({ bottom: 8 })
Slider({ value: this.value1, min: 1, max: 5, step: 1 })
.showSteps(true)
.onChange((v: number) => { this.value1 = v })
.selectedColor(PRESET_COLORS[2].value)
.blockColor(PRESET_COLORS[2].value)
.width('100%').margin({ bottom: 24 })
Row() {
Text('1').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('2').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('3').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('4').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('5').fontSize(11).fontColor(MUTED_TEXT_COLOR)
}.width('100%').justifyContent(FlexAlign.SpaceBetween).margin({ bottom: 28 })
Text(`进度: ${this.value2.toFixed(0)}%`).fontSize(14).margin({ bottom: 8 })
Slider({ value: this.value2, min: 0, max: 100, step: 25 })
.showSteps(true)
.onChange((v: number) => { this.value2 = v })
.selectedColor(ACCENT_COLOR)
.blockColor(ACCENT_COLOR)
.width('100%').margin({ bottom: 24 })
Row() {
Text('0%').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('25%').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('50%').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('75%').fontSize(11).fontColor(MUTED_TEXT_COLOR)
Text('100%').fontSize(11).fontColor(MUTED_TEXT_COLOR)
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
}
.width('100%').padding(16).backgroundColor(PANEL_BG_COLOR).borderRadius(12)
}
Text('Slider 刻度标记')
.fontSize(12).fontColor(MUTED_TEXT_COLOR).margin({ top: 12 })
}
.width('100%').height('100%').backgroundColor(PAGE_BG_COLOR).padding(16)
}
}
第一眼先看 Slider 的 4 个关键参数
上面评分滑块这一行最值得你停下来多看两眼:
Slider({ value: this.value1, min: 1, max: 5, step: 1 })
这 4 个参数决定了这个滑块的基本行为:
| 参数 | 作用 | 这篇里的值 |
|---|---|---|
value |
当前默认值 | this.value1 |
min |
最小值 | 1 |
max |
最大值 | 5 |
step |
每次变化的步长 | 1 |
把它翻成大白话就是:
- 这个评分滑块最小只能到 1
- 最大只能到 5
- 每次只能按 1 星递增或递减
所以它最终只会停在 1、2、3、4、5 这几个位置上。
下面这个百分比滑块也是同样思路:
Slider({ value: this.value2, min: 0, max: 100, step: 25 })
它的结果只会落在:
0255075100
这就是“步长”在这个案例里的实际意义。
showSteps(true) 为什么是这篇的灵魂
看这行:
.showSteps(true)
它的作用就是把步长刻度显式展示出来。
你可以把它理解成:“不仅内部按固定档位走,而且把这些档位也直接画给用户看。”
这一点特别重要。
因为有些时候,开发者知道这个控件只能选固定档位,但用户未必知道。没有刻度时,用户会感觉自己在拖一个普通滑块;有了刻度以后,用户会更自然地理解:
- 哦,这是分档选择
- 哦,它不是连续值
- 哦,我只能落在几个明确位置上
这就是为什么我说,这一篇真正要理解的,不只是 Slider,而是怎么把“交互规则”清楚地表达给用户。
onChange 到底把什么连起来了
看这两段:
.onChange((v: number) => { this.value1 = v })
.onChange((v: number) => { this.value2 = v })
这两行是整个交互真正“活起来”的地方。
它们做的事情其实非常直接:
- 用户拖动滑块。
- 新值通过回调传进来。
- 把新值写回状态。
- 页面文案自动刷新。
这就是一个最标准的“输入 -> 状态 -> 显示”的流程。
如果你是小白,建议你把这条线牢牢记住。后面学 Rating、TextPicker、DatePicker、TimePicker,本质上都是这一套。
为什么文案要跟着滑块实时变化
看这两行:
Text(`评分: ${this.value1.toFixed(0)} 星`)
Text(`进度: ${this.value2.toFixed(0)}%`)
很多人写示例时,会把滑块放上去就算完事。
但如果没有这些文案,用户虽然能拖,却不一定第一时间知道自己选中了什么值。
尤其是百分比、等级、评分这类输入,拖动结束后最好要有明确结果反馈。
所以这里的文案不是装饰,它承担的是“结果回显”的职责。
toFixed(0) 为什么也值得留意
这里用了:
this.value1.toFixed(0)
this.value2.toFixed(0)
它的作用是把结果格式化成不带小数的整数显示。
虽然这篇里的步长本来就是整数,但这里依然用了 toFixed(0),好处是显示结果更稳定,也更直观。
如果后面你把步长改成 0.5、0.1 这种更细的粒度,就要重新考虑显示格式,比如保留 1 位小数。
为什么还额外写了两排标签
看这两块 Row:
Row() {
Text('1')
Text('2')
Text('3')
Text('4')
Text('5')
}
Row() {
Text('0%')
Text('25%')
Text('50%')
Text('75%')
Text('100%')
}
这两排文字不是多余的。
showSteps(true) 会把刻度点显示出来,但刻度点本身不一定自带可读标签。对初学者或者普通用户来说,看到刻度点,不一定能马上把它和具体数值对应上。
所以这里额外补了一排说明文字,体验会更完整。
这也是一个很真实的开发思路:
控件本身提供基础交互,但页面往往还需要补足“说明层”。
这个页面的布局为什么很适合入门
这篇的布局结构很简单:
- 外层一个
Column - 中间一个卡片容器
- 卡片里先放评分模块,再放百分比模块
- 每个模块都是“结果文案 + 滑块 + 刻度标签”三件套
这种布局很适合小白,因为它清楚、顺序强、没有太多干扰。
你看代码时不会被复杂嵌套绕晕,能把注意力集中在交互逻辑本身。
这篇最值得单独记住的 3 处代码
1. @State value1: number = 3
@State value1: number = 3
它保存的是评分结果。
你拖评分滑块时,真正变的就是它。
2. Slider({ value: this.value1, min: 1, max: 5, step: 1 })
Slider({ value: this.value1, min: 1, max: 5, step: 1 })
这一行决定了评分滑块的规则边界。
如果没有 min、max、step 这些限制,评分就不会这么明确地落在固定档位上。
3. .onChange((v: number) => { this.value2 = v })
.onChange((v: number) => { this.value2 = v })
这行代码把“用户拖动”真正变成了“页面结果更新”。
没有它,滑块就只是看起来能动,结果却不会写回状态。
小白最容易踩的坑
1. 步长和标签对不上
比如你把 step 写成 20,下面标签却还是 0%、25%、50%、75%、100%。
这样页面会很别扭,用户也会困惑。
所以只要你改了步长,就要顺手检查标签是不是也该一起改。
2. 只改滑块,不做结果回显
如果没有上面的“评分”和“进度”文案,交互会显得很空。尤其在业务页面里,用户通常需要一个明确结果,而不是只看一个滑块位置。
3. 一个结果拆成多个状态存
如果评分数字一份状态、星级展示一份状态、提交参数再一份状态,后面很容易不同步。
一个结果,尽量由一个核心状态负责。
4. 忽略 min、max、step 的组合关系
有些同学会只改一个值,比如把 max 改成 10,但下面的标签和展示文案都没跟着改。页面虽然能跑,但逻辑已经不统一了。
这篇代码能怎么改成真实业务
你完全可以把这个案例继续改成这些页面:
| 业务方向 | 改法 |
|---|---|
| 商品评分页 | 保留上半部分评分滑块,拖动后同步展示“非常满意 / 一般 / 不推荐”等文案 |
| 系统设置页 | 把百分比滑块改成音量、亮度、字号调节 |
| 筛选面板 | 用滑块选择价格范围、距离档位、风险等级 |
| 问卷页面 | 让用户用滑块选择满意度、推荐意愿、使用频率 |
你会发现,它虽然只是一个基础案例,但可迁移性很强。
动手改一改
如果你已经读懂了,建议你顺手做几个小练习:
- 把评分滑块的范围改成
1 ~ 10。 - 把百分比滑块的步长改成
10,再把标签同步调整。 - 给评分结果增加一行描述文案,比如
1-2 星 = 不满意、4-5 星 = 满意。 - 把两个滑块拆成两个独立小卡片,练习组件拆分。
这些改动不复杂,但非常适合巩固今天这篇的理解。
写在最后
这篇案例表面上讲的是 Slider,其实更重要的是让你理解:当一个值本来就应该按固定档位变化时,界面也应该把这种规则清楚地表达出来。
如果你是 HarmonyOS7 初学者,我建议你不要只看代码,最好自己动手把 step、标签文案、结果回显都改一遍。等你能真正把“步长、刻度、状态、回显”这四件事串起来,后面再做更复杂的交互页面,思路会稳很多。
更多推荐


所有评论(0)