// Copyright 2017, NetEase (Hangzhou) Network Co., Ltd. All rights reserved. // // zqw // 2015/7/22 // // virtual ListBox class #pragma once namespace ui { /** * @brief 虚拟列表接口类 * 提供开发者对子项数据管理个性化定制 */ class VirtualListInterface { public: /** * @brief 创建一个子项 * @return 返回创建后的子项指针 */ virtual Control* CreateElement() = 0; /** * @brief 填充指定子项 * @param[in] control 子项控件指针 * @param[in] index 索引 * @return 返回创建后的子项指针 */ virtual void FillElement(Control *control, int index) = 0; /** * @brief 获取子项总数 * @return 返回子项总数 */ virtual int GetElementtCount() = 0; }; /** * @brief 虚拟列表 */ class UILIB_API VirtualLayout : public VLayout { protected: virtual ui::CSize ArrangeChild(const std::vector& items, ui::UiRect rc); }; class UILIB_API VirtualListBox : public ListBox { friend class VirtualLayout; public: VirtualListBox(ui::Layout* pLayout = new VirtualLayout); /** * @brief 设置数据代理对象 * @param[in] pProvider 开发者需要重写 VirtualListInterface 的接口来作为数据代理对象 * @return 无 */ virtual void SetDataProvider(VirtualListInterface *pProvider); /** * @brief 设置子项高度 * @param[in] nHeight 高度值 * @return 无 */ virtual void SetElementHeight(int nHeight); /** * @brief 初始化子项 * @param[in] nMaxItemCount 初始化数量,默认 50 * @return 无 */ virtual void InitElement(int nMaxItemCount = 50); /** * @brief 刷新列表 * @return 无 */ virtual void Refresh(); /** * @brief 删除所有子项 * @return 无 */ virtual void RemoveAll() override; /** * @brief 设置是否强制重新布局 * @param[in] bForce 设置为 true 为强制,否则为不强制 * @return 无 */ void SetForceArrange(bool bForce); /** * @brief 获取当前所有可见控件的索引 * @param[out] collection 索引列表 * @return 无 */ void GetDisplayCollection(std::vector& collection); /** * @brief 让控件在可见范围内 * @param[in] iIndex 控件索引 * @param[in] bToTop 是否在最上方 * @return 无 */ void EnsureVisible(int iIndex, bool bToTop = false); protected: /// 重写父类接口,提供个性化功能 virtual void SetScrollPos(ui::CSize szPos) override; virtual void HandleMessage(ui::EventArgs& event) override; virtual void SetPos(UiRect rc) override; /** * @brief 重新布局子项 * @param[in] bForce 是否强制重新布局 * @return 无 */ void ReArrangeChild(bool bForce); /** * @brief 添加一个子项 * @param[in] iIndex 要插入的位置 * @return 无 */ void AddElement(int iIndex); /** * @brief 移除一个子项 * @param[in] iIndex 要移除的子项索引 * @return 无 */ void RemoveElement(int iIndex); /** * @brief 键盘按下通知 * @param[in] ch 按键 * @return 无 */ virtual void OnKeyDown(TCHAR ch) {} /** * @brief 键盘弹起通知 * @param[in] ch 按键 * @return 无 */ virtual void OnKeyUp(TCHAR ch) {} private: enum ScrollDirection { kScrollUp = -1, kScrollDown = 1 }; /** * @brief 创建一个子项 * @return 返回创建后的子项指针 */ Control* CreateElement(); /** * @brief 填充指定子项 * @param[in] control 子项控件指针 * @param[in] index 索引 * @return 返回创建后的子项指针 */ void FillElement(Control *pControl, int iIndex); /** * @brief 获取元素总数 * @return 返回元素总指数 */ int GetElementCount(); /** * @brief 使用默认布局 * @return 成功返回 true,否则返回 false */ bool UseDefaultLayout(); /** * @brief 得到n个元素对应的高度和, * @param[in] nCount 要得到多少元素的高度,-1表示全部元素 * @return 返回指定数量元素的高度和 */ int CalcElementsHeight(int nCount); /** * @brief 得到可见范围内第一个元素的前一个元素索引 * @param[out] bottom 返回上一个元素的 bottom 值 * @return 返回上一个元素的索引 */ int GetTopElementIndex(int &bottom); /** * @brief 判断某个元素是否在可见范围内 * @param[in] iIndex 元素索引 * @return 返回 true 表示可见,否则为不可见 */ bool IsElementDisplay(int iIndex); /** * @brief 判断是否要重新布局 * @param[out] direction 向上滚动还是向下滚动 * @return true 为需要重新布局,否则为 false */ bool NeedReArrange(ScrollDirection &direction); private: VirtualListInterface *m_pDataProvider; int m_nElementHeight; // 每个项的高度 int m_nMaxItemCount; // 列表真实控件数量上限 int m_nOldYScrollPos; bool m_bArrangedOnce; bool m_bForceArrange; // 强制布局标记 }; }