ArkUI ArcScrollBar 组件完整知识库
文档版本:v1.0 更新时间:2026-02-03 源码版本:OpenHarmony ace_engine (master 分支) 作者:基于 CLAUDE.md 规范自动生成
📚 目录
- 概述
- 完整调用链
- 目录结构
- 核心类继承关系
- Pattern层详解
- 圆形坐标系
- 角度计算逻辑
- 弧形渲染实现
- 与普通ScrollBar的区别
- 与Scroll的交互
- 动画系统
- 执行流程
- 完整API清单
- 关键实现细节
- 使用示例
- 调试指南
- 常见问题
- 附录
概述
组件定位
ArcScrollBar 组件是 OpenHarmony ArkUI 框架中的弧形滚动条组件,是普通 ScrollBar 的特殊变体,专为圆形设备或特殊 UI 设计而定制。它继承了 ScrollBar 的核心功能,但使用圆形/弧形渲染,提供独特的视觉体验。
技术栈:
- 前端:ArkTS/TypeScript
- 桥接层:ScrollModelNG (复用普通 ScrollBar 的桥接层)
- 核心层:NG Pattern 架构 (ArcScrollBarPattern)
- 代理层:ScrollBarProxy (复用普通 ScrollBar 的代理机制)
- 渲染层:Rosen + Skia (弧形绘制)
代码规模:
- 总文件数:约 6 个文件
- 核心代码:约 3,000+ 行 C++ 代码
- 涉及 3 个架构层次
功能特性
ArcScrollBar 组件支持:
- 弧形渲染:圆形/弧形滚动条,支持全圆或部分弧
- 极坐标系:使用圆心、半径和角度进行计算
- 位置模式:支持 LEFT 和 RIGHT 弧形方向
- 双层设计:背景弧(轨道)+ 前景弧(滑块)
- 交互检测:基于弧形区域的触摸/悬停检测
- 平滑动画:
- 角度过渡动画
- 透明度变化动画
- 悬停效果动画
- 兼容性:完全兼容普通 ScrollBar 的 API 和通信机制
设计模式
ArcScrollBar 组件采用 继承模式 + NG Pattern 架构:
ScrollBarPattern (普通滚动条基类)
↓ 继承
ArcScrollBarPattern (弧形滚动条)
├─ 重写布局算法创建
├─ 重写绘制方法创建
└─ 重写滚动条对象创建
↓
ArcScrollBar (弧形滚动条对象)
├─ 圆形坐标系
├─ 角度计算
└─ 弧形区域检测
核心概念:
- ArcRound:描述圆心、半径、起始角度、扫描角度
- 极坐标系:使用
(r, θ)而非(x, y) - PositionMode:LEFT/RIGHT 决定弧形方向
- 双层弧:背景弧和前景弧分离
应用场景
- 圆形设备:智能手表、圆形旋钮
- 特殊 UI 设计:需要弧形指示器的场景
- 仪表盘界面:汽车仪表盘、工业控制面板
- 创意交互:非传统的滚动条设计
完整调用链
1. 从 ArkTS 到 Pattern 的调用链
调用链图
┌─────────────────────────────────────────────────────────┐
│ 前端 ArkTS │
│ │
│ Stack() { │
│ Scroll({ scroller: this.scroller }) { │
│ // 内容 │
│ } │
│ │
│ ArcScrollBar({ scroller: this.scroller }) │
│ .width(40) │
│ .height(40) │
│ } │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Model 层 (NG) │
│ │
│ class ArcScrollBarModelNG │
│ ↓ │
│ Create(scroller, options) │
│ ↓ │
│ 创建 ArcScrollBar FrameNode │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Pattern 层(业务逻辑) │
│ │
│ class ArcScrollBarPattern : public ScrollBarPattern │
│ 源码:frameworks/core/components_ng/pattern/ │
│ arc_scroll_bar/arc_scroll_bar_pattern.cpp │
│ │
│ 核心职责: │
│ - 重写弧形布局算法创建 │
│ - 重写弧形绘制方法创建 │
│ - 创建 ArcScrollBar 对象 │
│ - 设置透明点击模式 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Render 层(渲染层) │
│ │
│ class ArcScrollBarPaintMethod │
│ class ArcScrollBarOverlayModifier │
│ │
│ 核心职责: │
│ - 绘制背景弧 │
│ - 绘制前景弧(滑块) │
│ - 处理角度动画 │
└─────────────────────────────────────────────────────────┘
↓
[弧形滚动条显示在屏幕上]
2. 弧形渲染调用链
触发布局/绘制
↓
ArcScrollBarPattern::CreateNodePaintMethod()
↓
创建 ArcScrollBarPaintMethod
↓
创建 ArcScrollBarOverlayModifier
↓
设置弧形参数
├─ SetArcRect(arcActiveRect_)
├─ SetBackgroundArcRect(arcAarRect_)
└─ SetPositionMode(positionMode_)
↓
ArcScrollBarOverlayModifier::DrawArc()
├─ DrawBackgroundArc() - 绘制轨道
└─ DrawForegroundArc() - 绘制滑块
↓
[弧形滚动条渲染完成]
目录结构
完整目录树
frameworks/core/components_ng/pattern/arc_scroll_bar/
├── arc_scroll_bar_pattern.h # ArcScrollBarPattern 类定义
├── arc_scroll_bar_pattern.cpp # ArcScrollBarPattern 实现
├── arc_scroll_bar_layout_algorithm.h # 弧形布局算法定义
├── arc_scroll_bar_layout_algorithm.cpp # 弧形布局算法实现
├── arc_scroll_bar_paint_method.h # 弧形绘制方法定义
└── arc_scroll_bar_paint_method.cpp # 弧形绘制方法实现
依赖项:
├── ../arc_scroll/inner/arc_scroll_bar.h # ArcScrollBar 类定义
├── ../arc_scroll/inner/arc_scroll_bar.cpp # ArcScrollBar 实现
├── ../arc_scroll/inner/arc_scroll_bar_overlay_modifier.h # 弧形修饰器
├── ../arc_scroll/inner/arc_scroll_bar_overlay_modifier.cpp # 弧形修饰器实现
└── ../../base/geometry/arc_round.h # ArcRound 几何类
关键文件说明
| 文件 | 职责 | 核心类/方法 |
|---|---|---|
| arc_scroll_bar_pattern.h/cpp | 核心业务逻辑 | ArcScrollBarPattern::CreateNodePaintMethod(), UseInnerScrollBar() |
| arc_scroll_bar_layout_algorithm.h/cpp | 弧形布局计算 | ArcScrollBarLayoutAlgorithm::Measure(), Layout() |
| arc_scroll_bar_paint_method.h/cpp | 弧形绘制 | ArcScrollBarPaintMethod::UpdateOverlayModifier() |
| inner/arc_scroll_bar.h | 弧形滚动条对象 | ArcScrollBar::InBarTouchRegion(), GetPositionAngle() |
| inner/arc_scroll_bar_overlay_modifier.h | 弧形修饰器 | ArcScrollBarOverlayModifier::DrawArc(), SetStartAngle() |
| base/geometry/arc_round.h | 圆形几何类 | ArcRound::GetPointByAngle(), IsInRegion() |
核心类继承关系
1. Pattern 层继承关系
Pattern (基类)
↓
ScrollBarPattern (普通滚动条基类)
├─ 显示模式管理
├─ 位置更新
└─ 用户交互处理
↓
ArcScrollBarPattern (弧形滚动条)
├─ 重写布局算法创建
├─ 重写绘制方法创建
└─ 重写滚动条对象创建
2. 关键类定义
ArcScrollBarPattern
文件:arc_scroll_bar_pattern.h:27
class ArcScrollBarPattern : public ScrollBarPattern
{
DECLARE_ACE_TYPE(ArcScrollBarPattern, ScrollBarPattern);
public:
ArcScrollBarPattern() = default;
~ArcScrollBarPattern() override = default;
// 重写:创建弧形布局算法
RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override
{
auto layoutAlgorithm = MakeRefPtr<ArcScrollBarLayoutAlgorithm>();
return layoutAlgorithm;
}
// 重写:创建弧形绘制方法
RefPtr<NodePaintMethod> CreateNodePaintMethod() override
{
auto paint = MakeRefPtr<ArcScrollBarPaintMethod>();
// 创建弧形覆盖修饰器
auto scrollBarOverlayModifier = AceType::MakeRefPtr<ArcScrollBarOverlayModifier>();
// 设置弧形参数
auto scrollBar = GetScrollBar();
auto arcScrollBar = AceType::DynamicCast<ArcScrollBar>(scrollBar);
auto arcScrollBarOverlayModifier =
AceType::DynamicCast<ArcScrollBarOverlayModifier>(scrollBarOverlayModifier);
if (arcScrollBar && arcScrollBarOverlayModifier) {
arcScrollBarOverlayModifier->SetPositionMode(arcScrollBar->GetPositionMode());
arcScrollBarOverlayModifier->SetArcRect(arcScrollBar->GetArcActiveRect());
arcScrollBarOverlayModifier->SetBackgroundArcRect(arcScrollBar->GetArcBarRect());
}
paint->SetScrollBarOverlayModifier(scrollBarOverlayModifier);
return paint;
}
// 重写:使用内置滚动条
bool UseInnerScrollBar() const override
{
return true;
}
// 重写:创建弧形滚动条对象
RefPtr<ScrollBar> CreateScrollBar() const override
{
return AceType::MakeRefPtr<ArcScrollBar>();
}
// 重写:OnModifyDone - 设置透明点击模式
void OnModifyDone() override;
};
ArcScrollBar (弧形滚动条对象)
文件:../arc_scroll/inner/arc_scroll_bar.h:22
class ArcScrollBar : public ScrollBar
{
DECLARE_ACE_TYPE(ArcScrollBar, ScrollBar);
public:
ArcScrollBar() : ScrollBar(DisplayMode::AUTO, ShapeMode::ROUND, PositionMode::RIGHT) {}
// 弧形区域访问
const ArcRound& GetArcActiveRect() const { return arcActiveRect_; }
const ArcRound& GetArcBarRect() const { return arcAarRect_; }
// 区域检测(圆形坐标)
bool InBarTouchRegion(const Point& point) const override;
bool InBarHoverRegion(const Point& point) const override;
bool InBarRectRegion(const Point& point) const override;
// 设置弧形区域
void SetBarRegion(const Offset& offset, const Size& size,
const RefPtr<PipelineContext>& context = nullptr) override;
void SetRoundTrickRegion(double estimatedHeight, double barRegionSize,
double activeSize, double activeMainOffset,
double normalWidth, const Size& size) override;
// 弧形偏移计算
float CalcPatternOffset(float scrollBarOffset) const override;
private:
ArcRound arcHoverRegion_; // 悬停区域
ArcRound arcAarRect_; // 背景弧形区域
ArcRound arcActiveRect_; // 前景弧形区域(滑块)
ArcRound arcHotZoneRect_; // 触摸热区
double trickSweepAngle_; // 滑块扫描角度
double trickStartAngle_; // 滑块起始角度
double width_; // 弧形宽度
double centerDeviation_; // 圆心偏移
};
ArcRound (弧形区域几何类)
文件:frameworks/base/geometry/arc_round.h:33
class ACE_EXPORT ArcRound {
public:
ArcRound() = default;
ArcRound(const Point& centerPoint, float radius,
float startAngle, float sweepAngle, float width);
// 核心属性
Point centerPoint_; // 圆心点
float radius_; // 半径
float startAngle_; // 起始角度(度)
float sweepAngle_; // 扫描角度(度)
float width_; // 宽度/粗细
float outerRadius_; // 外半径
Color color_; // 颜色
// 核心方法
void GetPointByAngle(float angle, Point& out) const;
float GetPositionAngle(const Offset& position) const;
bool IsInRegion(const Point& point, float minHotRegion = ORG_HOTREGION) const;
// 静态常量
static constexpr float HALF_CIRCULARITY = 180.0f; // 半圆
static constexpr float WHOLE_CIRCULARITY = 360.0f; // 全圆
static constexpr float ORG_HOTREGION = 10.0f; // 原始热区
};
Pattern层详解
ArcScrollBarPattern 核心职责
ArcScrollBarPattern 是弧形滚动条的核心逻辑层,负责:
-
重写基类方法
- 重写
CreateLayoutAlgorithm()- 创建弧形布局算法 - 重写
CreateNodePaintMethod()- 创建弧形绘制方法 - 重写
UseInnerScrollBar()- 标记使用内置滚动条 - 重写
CreateScrollBar()- 创建弧形滚动条对象
- 重写
-
配置绘制方法
- 创建
ArcScrollBarOverlayModifier - 设置弧形参数(圆心、半径、角度等)
- 配置位置模式(LEFT/RIGHT)
- 创建
-
设置交互模式
- 设置透明点击模式(
HTMTRANSPARENT) - 允许点击穿透到底层内容
- 设置透明点击模式(
关键生命周期方法
OnModifyDone()
调用时机:组件属性修改完成时
源码位置:arc_scroll_bar_pattern.cpp:20
执行流程:
void ArcScrollBarPattern::OnModifyDone()
{
// 1. 调用基类的 OnModifyDone
ScrollBarPattern::OnModifyDone();
// 2. 获取 FrameNode
auto host = GetHost();
CHECK_NULL_VOID(host);
// 3. 获取事件中心
auto hub = host->GetEventHub<EventHub>();
CHECK_NULL_VOID(hub);
// 4. 获取手势中心
auto gestureHub = hub->GetOrCreateGestureEventHub();
CHECK_NULL_VOID(gestureHub);
// 5. 设置透明点击模式
// 这允许点击穿透到底层内容,因为弧形滚动条
// 通常只占圆环的一部分
gestureHub->SetHitTestMode(HitTestMode::HTMTRANSPARENT);
}
注意事项:
- ✅ 必须调用基类的
OnModifyDone() - ✅ 设置
HTMTRANSPARENT模式允许点击穿透 - ✅ 这是弧形滚动条的特殊要求
重写方法详解
1. UseInnerScrollBar()
功能:标记使用内置滚动条对象
源码位置:arc_scroll_bar_pattern.h:62
bool UseInnerScrollBar() const override
{
return true;
}
说明:
- 返回
true表示使用ArcScrollBar内置对象 - 普通
ScrollBarPattern可能返回false
2. CreateScrollBar()
功能:创建弧形滚动条对象
源码位置:arc_scroll_bar_pattern.h:67
RefPtr<ScrollBar> CreateScrollBar() const override
{
return AceType::MakeRefPtr<ArcScrollBar>();
}
ArcScrollBar 构造函数:
ArcScrollBar::ArcScrollBar()
: ScrollBar(
DisplayMode::AUTO, // 自动显示/隐藏
ShapeMode::ROUND, // 圆形模式
PositionMode::RIGHT // 右侧位置
)
{
// 弧形滚动条初始化
}
圆形坐标系
1. 极坐标系统
普通 ScrollBar:使用笛卡尔坐标系 (x, y)
y
↑
│ (x, y)
│
└──────→ x
ArcScrollBar:使用极坐标系 (r, θ)
90°
↑
│
180° ←─ ● ─→ 0°
(圆心) │
│
270°
2. ArcRound 核心属性
文件:frameworks/base/geometry/arc_round.h:33
class ACE_EXPORT ArcRound {
private:
Point centerPoint_; // 圆心坐标
float radius_; // 半径(像素)
float startAngle_; // 起始角度(度)
float sweepAngle_; // 扫描角度(度)
float width_; // 弧形宽度/粗细(像素)
float outerRadius_; // 外半径
Color color_; // 颜色
public:
// 静态常量
static constexpr float HALF_CIRCULARITY = 180.0f; // 半圆
static constexpr float WHOLE_CIRCULARITY = 360.0f; // 全圆
static constexpr float ORG_HOTREGION = 10.0f; // 原始热区
};
3. 坐标转换方法
GetPointByAngle() - 根据角度获取点
功能:给定角度,计算弧形上的点坐标
源码位置:frameworks/base/geometry/arc_round.cpp
void ArcRound::GetPointByAngle(float angle, Point& out) const
{
// 1. 转换为弧度
float rad = angle * M_PI / 180.0f;
// 2. 计算圆上的点
out.SetX(centerPoint_.GetX() + radius_ * std::cos(rad));
out.SetY(centerPoint_.GetY() + radius_ * std::sin(rad));
}
示例:
ArcRound arc(Point(100, 100), 50, 0, 90, 10);
Point p;
arc.GetPointByAngle(45, p);
// p ≈ (135, 135) - 45° 位置
GetPositionAngle() - 从位置计算角度
功能:给定点坐标,计算相对于圆心的角度
源码位置:frameworks/base/geometry/arc_round.cpp
float ArcRound::GetPositionAngle(const Offset& position) const
{
// 1. 计算相对坐标
float dx = position.GetX() - centerPoint_.GetX();
float dy = position.GetY() - centerPoint_.GetY();
// 2. 使用 atan2 计算角度(弧度)
float angleRad = std::atan2(dy, dx);
// 3. 转换为度数
float angleDeg = angleRad * 180.0f / M_PI;
// 4. 归一化到 [0, 360)
if (angleDeg < 0) {
angleDeg += 360.0f;
}
return angleDeg;
}
示例:
ArcRound arc(Point(100, 100), 50, ...);
float angle = arc.GetPositionAngle(Offset(150, 100));
// angle ≈ 0° - 右方向
float angle = arc.GetPositionAngle(Offset(100, 150));
// angle ≈ 90° - 下方向
IsInRegion() - 区域检测
功能:判断点是否在弧形区域内
源码位置:frameworks/base/geometry/arc_round.cpp
bool ArcRound::IsInRegion(const Point& point, float minHotRegion) const
{
// 1. 计算点到圆心的距离
float dx = point.x - centerPoint_.x;
float dy = point.y - centerPoint_.y;
float distance = std::sqrt(dx * dx + dy * dy);
// 2. 检查半径范围
float innerRadius = radius_ - width_ / 2.0f;
float outerRadius = radius_ + width_ / 2.0f;
if (distance < innerRadius - minHotRegion || distance > outerRadius + minHotRegion) {
return false; // 不在半径范围内
}
// 3. 检查角度范围
float angle = GetPositionAngle(Offset(point.x, point.y));
float endAngle = startAngle_ + sweepAngle_;
// 归一化角度到 [0, 360)
auto normalizeAngle = [](float a) {
while (a < 0) a += 360.0f;
while (a >= 360.0f) a -= 360.0f;
return a;
};
angle = normalizeAngle(angle);
startAngle_ = normalizeAngle(startAngle_);
endAngle = normalizeAngle(endAngle);
// 检查是否在角度范围内
if (sweepAngle_ > 0) {
return angle >= startAngle_ && angle <= endAngle_;
} else {
return angle <= startAngle_ && angle >= endAngle_;
}
}
4. 位置模式
RIGHT 模式(默认)
描述:弧形从右侧开始,顺时针方向
90°
↑
│
180° ←─ ─→ 0° (起始)
│
270°
示例:
ArcScrollBar(PositionMode::RIGHT)
startAngle_ = 0° // 从 0° 开始
sweepAngle_ = 270° // 扫描 270°(到顶部)
LEFT 模式
描述:弧形从左侧开始,逆时针方向
90°
↑
│
←── 180° 0°
│
270°
示例:
ArcScrollBar(PositionMode::LEFT)
startAngle_ = 180° // 从 180° 开始
sweepAngle_ = -270° // 逆时针扫描 270°(到顶部)
角度计算逻辑
1. 设置弧形区域
源码位置:inner/arc_scroll_bar.cpp:48
void ArcScrollBar::SetBarRegion(
const Offset& offset,
const Size& size,
const RefPtr<PipelineContext>& context)
{
// 1. 获取弧形宽度
double normalWidth = GetNormalWidthToPx();
// 2. 计算圆心(容器中心)
Point centerPoint(size.Width() * 0.5, size.Height() * 0.5);
// 3. 计算起始角度
double startAngle = GetArcNormalStartAngle();
// 4. 计算扫描角度(基于位置模式)
double sweepAngle = (GetPositionMode() == PositionMode::LEFT) ?
-GetArcNormalMaxOffsetAngle() : // LEFT:负角度(逆时针)
GetArcNormalMaxOffsetAngle(); // RIGHT:正角度(顺时针)
// 5. 计算弧形宽度
double width = NormalizeToPx(GetArcNormalBackgroundWidth());
centerDeviation_ = width * 0.5;
// 6. 计算半径(容器半径 - 圆心偏移)
double radius = size.Width() * 0.5 - centerDeviation_;
// 7. 创建背景弧形区域
arcAarRect_ = ArcRound(centerPoint, radius, startAngle, sweepAngle, width);
}
参数说明:
normalWidth:弧形轨道宽度centerPoint:圆心(容器中心)startAngle:起始角度(通常为 0° 或 180°)sweepAngle:扫描角度(正数为顺时针,负数为逆时针)radius:半径width:弧形宽度
2. 设置滑块区域
源码位置:inner/arc_scroll_bar.cpp:68
void ArcScrollBar::SetRoundTrickRegion(
double estimatedHeight,
double barRegionSize,
double activeSize,
double activeMainOffset,
double normalWidth,
const Size& size)
{
// 1. 计算最大角度(通常为 270°)
double maxAngle = GetArcNormalMaxOffsetAngle();
// 2. 计算滑块扫描角度(与内容尺寸成正比)
trickSweepAngle_ = activeSize * maxAngle / barRegionSize;
// 3. 计算滑块起始角度(与滚动位置成正比)
trickStartAngle_ = (maxAngle - trickSweepAngle_) * activeMainOffset / (barRegionSize - activeSize);
// 4. 根据位置模式调整角度方向
if (GetPositionMode() == PositionMode::LEFT) {
// LEFT 模式:逆时针
trickStartAngle_ = 180.0f - trickStartAngle_;
trickSweepAngle_ = -trickSweepAngle_;
} else {
// RIGHT 模式:顺时针
trickStartAngle_ = trickStartAngle_;
}
// 5. 创建前景弧形区域(滑块)
double radius = size.Width() * 0.5 - centerDeviation_;
arcActiveRect_ = ArcRound(
centerPoint_, // 圆心
radius, // 半径
trickStartAngle_, // 起始角度(动态)
trickSweepAngle_, // 扫描角度(动态)
normalWidth // 宽度
);
}
参数说明:
estimatedHeight:估算高度barRegionSize:可滚动区域大小activeSize:内容大小activeMainOffset:当前滚动位置normalWidth:滑块宽度
计算逻辑:
trickSweepAngle ∝ activeSize / barRegionSize
- 内容越大 → 滑块越长(角度越大)
- 内容越小 → 滑块越短(角度越小)
trickStartAngle ∝ activeMainOffset
- 滚动位置越靠前 → 起始角度越小
- 滚动位置越靠后 → 起始角度越大
3. 计算滚动偏移
源码位置:inner/arc_scroll_bar.cpp:157
float ArcScrollBar::CalcPatternOffset(float scrollBarOffset) const
{
// 1. 计算最大角度
double maxAngle = GetArcNormalMaxOffsetAngle();
// 2. 计算滑块最大扫描角度
double maxSweepAngle = trickSweepAngle_;
// 3. 根据滚动偏移计算角度偏移
double angleOffset = scrollBarOffset * maxAngle / maxSweepAngle;
// 4. 根据位置模式调整
if (GetPositionMode() == PositionMode::LEFT) {
angleOffset = -angleOffset; // LEFT 模式:取反
}
return static_cast<float>(angleOffset);
}
反向计算(角度 → 滚动偏移):
float angle = ...; // 从点击位置计算的角度
float scrollBarOffset = angle * maxSweepAngle / maxAngle;
4. 角度与滚动位置关系
RIGHT 模式:
滚动位置 (0.0 ~ 1.0)
↓
angle = position × 270°
↓
弧从 0°(右) → 270°(顶部)
示例:
position = 0.0 → angle = 0°
position = 0.5 → angle = 135°
position = 1.0 → angle = 270°
LEFT 模式:
滚动位置 (0.0 ~ 1.0)
↓
angle = 180° - position × 270°
↓
弧从 180°(左) → 270°(顶部)
示例:
position = 0.0 → angle = 180°
position = 0.5 → angle = 45°
position = 1.0 → angle = -90° ≡ 270°
弧形渲染实现
ArcScrollBarPaintMethod
文件:arc_scroll_bar_paint_method.h:25
核心职责:
- 绘制弧形滚动条
- 管理弧形覆盖修饰器
- 处理绘制上下文
class ArcScrollBarPaintMethod : public ScrollBarPaintMethod {
public:
ArcScrollBarPaintMethod() : ScrollBarPaintMethod(false) {}
~ArcScrollBarPaintMethod() override = default;
// 重写绘制方法
void UpdateOverlayModifier(PaintWrapper* paintWrapper) override;
private:
RefPtr<ArcScrollBarOverlayModifier> scrollBarOverlayModifier_;
};
ArcScrollBarOverlayModifier
文件:inner/arc_scroll_bar_overlay_modifier.h:22
核心职责:
- 绘制背景弧
- 绘制前景弧(滑块)
- 管理弧形动画
class ArcScrollBarOverlayModifier : public ScrollBarOverlayModifier {
public:
// 绘制弧形
void DrawArc(DrawingContext& context);
void DrawBackgroundArc(DrawingContext& context);
// 设置弧形参数
void SetStartAngle(float startAngle);
void SetSweepAngle(float sweepAngle);
void SetCurveRadius(float curveRadius);
void SetArcRect(const ArcRound& arcRect);
void SetBackgroundArcRect(const ArcRound& backgroundArcRect);
void SetPositionMode(PositionMode positionMode);
// 启动动画
void StartArcBarAnimation(
HoverAnimationType hoverAnimationType,
OpacityAnimationType opacityAnimationType,
bool needAdaptAnimation,
const ArcRound& arcBarRect,
const ArcRound& backgroundArcBarRect);
private:
// 弧形属性
RefPtr<PropertyFloat> startAngle_; // 起始角度
RefPtr<PropertyFloat> sweepAngle_; // 扫描角度
RefPtr<PropertyFloat> curveRadius_; // 曲率半径
RefPtr<PropertyBool> isAlignCenter_; // 居中对齐
RefPtr<PropertyInt> positionMode_; // 位置模式
// 弧形区域
ArcRound arcRect_; // 前景弧
ArcRound backgroundArcRect_; // 背景弧
};
渲染流程
UpdateOverlayModifier() 方法
源码位置:arc_scroll_bar_paint_method.cpp:22
void ArcScrollBarPaintMethod::UpdateOverlayModifier(PaintWrapper* paintWrapper)
{
CHECK_NULL_VOID(paintWrapper);
auto scrollBarOverlayModifier = GetScrollBarOverlayModifier();
CHECK_NULL_VOID(scrollBarOverlayModifier);
auto scrollBar = GetScrollBar();
CHECK_NULL_VOID(scrollBar);
// 1. 更新位置模式
if (scrollBar->GetPositionModeUpdate()) {
scrollBarOverlayModifier->SetPositionMode(scrollBar->GetPositionMode());
}
// 2. 转换为弧形修饰器
auto arcScrollBarOverlayModifier =
AceType::DynamicCast<ArcScrollBarOverlayModifier>(scrollBarOverlayModifier);
CHECK_NULL_VOID(arcScrollBarOverlayModifier);
// 3. 转换为弧形滚动条
auto arcScrollBar = AceType::DynamicCast<ArcScrollBar>(scrollBar);
CHECK_NULL_VOID(arcScrollBar);
// 4. 设置背景颜色
arcScrollBarOverlayModifier->SetBackgroundBarColor(arcScrollBar->GetArcBackgroundColor());
// 5. 启动弧形动画
arcScrollBarOverlayModifier->StartArcBarAnimation(
arcScrollBar->GetHoverAnimationType(),
arcScrollBar->GetOpacityAnimationType(),
arcScrollBar->GetNeedAdaptAnimation(),
arcScrollBar->GetArcActiveRect(),
arcScrollBar->GetArcBarRect());
// 6. 设置滑块颜色
scrollBarOverlayModifier->SetBarColor(arcScrollBar->GetArcForegroundColor());
// 7. 重置动画类型
scrollBar->SetHoverAnimationType(HoverAnimationType::NONE);
scrollBar->SetOpacityAnimationType(OpacityAnimationType::NONE);
}
DrawArc() 方法
源码位置:inner/arc_scroll_bar_overlay_modifier.cpp
void ArcScrollBarOverlayModifier::DrawArc(DrawingContext& context)
{
// 1. 绘制背景弧(轨道)
DrawBackgroundArc(context);
// 2. 绘制前景弧(滑块)
auto arcRect = GetArcRect();
if (arcRect.GetRadius() > 0.0f && arcRect.GetSweepAngle() != 0.0f) {
DrawForegroundArc(context, arcRect);
}
}
void ArcScrollBarOverlayModifier::DrawBackgroundArc(DrawingContext& context)
{
// 1. 获取背景弧参数
auto backgroundArcRect = GetBackgroundArcRect();
Point center = backgroundArcRect.GetCenterPoint();
float radius = backgroundArcRect.GetRadius();
float startAngle = backgroundArcRect.GetStartAngle();
float sweepAngle = backgroundArcRect.GetSweepAngle();
float width = backgroundArcRect.GetWidth();
// 2. 创建路径
auto path = std::make_unique<DrawingPath>();
// 3. 添加弧形路径
// 从起始角度扫描到结束角度
float endAngle = startAngle + sweepAngle;
path->AddArc(center.x, center.y, radius, startAngle, endAngle);
// 4. 设置绘制属性
auto brush = context.GetBrush();
brush.SetColor(backgroundArcRect.GetColor());
context.SetBrush(brush);
auto pen = context.GetPen();
pen.SetWidth(width);
context.SetPen(pen);
// 5. 绘制
context.DrawPath(*path);
}
与普通ScrollBar的区别
1. 继承关系对比
普通 ScrollBar:
Pattern → ScrollBarPattern
ArcScrollBar:
Pattern → ScrollBarPattern → ArcScrollBarPattern
2. 渲染方法对比
| 特性 | 普通 ScrollBar | ArcScrollBar |
|---|---|---|
| 形状 | 矩形条 | 圆形/弧形 |
| 坐标系 | 笛卡尔 (x, y) |
极坐标 (r, θ) |
| 位置计算 | 线性插值 | 角度插值 |
| 区域检测 | 矩形边界 | 弧形边界 |
| PaintMethod | ScrollBarPaintMethod |
ArcScrollBarPaintMethod |
| Modifier | ScrollBarOverlayModifier |
ArcScrollBarOverlayModifier |
3. 对象创建对比
普通 ScrollBar:
RefPtr<ScrollBar> ScrollBarPattern::CreateScrollBar() const
{
return AceType::MakeRefPtr<ScrollBar>(
DisplayMode::AUTO,
ShapeMode::RECT, // 矩形
PositionMode::RIGHT
);
}
ArcScrollBar:
RefPtr<ScrollBar> ArcScrollBarPattern::CreateScrollBar() const
{
return AceType::MakeRefPtr<ArcScrollBar>(
DisplayMode::AUTO,
ShapeMode::ROUND, // 圆形 ← 关键区别
PositionMode::RIGHT
);
}
4. 交互检测对比
普通 ScrollBar - 矩形检测:
bool ScrollBar::InBarTouchRegion(const Point& point) const
{
// 矩形边界检测
return point.x >= left && point.x <= right &&
point.y >= top && point.y <= bottom;
}
ArcScrollBar - 弧形检测:
bool ArcScrollBar::InBarTouchRegion(const Point& point) const
{
// 弧形边界检测
return arcHotZoneRect_.IsInRegion(point, MIN_HOTREGION.ConvertToPx());
}
5. 位置更新对比
普通 ScrollBar - 线性位置:
void ScrollBarPattern::UpdateScrollBarPosition()
{
float positionRatio = currentOffset_ / scrollableDistance_;
// 直接使用比例更新位置
scrollBar_->UpdatePosition(positionRatio);
}
ArcScrollBar - 角度位置:
void ArcScrollBarPattern::UpdateScrollBarPosition()
{
float positionRatio = currentOffset_ / scrollableDistance_;
// 转换为角度
float angle = positionRatio * maxAngle;
// 更新弧形位置
auto arcScrollBar = AceType::DynamicCast<ArcScrollBar>(scrollBar_);
arcScrollBar->SetCurrentAngle(angle);
}
与Scroll的交互
通信方式
ArcScrollBar 通过 ScrollBarProxy 与 Scroll 通信,与普通 ScrollBar 相同:
Scroll (ScrollablePattern)
↓ 注册
ScrollBarProxy (中介)
↓ 管理
ArcScrollBar (via ScrollBarPattern)
注册流程
// 1. Scroll 侧注册
void ScrollModelNG::SetScrollBar(DisplayMode displayMode, const std::string& id)
{
// 创建 ScrollableNodeInfo
ScrollableNodeInfo scrollableNode;
scrollableNode.scrollableNode = WeakClaim(this);
scrollableNode.onPositionChanged = [...] (double distance, ...) {
// 滚动回调
pattern->UpdateCurrentOffset(distance, source);
};
// 注册到 Proxy
auto proxy = ScrollBarProxy::GetInstance();
proxy->RegisterScrollableNode(scrollableNode);
}
// 2. ArcScrollBar 侧注册
void ArcScrollBarPattern::OnAttachToFrameNode()
{
// 创建 ArcScrollBar 对象
auto scrollBar = AceType::MakeRefPtr<ArcScrollBar>();
// 注册到 Proxy
auto proxy = GetScrollBarProxy();
if (proxy) {
proxy->RegisterScrollBar(AceType::WeakClaim(this));
}
}
双向通知机制
Scroll → ArcScrollBar
// Scroll 滚动
bool ScrollPattern::UpdateCurrentOffset(float offset, int32_t source)
{
currentOffset_ += offset;
// 通知 ScrollBar 更新
if (scrollBarProxy_) {
scrollBarProxy_->NotifyScrollBar(source);
}
return true;
}
// Proxy 通知 ArcScrollBar
void ScrollBarProxy::NotifyScrollBar(int32_t scrollSource)
{
for (auto& weakScrollBar : scrollBars_) {
auto scrollBar = weakScrollBar.Upgrade();
if (scrollBar) {
scrollBar->SetCurrentPosition(currentOffset_);
scrollBar->UpdateScrollBarPosition(); // ← ArcScrollBar 重写此方法
}
}
}
ArcScrollBar → Scroll
// 用户拖动 ArcScrollBar
void ArcScrollBarPattern::OnDragUpdate(const GestureEvent& info)
{
// 1. 计算角度偏移
float angleDelta = CalculateAngleDelta(info);
// 2. 转换为滚动偏移
float scrollDelta = CalcPatternOffset(angleDelta);
// 3. 通知 Proxy
if (scrollBarProxy_) {
scrollBarProxy_->NotifyScrollableNode(
scrollDelta, SCROLL_FROM_BAR, AceType::WeakClaim(this), axis_);
}
}
// Proxy 通知 Scroll
void ScrollBarProxy::NotifyScrollableNode(float distance, ...) const
{
for (auto& scrollableNode : scrollableNodes_) {
if (scrollableNode.onPositionChanged) {
scrollableNode.onPositionChanged(distance, source, ...);
}
}
}
动画系统
动画类型
- 角度动画:滑块角度平滑过渡
- 透明度动画:显示/隐藏淡入淡出
- 悬停动画:鼠标悬停效果
StartArcBarAnimation()
源码位置:inner/arc_scroll_bar_overlay_modifier.cpp
void ArcScrollBarOverlayModifier::StartArcBarAnimation(
HoverAnimationType hoverAnimationType,
OpacityAnimationType opacityAnimationType,
bool needAdaptAnimation,
const ArcRound& arcBarRect,
const ArcRound& backgroundArcBarRect)
{
// 1. 启动悬停动画
StartHoverAnimation(arcBarRect, backgroundArcBarRect, hoverAnimationType);
// 2. 设置角度动画属性
if (needAdaptAnimation) {
startAngle_->Set(arcBarRect.GetStartAngle());
sweepAngle_->Set(arcBarRect.GetSweepAngle());
}
// 3. 设置半径动画
curveRadius_->Set(arcBarRect.GetRadius());
// 4. 启动透明度动画
if (opacityAnimationType != OpacityAnimationType::NONE) {
StartOpacityAnimation(opacityAnimationType);
}
}
角度过渡动画
// 角度属性动画
auto angleAnimation = AceType::MakeRefPtr<CurveAnimation<float>>(
startAngle,
endAngle,
Curves::FAST_OUT_SLOW_IN
);
angleAnimation->AddListener([this](float angle) {
startAngle_->Set(angle);
// 触发重绘
auto host = host_.Upgrade();
if (host) {
host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
}
});
animation->AddAngleAnimation(angleAnimation);
animation->SetDuration(300); // 300ms
执行流程
1. 初始化流程
ArkTS: Scroll() { ... }
↓
ScrollModelNG::SetScrollBar(displayMode, id)
↓
SetScrollBarArc(...) ← 弧形配置
↓
创建 ArcScrollBarPattern
↓
ArcScrollBarPattern::OnAttachToFrameNode()
├─ CreateScrollBar() → 创建 ArcScrollBar 对象
├─ InitDragEvent() - 初始化拖动手势
└─ InitMouseEvent() - 初始化鼠标事件
↓
注册到 ScrollBarProxy
↓
[初始化完成]
2. 布局流程
触发布局
↓
ArcScrollBarPattern::CreateLayoutAlgorithm()
↓
ArcScrollBarLayoutAlgorithm::Measure()
├─ 测量容器尺寸
└─ 计算圆心和半径
↓
ArcScrollBarLayoutAlgorithm::Layout()
├─ SetBarRegion() - 设置弧形区域
└─ SetRoundTrickRegion() - 设置滑块区域
↓
[布局完成]
3. 绘制流程
触发绘制
↓
ArcScrollBarPaintMethod::UpdateOverlayModifier()
↓
获取 ArcScrollBar 对象
↓
获取 ArcRound 参数
├─ centerPoint(圆心)
├─ radius(半径)
├─ startAngle(起始角度)
└─ sweepAngle(扫描角度)
↓
ArcScrollBarOverlayModifier::DrawArc()
├─ DrawBackgroundArc() - 绘制轨道
└─ DrawForegroundArc() - 绘制滑块
↓
[绘制完成]
完整API清单
ArkTS API 列表
创建 ArcScrollBar 组件
// 创建弧形滚动条
ArcScrollBar()
ArcScrollBar(options: { scroller: Scroller, state?: ScrollState })
// 滚动控制器(必填)
scroller: Scroller
// 显示状态(可选)
// BarState.Auto - 自动显示/隐藏(默认)
// BarState.On - 始终显示
// BarState.Off - 始终隐藏
完整使用示例
Stack() {
// 可滚动组件
Scroll({ scroller: this.scroller }) {
// 内容
}
// 弧形滚动条
ArcScrollBar({ scroller: this.scroller })
.width(40) // 设置宽度
.height(40) // 设置高度
}
完整 API 映射表
| ArkTS API | Model 层方法 | LayoutProperty | PaintProperty | Pattern 影响 | 说明 |
|---|---|---|---|---|---|
ArcScrollBar({ scroller }) |
Create() |
- | - | 创建 ArcScrollBar FrameNode | 创建弧形滚动条组件 |
ArcScrollBar({ state }) |
Create() |
- | - | displayMode_ |
设置显示状态 |
注意:
- ArcScrollBar 是独立组件,需要与可滚动组件(Scroll、ArcList、List、Grid、WaterFlow)配合使用
- 通过 scroller 控制器与可滚动组件绑定
- 必须设置 width 和 height 属性
- 不超出官方 API 文档的范围
C++ API 列表
ArcScrollBarPattern 公共方法
// 重写方法
RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override;
RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
bool UseInnerScrollBar() const override;
RefPtr<ScrollBar> CreateScrollBar() const override;
void OnModifyDone() override;
ArcScrollBar 公共方法
// 弧形区域访问
const ArcRound& GetArcActiveRect() const;
const ArcRound& GetArcBarRect() const;
// 区域检测
bool InBarTouchRegion(const Point& point) const override;
bool InBarHoverRegion(const Point& point) const override;
bool InBarRectRegion(const Point& point) const override;
// 设置弧形区域
void SetBarRegion(const Offset& offset, const Size& size, ...) override;
void SetRoundTrickRegion(double estimatedHeight, double barRegionSize, ...) override;
// 偏移计算
float CalcPatternOffset(float scrollBarOffset) const override;
ArcRound 公共方法
// 构造函数
ArcRound(const Point& centerPoint, float radius,
float startAngle, float sweepAngle, float width);
// 坐标转换
void GetPointByAngle(float angle, Point& out) const;
float GetPositionAngle(const Offset& position) const;
// 区域检测
bool IsInRegion(const Point& point, float minHotRegion = ORG_HOTREGION) const;
// 静态常量
static constexpr float HALF_CIRCULARITY = 180.0f;
static constexpr float WHOLE_CIRCULARITY = 360.0f;
static constexpr float ORG_HOTREGION = 10.0f;
关键实现细节
1. 角度与位置转换
位置 → 角度(滚动时):
float PositionToAngle(float position, float maxAngle)
{
// position: 0.0 ~ 1.0
// maxAngle: 270° (或 360°)
return position * maxAngle;
}
角度 → 位置(点击时):
float AngleToPosition(float angle, float maxAngle)
{
// angle: 0° ~ 270°
// maxAngle: 270° (或 360°)
return angle / maxAngle;
}
角度 → 滚动偏移:
float AngleToScrollOffset(float angle, float scrollableDistance, float maxAngle)
{
float position = AngleToPosition(angle, maxAngle);
return position * scrollableDistance;
}
2. 滑块角度计算
滑块长度(角度):
float CalcTrickSweepAngle(float contentSize, float viewportSize, float maxAngle)
{
float ratio = viewportSize / contentSize;
return ratio * maxAngle;
}
滑块起始角度:
float CalcTrickStartAngle(float scrollOffset, float scrollableDistance, float maxAngle, float trickSweepAngle)
{
float movableAngle = maxAngle - trickSweepAngle;
float position = scrollOffset / scrollableDistance;
return position * movableAngle;
}
3. PositionMode 角度调整
void AdjustAngleByPositionMode(float& angle, PositionMode mode)
{
if (mode == PositionMode::LEFT) {
// LEFT 模式:从 180° 开始,逆时针
angle = 180.0f - angle;
if (angle < 0) {
angle += 360.0f;
}
}
// RIGHT 模式:从 0° 开始,顺时针(无需调整)
}
4. 透明点击模式
设置原因:
弧形滚动条通常只占圆环的一部分(例如 270°),剩余区域应允许点击穿透到底层内容。
实现:
void ArcScrollBarPattern::OnModifyDone()
{
ScrollBarPattern::OnModifyDone();
auto host = GetHost();
CHECK_NULL_VOID(host);
auto hub = host->GetEventHub<EventHub>();
CHECK_NULL_VOID(hub);
auto gestureHub = hub->GetOrCreateGestureEventHub();
CHECK_NULL_VOID(gestureHub);
// 设置透明点击模式
gestureHub->SetHitTestMode(HitTestMode::HTMTRANSPARENT);
}
使用示例
示例 1:基础弧形滚动条
@Entry
@Component
struct BasicArcScrollBar {
private scroller: Scroller = new Scroller()
build() {
Stack() {
Scroll({ scroller: this.scroller }) {
Column() {
ForEach(Array.from({ length: 20 }), (_, index) => {
Text(`Item ${index}`)
.width('100%')
.height(80)
})
}
}
.width('100%')
.height('100%')
.scrollable(ScrollDirection.Vertical)
ArcScrollBar({ scroller: this.scroller })
.width(40)
.height(40)
}
.width('100%')
.height('100%')
}
}
示例 2:自定义尺寸弧形滚动条
@Entry
@Component
struct CustomSizeArcScrollBar {
private scroller: Scroller = new Scroller()
build() {
Stack() {
Scroll({ scroller: this.scroller }) {
Column() {
ForEach(Array.from({ length: 20 }), (_, index) => {
Text(`Item ${index}`)
.width('100%')
.height(80)
})
}
}
.scrollable(ScrollDirection.Vertical)
ArcScrollBar({ scroller: this.scroller })
.width(50) // 自定义宽度
.height(50) // 自定义高度
}
.width('100%')
.height('100%')
}
}
示例 3:始终显示弧形滚动条
@Entry
@Component
struct AlwaysOnArcScrollBar {
private scroller: Scroller = new Scroller()
build() {
Stack() {
Scroll({ scroller: this.scroller }) {
Column() {
ForEach(Array.from({ length: 20 }), (_, index) => {
Text(`Item ${index}`)
.width('100%')
.height(80)
})
}
}
.scrollable(ScrollDirection.Vertical)
ArcScrollBar({
scroller: this.scroller,
state: BarState.On // 始终显示
})
.width(40)
.height(40)
}
}
}
示例 4:与 ArcList 配合使用
@Entry
@Component
struct ArcListWithScrollBar {
private scroller: Scroller = new Scroller()
@State items: Array<number> = Array.from({ length: 50 }, (_, i) => i)
build() {
Stack() {
ArcList({ scroller: this.scroller }) {
ForEach(this.items, (item: number) => {
ArcListItem() {
Text(`Item ${item}`)
.fontSize(16)
}
}, (item: number) => item.toString())
}
ArcScrollBar({ scroller: this.scroller })
.width(40)
.height(40)
}
}
}
示例 5:与 List 配合使用
@Entry
@Component
struct ListWithArcScrollBar {
private scroller: Scroller = new Scroller()
@State items: Array<number> = Array.from({ length: 100 }, (_, i) => i)
build() {
Stack() {
List({ scroller: this.scroller }) {
ForEach(this.items, (item: number) => {
ListItem() {
Text(`Item ${item}`)
.width('100%')
.height(60)
}
}, (item: number) => item.toString())
}
.width('80%')
.height('100%')
.edgeEffect(EdgeEffect.Spring)
ArcScrollBar({ scroller: this.scroller })
.width(20)
.height(20)
}
}
}
示例 6:与 Grid 配合使用
@Entry
@Component
struct GridWithArcScrollBar {
private scroller: Scroller = new Scroller()
build() {
Stack() {
Grid({ scroller: this.scroller }) {
ForEach(Array.from({ length: 50 }), (_, index) => {
GridItem() {
Text(`Item ${index}`)
.width('100%')
.height('100%')
.textAlign(TextAlign.Center)
}
.width(80)
.height(80)
})
}
.columnsTemplate('1fr 1fr 1fr')
.rowsGap(10)
.columnsGap(10)
ArcScrollBar({ scroller: this.scroller })
.width(30)
.height(30)
}
}
}
调试指南
1. 日志调试
使用专用日志标签:
#include "base/log/ace_trace.h"
// 弧形滚动条相关日志
TAG_LOGI(AceLogTag::ACE_SCROLL_BAR, "ArcScrollBar: startAngle=%{public}f, sweepAngle=%{public}f",
startAngle, sweepAngle);
// 角度计算日志
TAG_LOGD(AceLogTag::ACE_SCROLL_BAR, "CalcTrickStartAngle: angle=%{public}f", angle);
2. Dump 调试
实现 dump 方法:
void ArcScrollBarPattern::DumpInfo(std::unique_ptr<JsonValue>& json)
{
auto scrollBar = GetScrollBar();
CHECK_NULL_VOID(scrollBar);
auto arcScrollBar = AceType::DynamicCast<ArcScrollBar>(scrollBar);
CHECK_NULL_VOID(arcScrollBar);
// 弧形区域信息
auto arcRect = arcScrollBar->GetArcActiveRect();
json->Put("centerX", arcRect.GetCenterPoint().x);
json->Put("centerY", arcRect.GetCenterPoint().y);
json->Put("radius", arcRect.GetRadius());
json->Put("startAngle", arcRect.GetStartAngle());
json->Put("sweepAngle", arcRect.GetSweepAngle());
// 位置模式
json->Put("positionMode", static_cast<int>(arcScrollBar->GetPositionMode()));
}
3. 调试器检查
关键变量:
// ArcScrollBar 状态
arcAarRect_ // 背景弧形区域
arcActiveRect_ // 前景弧形区域(滑块)
arcHotZoneRect_ // 触摸热区
trickSweepAngle_ // 滑块扫描角度
trickStartAngle_ // 滑块起始角度
centerDeviation_ // 圆心偏移
4. 常见问题定位
问题 1:弧形不显示
检查点:
ShapeMode是否为ROUND?startAngle和sweepAngle是否有效?radius是否大于 0?
定位方法:
auto arcScrollBar = AceType::DynamicCast<ArcScrollBar>(scrollBar);
if (arcScrollBar) {
auto arcRect = arcScrollBar->GetArcActiveRect();
TAG_LOGI(AceLogTag::ACE_SCROLL_BAR,
"ArcRect: radius=%{public}f, startAngle=%{public}f, sweepAngle=%{public}f",
arcRect.GetRadius(), arcRect.GetStartAngle(), arcRect.GetSweepAngle());
}
问题 2:点击无响应
检查点:
IsInRegion()返回值MIN_HOTREGION是否合理?- 是否设置了
HTMTRANSPARENT模式?
定位方法:
bool ArcScrollBar::InBarTouchRegion(const Point& point) const
{
bool inRegion = arcHotZoneRect_.IsInRegion(point, MIN_HOTREGION.ConvertToPx());
TAG_LOGI(AceLogTag::ACE_SCROLL_BAR,
"InBarTouchRegion: point=(%{public}f,%{public}f), inRegion=%{public}d",
point.x, point.y, inRegion);
return inRegion;
}
问题 3:角度计算错误
检查点:
trickSweepAngle_计算是否正确?trickStartAngle_是否在合理范围?- PositionMode 角度调整是否正确?
定位方法:
TAG_LOGI(AceLogTag::ACE_SCROLL_BAR,
"SetRoundTrickRegion: trickSweepAngle=%{public}f, trickStartAngle=%{public}f, positionMode=%{public}d",
trickSweepAngle_, trickStartAngle_, static_cast<int>(GetPositionMode()));
常见问题
Q1: ArcScrollBar 与普通 ScrollBar 如何选择?
A:
- 普通 ScrollBar:适用于矩形界面、桌面应用
- ArcScrollBar:适用于圆形设备、特殊 UI 设计
Q2: ArcScrollBar 如何与 Scroll 配合使用?
A:
Stack() {
Scroll({ scroller: this.scroller }) {
// 内容
}
ArcScrollBar({ scroller: this.scroller })
.width(40)
.height(40)
}
Q3: ArcScrollBar 支持哪些可滚动组件?
A:
- Scroll
- ArcList
- List
- Grid
- WaterFlow
Q4: ArcScrollBar 的显示状态有哪些?
A:
BarState.Auto- 自动显示/隐藏(默认)BarState.On- 始终显示BarState.Off- 始终隐藏
Q5: 为什么 ArcScrollBar 不显示?
A:
- 确保已设置
width和height属性 - 确保
scroller与可滚动组件绑定正确 - 检查可滚动组件的内容是否超出显示区域
Q6: ArcScrollBar 能与普通 ScrollBar 一起使用吗?
A: 不推荐。一个可滚动组件建议只关联一个滚动条。
Q7: 如何调整 ArcScrollBar 的尺寸?
A:
ArcScrollBar({ scroller: this.scroller })
.width(50) // 设置宽度
.height(50) // 设置高度
Q8: ArcScrollBar 适用于哪些场景?
A:
- 圆形智能手表
- 圆形旋钮
- 汽车仪表盘
- 工业控制面板
- 创意交互设计
Q9: ArcScrollBar 需要设置哪些必填属性?
A:
scroller: Scroller- 滚动控制器(必填)width: Length- 宽度(必填)height: Length- 高度(必填)
Q10: ArcScrollBar 支持的颜色设置有哪些?
A: 当前 ArcScrollBar 组件使用系统默认颜色,暂不支持自定义颜色。
附录
A. 术语表
| 术语 | 英文 | 描述 |
|---|---|---|
| 弧形滚动条 | ArcScrollBar | 圆形/弧形滚动条 |
| 极坐标 | Polar Coordinates | (r, θ) 坐标系 |
| 圆心 | Center Point | 弧形的圆心 |
| 半径 | Radius | 弧形的半径 |
| 起始角度 | Start Angle | 弧形的起始角度(度) |
| 扫描角度 | Sweep Angle | 弧形的扫描角度(度) |
| 位置模式 | PositionMode | LEFT/RIGHT 决定弧形方向 |
| 热区 | Hot Zone | 触摸热区 |
| 轨道 | Background Arc | 背景弧(轨道) |
| 滑块 | Foreground Arc | 前景弧(滑块) |
B. 源码文件索引
| 文件 | 行数 | 描述 |
|---|---|---|
arc_scroll_bar_pattern.h |
~76 | ArcScrollBarPattern 定义 |
arc_scroll_bar_pattern.cpp |
~30 | ArcScrollBarPattern 实现 |
arc_scroll_bar_layout_algorithm.h |
~36 | 布局算法定义 |
arc_scroll_bar_layout_algorithm.cpp |
~61 | 布局算法实现 |
arc_scroll_bar_paint_method.h |
~33 | 绘制方法定义 |
arc_scroll_bar_paint_method.cpp |
~46 | 绘制方法实现 |
inner/arc_scroll_bar.h |
~60 | ArcScrollBar 类定义 |
inner/arc_scroll_bar.cpp |
~174 | ArcScrollBar 实现 |
inner/arc_scroll_bar_overlay_modifier.h |
~70 | 弧形修饰器定义 |
base/geometry/arc_round.h |
~150+ | ArcRound 几何类 |
C. 相关文档
D. 版本历史
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.0 | 2026-02-03 | 初始版本 |
文档结束
本文档基于 OpenHarmony ace_engine 源码分析生成,如有错误或遗漏,欢迎指正。