棋牌大廳游戲菜單展示,需類似悠揚/JJ 棋牌的左右/上下滑動切換效果。
基於 DuiLib 擴展 CTabLayoutUI,實現三種滑動動畫方案。
class CSliderTabLayoutUI : public CTabLayoutUI {
// 方案1:雙頁面同步位移
int m_iCurFrame; bool m_bIsVertical; int m_nPositiveDirection;
RECT m_rcCurPos, m_rcNextPos;
CControlUI* m_pCurPage; CControlUI* m_pNextPage;
enum { TIMER_ANIMATION_ID=1, ANIMATION_ELLAPSE=2, ANIMATION_FRAME_COUNT=30 };
};
原理:當前頁和下一頁同時向反方向移動,形成「推擠」效果。
關鍵代碼:
void OnSliderStep() {
int stepLen = width * m_nPositiveDirection / FRAME_COUNT;
if (m_iCurFrame != FRAME_COUNT) {
OffsetRect(&m_rcCurPos, stepLen, 0);
OffsetRect(&m_rcNextPos, stepLen, 0);
m_pCurPage->SetPos(m_rcCurPos);
m_pNextPage->SetPos(m_rcNextPos);
} else {
m_pCurPage->SetVisible(false);
m_pNextPage->SetPos(m_rcItem); // 歸位
}
m_iCurFrame++;
}
原理:創建臨時 CHorizontalLayoutUI 容器,裝載兩頁,移動容器。
缺點:動態創建/銷毀容器,邏輯複雜,需處理浮動、定位、寬高同步。
核心思想:利用 DuiLib 佈局系統,在 SetPos 中按幀更新子控件位置。
關鍵實現:
void SetPos(RECT rc) {
CControlUI::SetPos(rc);
if (m_bAnimating) {
int stepLen = width * m_nPositiveDirection / FRAME_COUNT;
if (m_iCurFrame != FRAME_COUNT) {
OffsetRect(&m_rcCurPos, stepLen, 0);
OffsetRect(&m_rcNextPos, stepLen, 0);
m_pCurPage->SetPos(m_rcCurPos);
m_pNextPage->SetPos(m_rcNextPos);
} else {
m_pCurPage->SetVisible(false);
m_pNextPage->SetPos(rc);
m_bAnimating = false;
m_pManager->KillTimer(this, TIMER_ANIMATION_ID);
}
m_iCurFrame++;
} else {
// 正常佈局邏輯
for (子控件) { ... 佈局可見頁面 ... }
}
}
優勢:無需額外定時器回調,佈局系統自動驅動幀更新,代碼最簡潔。
... ... ...
| 方案 | 實現複雜度 | 性能 | 穩定性 | 推薦度 |
|---|---|---|---|---|
| 1. 雙頁同步 | 中等 | 好 | 高 | ★★★☆☆ |
| 2. 容器包裹 | 高 | 一般 | 中 | ★★☆☆☆ |
| 3. SetPos 驅動 | 低 | 最好 | 最高 | ★★★★★ |
SetFloat(true):使頁面脫離標準流,支持絕對定位動畫OffsetRect:Windows API 高效偏移矩形ANIMATION_ELLAPSE=10ms,幀數 15-30,流暢度佳m_bIsVertical 切換 X/Y 軸計算方案 3 完美融入 DuiLib 佈局生命週期,是擴展自定義動畫控件的最佳實踐模式。