HarmonyOS鸿蒙Next中如何实现一个可拖动的环形进度条,且支持自定义背景图片
HarmonyOS鸿蒙Next中如何实现一个可拖动的环形进度条,且支持自定义背景图片
想实现类似图中的环形进度条拖动效果,要求:
-
可以通过拖动末端(下面红框)来调整圆环的进度,从 0 到 360 度
-
首端(上面红框)、末端(下面红框)以及轨道(红色箭头部分)的背景可以使用自定义图片
我看了下,progress、datapanel 好像都不太适合,是不是只能用 canvas + 监听 touch 事件自行实现?期望能给出简单 demo,谢谢!
在HarmonyOS Next中,可通过Canvas组件绘制可拖动的环形进度条。使用CanvasRenderingContext2D的arc方法绘制环形轨道和进度条,通过@Watch监听触摸事件处理拖动逻辑。自定义背景图片通过Image组件或PixelMap实现,可将其设置为Canvas背景或叠加在环形图层下方。利用Canvas的矩阵变换功能调整图片尺寸和位置,确保与进度条视觉协调。具体实现涉及角度计算和手势交互处理,需结合ArkTS声明式开发完成。
更多关于HarmonyOS鸿蒙Next中如何实现一个可拖动的环形进度条,且支持自定义背景图片的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,实现可拖动的自定义环形进度条,推荐使用Canvas结合触摸事件处理,因为Progress和DataPanel组件无法直接支持拖动交互和图片背景自定义。以下是关键实现思路和代码示例:
- 使用Canvas绘制环形进度条:通过
CanvasRenderingContext2D绘制圆环轨道、进度填充及首尾端点。 - 自定义图片资源:将图片资源放入
resources/base/media/目录,通过ResourceManager加载。 - 触摸事件处理:监听
onTouch事件,计算触摸点与圆心的角度,动态更新进度值并重绘。
示例代码(基于ArkTS):
@Entry
@Component
struct DraggableCircularProgress {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private ctx: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
private progress: number = 0; // 进度值(0-360)
private centerX: number = 150;
private centerY: number = 150;
private radius: number = 100;
build() {
Column() {
Canvas(this.ctx)
.width(300)
.height(300)
.backgroundColor('#f0f0f0')
.onReady(() => {
this.drawProgress();
})
.onTouch((event: TouchEvent) => {
this.handleTouch(event);
})
}
}
// 绘制进度条
private drawProgress() {
this.ctx.clearRect(0, 0, 300, 300);
// 绘制轨道(使用自定义图片,此处用颜色代替)
this.ctx.beginPath();
this.ctx.arc(this.centerX, this.centerY, this.radius, 0, Math.PI * 2);
this.ctx.strokeStyle = '#e0e0e0';
this.ctx.lineWidth = 10;
this.ctx.stroke();
// 绘制进度(使用自定义图片,此处用颜色代替)
this.ctx.beginPath();
this.ctx.arc(this.centerX, this.centerY, this.radius, -Math.PI/2, (this.progress * Math.PI / 180) - Math.PI/2);
this.ctx.strokeStyle = '#007dff';
this.ctx.lineWidth = 10;
this.ctx.stroke();
// 绘制首端和末端(使用自定义图片,此处用圆形代替)
this.drawEndpoint(this.progress);
}
// 绘制端点
private drawEndpoint(angle: number) {
const radian = (angle - 90) * Math.PI / 180;
const x = this.centerX + this.radius * Math.cos(radian);
const y = this.centerY + this.radius * Math.sin(radian);
this.ctx.beginPath();
this.ctx.arc(x, y, 15, 0, Math.PI * 2);
this.ctx.fillStyle = '#ff0000';
this.ctx.fill();
}
// 处理触摸事件
private handleTouch(event: TouchEvent) {
if (event.type === TouchType.Move) {
const touchX = event.touches[0].x;
const touchY = event.touches[0].y;
// 计算触摸点相对于圆心的角度
let angle = Math.atan2(touchY - this.centerY, touchX - this.centerX) * 180 / Math.PI + 90;
if (angle < 0) angle += 360;
this.progress = Math.min(360, Math.max(0, angle));
this.drawProgress();
}
}
}
自定义图片实现:
- 将图片文件放入
resources/base/media/,通过$r('app.media.imageName')加载。 - 在绘制轨道和端点时,使用
drawImage方法替换颜色填充。
注意事项:
- 需要处理图片加载的异步逻辑,确保绘制时资源已就绪。
- 可通过调整
lineWidth和端点半径控制视觉效果。 - 触摸事件中需添加边界判断,避免进度值超出范围。
此方案提供了完整的交互逻辑和绘制流程,实际应用中可根据需求调整样式和交互细节。

