#pragma once typedef std::function DataChangedNotify; typedef std::function CountChangedNotify; class UILIB_API VirtualTileInterface: public nbase::SupportWeakCallback { public: VirtualTileInterface(); /** * @brief 创建一个子项 * @return 返回创建后的子项指针 */ virtual ui::Control* CreateElement() = 0; /** * @brief 填充指定子项 * @param[in] control 子项控件指针 * @param[in] index 索引 * @return 返回创建后的子项指针 */ virtual void FillElement(ui::Control *control, int index) = 0; /** * @brief 获取子项总数 * @return 返回子项总数 */ virtual int GetElementtCount() = 0; void RegNotifys(const DataChangedNotify& dcNotify, const CountChangedNotify& ccNotify); protected: void EmitDataChanged(int nStartIndex, int nEndIndex); void EmitCountChanged(); private: DataChangedNotify m_DataChangedNotify; CountChangedNotify m_CountChangedNotify; }; class UILIB_API VirtualTileLayout : public ui::TileLayout { public: VirtualTileLayout(); virtual ui::CSize ArrangeChild(const std::vector& items, ui::UiRect rc) override; virtual ui::CSize AjustSizeByChild(const std::vector& items, ui::CSize szAvailable) override; virtual bool SetAttribute(const std::wstring& strName, const std::wstring& strValue) override; virtual int GetElementsHeight(int nCount); virtual void LazyArrangeChild(); virtual int AjustMaxItem(); private: bool m_bAutoCalcColumn; }; class UILIB_API VirtualTileBox : public ui::ListBox { friend class VirtualTileLayout; public: VirtualTileBox(ui::Layout* pLayout = new VirtualTileLayout); /** * @brief 设置数据代理对象 * @param[in] pProvider 开发者需要重写 VirtualListInterface 的接口来作为数据代理对象 * @return 无 */ virtual void SetDataProvider(VirtualTileInterface *pProvider); virtual VirtualTileInterface* GetDataProvider(); /** * @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(ui::UiRect rc) override; /** * @brief 重新布局子项 * @param[in] bForce 是否强制重新布局 * @return 无 */ void ReArrangeChild(bool bForce); /** * @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 得到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); VirtualTileLayout* GetTileLayout(); int GetRealElementHeight(); int GetColumns(); void LazyArrangeChild(); void OnModelDataChanged(int nStartIndex, int nEndIndex); void OnModelCountChanged(); int ElementIndexToItemIndex(int nElementIndex); int ItemIndexToElementIndex(int nItemIndex); private: VirtualTileInterface *m_pDataProvider; int m_nMaxItemCount; // 列表真实控件数量上限 int m_nOldYScrollPos; bool m_bArrangedOnce; bool m_bForceArrange; // 强制布局标记 };