Chapter 152 · XUI 容器与导航

Accordion 手风琴

Accordion 可折叠分组面板,支持单展开/多展开模式、节头按钮、内容区独立布局。

152

概念

Accordion 垂直堆叠多个可折叠 Section:
• Header:节头(标题 + 展开箭头)
• Client:节内容区(展开时可见)
• Mode:0 = 多展开(独立切换),1 = 单展开(互斥)
• 适合设置面板、分类导航、FAQ 列表

API 速查

函数说明
int xuiAccordionCreate(xui_context pCtx, xui_widget* ppW, const xui_accordion_desc_t* pDesc)创建手风琴
int xuiAccordionAddSection(xui_widget pW, const char* sTitle, int iId, int bExpanded, xui_widget* ppClient)添加节
int xuiAccordionSetExpanded(xui_widget pW, int iIndex, int bExpanded)展开/折叠
int xuiAccordionIsExpanded(xui_widget pW, int iIndex)查询展开状态
int xuiAccordionSetMode(xui_widget pW, int iMode)单/多展开
int xuiAccordionAddSectionChild(xui_widget pW, int iIndex, xui_widget pChild)向节添加子控件
int xuiAccordionSetSectionTitle(xui_widget pW, int iIndex, const char* sTitle)修改标题
int xuiAccordionSetSectionEnabled(xui_widget pW, int iIndex, int bEnabled)启用/禁用节
int xuiAccordionSetMetrics(xui_widget pW, float fHeaderH, float fSpacing, float fPad)度量
int xuiAccordionSetSelect(xui_widget pW, onSelect, void* pUser)展开回调

编译本章示例

gcc -O2 -I. -o ch152.exe ch152_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch152.exe

示例:设置面板

xui_accordion_desc_t desc = { 0 };

xui_widget pAcc;
xuiAccordionCreate(pCtx, &pAcc, &desc);
xuiWidgetSetRect(pAcc, (xui_rect_t){0, 0, 300.0f, 500.0f});
xuiAccordionSetMode(pAcc, 0); // 多展开

// 添加三个节
xui_widget pClient1, pClient2, pClient3;
xuiAccordionAddSection(pAcc, "常规", 1, 1, &pClient1);
xuiAccordionAddSection(pAcc, "显示", 2, 0, &pClient2);
xuiAccordionAddSection(pAcc, "高级", 3, 0, &pClient3);

// 向"常规"节添加控件
xuiAccordionAddSectionChild(pAcc, 0, pCheckDarkMode);
xuiAccordionAddSectionChild(pAcc, 0, pSliderVolume);

xuiAccordionSetMetrics(pAcc, 36.0f, 2.0f, 12.0f);
xuiWidgetAddChild(pParent, pAcc);

完整代码

将以下代码保存为 ch152_main.c,编译后运行即可看到手风琴效果:

#include "xge.h"
#include "xui.h"

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);
    float mx, my;
    xgeMouseGet(&mx, &my);
    xuiInputPointerMove(g_pCtx, mx, my);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, 0);
    else
        xuiInputPointerUp(g_pCtx, 0);
    xuiUpdate(g_pCtx, xgeGetDelta());
    xuiLayout(g_pCtx);
    xuiRender(g_pCtx, NULL, NULL, 0);
    return XGE_OK;
}

int main(void) {
    xge_desc_t d = { 0 };
    d.iWidth = 800; d.iHeight = 600;
    d.sTitle = "ch152 - Accordion";
    d.iFlags = XGE_INIT_VSYNC;
    xgeInit(&d);

    xuiCreate(&g_pCtx);
    extern const xui_proxy_t tXgeProxy;
    xui_proxy_t tXgeProxy = xuiProxyXge();
xuiSetProxy(g_pCtx, &tXgeProxy);
    xuiSetViewportSize(g_pCtx, 800, 600);

    xui_widget pRoot;
    xuiWidgetCreate(g_pCtx, &pRoot);
xuiWidgetSetLayoutType(pRoot, XUI_LAYOUT_COLUMN);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 800, 600});
    xuiWidgetSetPadding(pRoot, 40, 40, 40, 40);
    xuiSetRootWidget(g_pCtx, pRoot);

    /* 创建手风琴 */
    xui_accordion_desc_t ad = { 0 };
    xui_widget pAcc;
    xuiAccordionCreate(g_pCtx, &pAcc, &ad);
    xuiWidgetSetRect(pAcc, (xui_rect_t){0, 0, 350, 500});
    xuiAccordionSetMode(pAcc, 0); // 多展开
    xuiWidgetAddChild(pRoot, pAcc);

    /* 添加三个节 */
    xui_widget pC1, pC2, pC3;
    xuiAccordionAddSection(pAcc, "常规", 1, 1, &pC1);
    xuiAccordionAddSection(pAcc, "显示", 2, 0, &pC2);
    xuiAccordionAddSection(pAcc, "高级", 3, 0, &pC3);

    /* 向“常规”节添加内容 */
    xui_label_desc_t lb = { 0 };
    lb.sText = "语言: 中文";
    xui_widget pLb;
    xuiLabelCreate(g_pCtx, &pLb, &lb);
    xuiAccordionAddSectionChild(pAcc, 0, pLb);

    xuiAccordionSetMetrics(pAcc, 36.0f, 2.0f, 12.0f);

    xgeRun(onFrame, NULL);
    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • Mode=0:多展开模式,各节独立切换;Mode=1 则互斥展开。
  • AddSection:参数为标题、ID、初始展开状态,返回客户区指针。
  • AddSectionChild:向指定索引的节添加子控件。
  • Metrics:设置节标题高度、节间距、内容内边距。

要点与陷阱

  • Mode=1:单展开模式,展开新节自动折叠其他节。
  • AddSection 的 bExpanded:初始展开状态。
  • ContentPadding:节内容区的内边距。
  • SectionEnabled:禁用节不可展开,标题变灰。
  • GetContentHeight:所有节完全展开时的总高度(用于外层 ScrollView)。

进阶练习

  1. FAQ 列表:单展开模式 + 富文本内容。
  2. 带动画展开:结合定时器逐步改变节高度实现平滑过渡。
Accordion 手风琴效果
图:Accordion 手风琴渲染效果