【HarmonyOS】鸿蒙实现刻度尺
作者:鑫
- 2025-05-07 广东
本文字数:2224 字
阅读完需:约 7 分钟
前言
近期在做鸿蒙 app 项目,有一个如图 1 所示的刻度尺,多次翻阅相关资料未找到类似的,所以纯手写了一份,在此与各位同行分享,也欢迎各位大佬点评。

图一
功能简介
刻度尺可以精确到小数点后一位
可以自定义刻度尺的刻度间隔,起始刻度数,总刻度数,当前选中的值
根据默认选中值,滑动到对应刻度
根据当前刻度尺滚动的距离自动贴合到附近最近的刻度
左右滑动刻度尺,停止滑动的时候,得到当前刻度尺值
使用
复制组件 RulerComponent 组件源码(在下面) 到 ArkTs 文件中。
在所需要的组件中引入
import { RulerComponent } from '../../component/ruler/RulerComponent';
复制代码
放入组件合适的位置:

组件源码
@Preview
@Component
export struct RulerComponent {
@Prop scaleWidth: number = 12 // 刻度间隔
@Prop totalScale: number = 33 //总刻度数
@Prop startScale: number = 1 //起始值
@Prop currentValue: number = 1.0 //当前值
@State totalArray: number[] = [] //总刻度
private scroller: Scroller = new Scroller();
scrollStopEvent: (scaleValue: number) => void = () => {
};
aboutToAppear(): void {
// 根据总刻度,创建一个刻度值组成的数组,总刻度*10,是因为需要精确到小数据后一位,
for (let i = 1; i <= this.totalScale * 10; i++) {
if ((i / 10) >= this.startScale) {
this.totalArray.push(i);
}
}
}
onDidBuild() {
// 计算滚动距离
let defaultScroll = (this.currentValue - this.startScale) * 10 * this.scaleWidth
this.scroller.scrollTo({ xOffset: defaultScroll, yOffset: 0 }) //吸附效果
}
build() {
RelativeContainer() {
this.contentBuilder()
}
.height('100')
.width('100%');
}
// 主题内容
@Builder
contentBuilder() {
Column() {
// 数值显示
Text(`${this.currentValue} mmol/L`)
.fontSize(22)
.margin({ bottom: 18 })
.fontColor("#4ad5c6")
// 刻度尺主体
Stack() {
Scroll(this.scroller) {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start }) {
ForEach(this.totalArray, (index: number) => {
this.CaleMarkBuilder(index % 10 === 0, (index / 10).toString())
})
}
.padding({
left: "50.5%",
right: "46%"
})
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.onScrollStop(() => {
this.getScaleValue()
})
// 中心指示器
this.Indicator()
}
.width("100%")
.border({
color: "#d4d5d7",
width: { top: 2 }
})
.clip(true)
}
.width("100%")
.padding({
left: 12,
right: 12
})
}
// 刻度线和数据
@Builder
CaleMarkBuilder(isBold: boolean, boldText: string) {
RelativeContainer() {
Rect()
.width(2)
.height(isBold ? 30 : 20)
.fill('#d4d5d7')
.alignRules({
top: { anchor: "__container__", align: VerticalAlign.Top },
left: { anchor: "__container__", align: HorizontalAlign.Center }
})
if (isBold) {
Text(boldText)
.fontSize(10)
.fontColor("#d4d5d7")
.width("100%")
.textAlign(TextAlign.Center)
.alignRules({
bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
})
}
}
.width(this.scaleWidth)
.height(48)
}
//中心指示器
@Builder
Indicator() {
Column() {
Text()
.width(0)
.height(0)
.border({
width: 10,
color: {
top: "#4ad5c6",
left: Color.Transparent,
right: Color.Transparent,
bottom: Color.Transparent
}
})
Rect()
.width(2)
.height(25)
.fill('#4ad5c6')
.position({ x: 9, y: 8 })
}
.position({ x: '50%', y: 0 })
}
private getScaleValue() {
let x = this.scroller.currentOffset().xOffset //偏移距离
let endX: number = 0
// 四舍五入取整
const quotient = Math.floor(x / this.scaleWidth) //121=12.1
// 计算当前数字除以 10 的余数
const remainder = x % 10
// 如果余数小于 5,最近的 10 的倍数是商乘以 10
if (remainder < 5) {
endX = quotient * this.scaleWidth
}
// 如果余数大于等于 5,最近的 10 的倍数是(商 + 1)乘以 10
else {
endX = (quotient + 1) * this.scaleWidth
}
this.scroller.scrollTo({ xOffset: endX, yOffset: 0 }) //吸附效果
this.currentValue = (this.startScale + (endX / this.scaleWidth / 10))
this.scrollStopEvent(this.currentValue)
}
}
复制代码
划线
评论
复制
发布于: 刚刚阅读数: 5
版权声明: 本文为 InfoQ 作者【鑫】的原创文章。
原文链接:【http://xie.infoq.cn/article/dff16007b09db34fccceb70a7】。文章转载请联系作者。

鑫
关注
还未添加个人签名 2025-05-06 加入
还未添加个人简介
评论