HarmonyOS鸿蒙Next中目前有一个圆形文本选择器,用现在的api组件实现起来比较困难,帮忙看看技术上如何实现最省时间
HarmonyOS鸿蒙Next中目前有一个圆形文本选择器,用现在的api组件实现起来比较困难,帮忙看看技术上如何实现最省时间 目前有一个圆形文本选择器,用现在的api组件实现起来比较困难,然后项目时间又比较赶,没那么多精力去完成这个,帮忙看看技术上如何实现最省时间
4 回复
你好,可以参考一下这个demo。
@Entry
@Component
struct RoundTextChoosePage {
@State items: number[] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
]
@State currentIndex: number = 0
@State value: number = 1
private radius: number = 120
private startAngle: number = 0
private lastAngle: number = 0
private _rotation: number = 0
private canvasCtx: CanvasRenderingContext2D = new CanvasRenderingContext2D()
build() {
Column() {
Text('圆形文本选择器')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ top: 30, bottom: 20 })
Text(`日期:${this.value}号`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 })
Canvas(this.canvasCtx)
.width(320)
.height(320)
.backgroundColor('#ffeecc')
.onReady(() => this.draw())
.onTouch(e => this.handleTouch(e))
Button('确定')
.width('80%')
.margin({ top: 50 })
.onClick(() => {
this.value = this.items[this.currentIndex]
})
}
.width('100%')
.height('100%')
}
/* ---------------- 绘制 ---------------- */
private draw() {
const ctx = this.canvasCtx
ctx.clearRect(0, 0, 320, 320)
const centerX = 160
const centerY = 160
const step = 2 * Math.PI / this.items.length
this.currentIndex = this.calculateCurrentIndex()
this.items.forEach((v, i) => {
const angle = i * step + this._rotation
const x = centerX + this.radius * Math.cos(angle - Math.PI / 2)
const y = centerY + this.radius * Math.sin(angle - Math.PI / 2)
if (i === this.currentIndex) {
ctx.fillStyle = '#ff0000'
ctx.font = 'bold 90px sans-serif'
} else {
ctx.fillStyle = '#999'
ctx.font = '40px sans-serif'
}
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText(v.toString(), x, y)
})
}
/**
* 计算“离顶部中心最近”的 item
* 保证任何时刻只返回一个 index
*/
private calculateCurrentIndex(): number {
const step = 2 * Math.PI / this.items.length
let min = Infinity
let index = 0
this.items.forEach((_, i) => {
const angle = i * step + this._rotation
const diff =
((angle - Math.PI / 2) % (2 * Math.PI) + Math.PI) % (2 * Math.PI) - Math.PI
const abs = Math.abs(diff)
if (abs < min) {
min = abs
index = i
}
})
return index
}
/* ---------------- 手势 ---------------- */
private handleTouch(e: TouchEvent) {
const touch = e.touches[0]
if (e.type === TouchType.Down) {
this.startAngle = this.getAngle(touch.x, touch.y)
this.lastAngle = this._rotation
}
if (e.type === TouchType.Move) {
const cur = this.getAngle(touch.x, touch.y)
this._rotation = this.lastAngle + (cur - this.startAngle)
this.draw()
}
if (e.type === TouchType.Up) {
this.snapToNearest()
}
}
private snapToNearest() {
const step = 2 * Math.PI / this.items.length
const target = Math.round(this._rotation / step) * step
animateTo({
duration: 200,
curve: Curve.EaseOut,
onFinish: () => this.draw()
}, () => {
this._rotation = target
})
}
/* ---------------- 工具 ---------------- */
private getAngle(x: number, y: number): number {
return Math.atan2(y - 160, x - 160)
}
}
更多关于HarmonyOS鸿蒙Next中目前有一个圆形文本选择器,用现在的api组件实现起来比较困难,帮忙看看技术上如何实现最省时间的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
如果加上类似于保险箱的密码的换一个数字就嘀嗒一声就好玩了,
在HarmonyOS鸿蒙Next中实现圆形文本选择器,可通过自定义组件结合Canvas绘制实现。使用Canvas的drawText方法结合Path进行环形布局,通过触摸事件处理选中逻辑。利用ArkUI的声明式UI和状态管理,可高效更新选中状态。建议参考官方文档中的Canvas和自定义组件示例。


