滚动条 Scroller
当内容太多,一个屏幕塞不下时,我们就需要滚动条。HiEasyX 的 Scroller 是一个容器型控件:它包裹住里面所有的子控件,当它们超出可视区域时,自动提供水平和/或竖直滚动条。
把 BeginScroller 和 EndScroller 想象成一对括号:中间的所有控件都会被“装”进一个可滚动的盒子里。
函数原型
void BeginScroller(ScrollerProfile &Profile);
void EndScroller(ScrollerProfile &Profile);
参数说明
ScrollerProfile
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Size | HXPoint | — | 滚动容器的外部尺寸(可视区域大小)。必须手动设置。 |
ViewSpace | HXPoint | {0, 0} | 内部内容的虚拟尺寸。通常由布局系统根据子控件自动计算,你也可以手动指定。 |
Where | HXPoint | {0, 0} | 相对当前窗口的偏移。通常由布局系统自动计算。 |
VerticalVPer | float | 0.0f | 竖直滚动位置(0.0 ~ 1.0)。内部状态。 |
HorizontalVPer | float | 0.0f | 水平滚动位置。内部状态。 |
Visible | bool | true | 是否可见。设为 false 时隐藏整个滚动区域及其内容。 |
VerticalButton | bool | false | 竖直滚动条按钮是否被按下。内部状态。 |
HorizontalButton | bool | false | 水平滚动条按钮是否被按下。内部状态。 |
ScrollbarThickness | int | 10 | 滚动条的粗细,单位像素。 |
WheelGracePeriodMs | int | 500 | 滚轮平滑滚动的“惯性”时间,单位毫秒。设为 0 可关闭惯性。 |
BeginScroller 和 EndScroller 必须成对出现,而且两个函数要传入同一个 ScrollerProfile 实例。如果你传了不同的对象,或者忘记调用 EndScroller,轻则滚动异常,重则程序崩溃。这是 IMGUI 容器的通用铁律。
返回值
两个函数都返回 void。滚动状态存储在传入的 Profile 中。
完整示例
下面这个例子创建了一个 300x200 的滚动区域,里面塞了 20 个按钮,远远超出可视范围,自然就会出现滚动条。
#include <include/hex.h>
#include <include/impl/EasyX/hex_impl_easyx.h>
// 全局资料结构体,生命周期必须跨帧
static HX::ScrollerProfile g_scroller;
int main() {
static HX::WindowProfile wp;
// 设置滚动容器的外观尺寸
g_scroller.Size = {300, 200};
g_scroller.ScrollbarThickness = 12;
while (true) {
HX::HXBegin();
ExMessage msg;
while (peekmessage(&msg)) {
HX::PushMessage(HX::GetHXMessage(&msg));
}
HX::Window(HXStr("Scroller 示例"), wp);
HX::Text(HXStr("滚动下面的区域:"));
HX::BeginScroller(g_scroller);
{
// 在这个大括号里,所有控件都会被装进滚动容器
for (int i = 0; i < 20; ++i) {
HX::ButtonProfile btn;
HXString label = HXStr("按钮 #") + std::to_wstring(i);
HX::Button(label, btn);
}
}
HX::EndScroller(g_scroller);
HX::Text(HXStr("滚动条上面的文字不会动"));
HX::End();
HX::Render();
}
return 0;
}
在 Begin 和 End 之间加大括号 {} 可以让代码层次更清晰,也能避免变量命名冲突。在 C++ 里这是一个非常友好的习惯。
滚轮平滑滚动
默认情况下,滚动条支持滚轮惯性:你快速拨一下滚轮,内容不会立刻停住,而是会“滑”一小段距离。这个行为由 WheelGracePeriodMs 控制:
g_scroller.WheelGracePeriodMs = 500; // 默认,有惯性
g_scroller.WheelGracePeriodMs = 0; // 立刻停止,无惯性
如果你在做像素级精确对齐的工具(比如关卡编辑器),可以把惯性关掉;如果是阅读长文本,保留惯性会更舒服。
水平滚动
当子控件的宽度总和超过 Size.x 时,水平滚动条会自动出现。你也可以在 BeginScroller 内部显式放置一个很宽的 Canvas 或 Panel 来触发它。
常见疑问
Q:滚动条会自动隐藏吗?
目前 HiEasyX 的滚动条在不需要时会自动禁用(变灰),但不会完全消失。如果你追求极简风格,可以把 ScrollbarThickness 设小一点,或者在外层手动判断内容是否溢出。
Q:Scroller 里面可以放 Scroller 吗? 理论上可以嵌套,但不建议太深。嵌套滚动条容易让用户 confused(到底滚的是哪一层?)。通常一层就足够了。
Q:我怎么知道用户滚到了哪里?
读取 g_scroller.VerticalVPer 即可。它是一个 0.0f 到 1.0f 的浮点数,0 表示在顶部,1 表示在底部。你可以用它来做“阅读进度”或者“懒加载触发”。
运行效果
截图占位符:请补充 $name 控件的运行效果截图。
截图占位符:请补充
Scroller 运行效果的运行效果截图,保存为./assets/Scroller_view.png。`n