SOUI原來實現的SListBoxEx的效率一直是我對SOUI不太滿意的地方。包括后來網友實現的SListCtrlEx。
這類控件為每一個列表項創建一個SWindow來容納數據,當數據量比較大(10000+)時,一方面內存消耗會很嚴重;另一方面列表數據初始化也需要大量的時間。
今年開始轉型做Android開發。大家都知道Android開發APP和PC上開發APP相比要簡單很多,其中我個人體會最深的就是Android的ListView控件。
在Android中,ListView中列表項的顯示采用控件+適配器(Adapter)的模式,也就是所謂的MVC模式。一個表項在需要顯示的時候才會把數據加載到View里去,當這個表項被隱藏起來以后,容納該表項的容器(View)則自動被加入到ListView中保存的一個容器回收列表中。需要顯示一個新表項時首先去回收站里查找是否存在指定類型的容器,存在則自動復用。
基本思想如上,當然實際實現還使用了很多技巧。通過上述機制,可以有效解決ListView顯示大量數據的問題。
本來也一直想重寫SOUI的ListBox, 這段時間正好項目需要,抽出時間模仿了一個,效果不錯。
先看看效果:
第一張圖是一個加載50000行的SListView控件,第二個圖是演示使用SComboView來做用戶登陸界面。
要在SOUI中使用SListView,我們首先需要自己實現一上數據填充的Adapter:
class CTestAdapter : public SAdapterBase { protected: SListView * m_pOwenr; public: CTestAdapter(SListView *pOwner):m_pOwenr(pOwner) { } virtual int getCount() { return 50000; } virtual void getView(int position, SWindow * pItem) { if(pItem->GetChildrenCount()==0) { pItem->InitFromXml(m_pOwenr->GetTemplate()); } SAnimateImgWnd *pAni = pItem->FindChildByName2<SAnimateImgWnd>(L"ani_test"); SButton *pBtn = pItem->FindChildByName2<SButton>(L"btn_test"); pBtn->SetWindowText(SStringW().Format(L"button %d",position)); pBtn->SetUserData(position); pBtn->GetEventSet()->subscribeEvent(EVT_CMD,Subscriber(&CTestAdapter::OnButtonClick,this)); } bool OnButtonClick(EventArgs *pEvt) { SButton *pBtn = sobj_cast<SButton>(pEvt->sender); int iItem = pBtn->GetUserData(); SMessageBox(NULL,SStringT().Format(_T("button of %d item was clicked"),iItem),_T("haha"),MB_OK); return true; } };
這里最關鍵的就是實現IAdapter中的getView方法。
和Android的ListView不同,SOUI中使用條件pItem->GetChildrenCount()==0來判斷一個容器是否是被復用。
當pItem->GetChildrenCount()==0時代表該容器還沒有被初始化,需要自己從XML模板中初始化容器。XML模板可以自己自己定義的任意符合SOUI布局語法的數據。
容器初始化完成后就可以向里面填充數據,也可以向控件連接響應函數了(subscribeEvent)。
在UI創建完成后需要在代碼中把這個Adapter交給SListView:
LRESULT CMainDlg::OnInitDialog( HWND hWnd, LPARAM lParam ) { //.... SListView *pLstView = FindChildByName2<SListView>("lv_test"); if(pLstView) { CTestAdapter *pAdapter = new CTestAdapter(pLstView); pLstView->SetAdapter(pAdapter); pAdapter->Release(); } return 0; }
第二個界面是演示SComboView的。SComboView的用戶和SListView基本一樣,具體看代碼。