Skip to content

列表视图控件 (SListView)

Warning

The current page still doesn't have a translation for this language.

You can read it through google translate.

SOUI 中的高性能列表视图控件,基于虚拟化(adapter)技术实现,支持大量数据的高效显示和滚动。适用于显示单列数据列表,每个项目可以使用自定义模板(<template>)。

基本信息

  • 类名SListView
  • 控件标签listview
  • 基类SPanel(通过 TPanelProxy<IListView> + SViewBase
  • 功能:提供高性能单列数据列表展示

属性说明

SListView 的自身属性在 SListView::SOUI_ATTRS_BEGIN 中声明,并通过 ATTR_CHAIN_CLASS(SViewBase) 继承 SViewBase 的选择相关属性。

自身属性

属性名 类型 默认值 是否重绘 说明
dividerSkin skin 列表项之间的分割线皮肤
dividerSize layoutsize 未设置(0) 分割线尺寸
vertical bool false 排列方向:true=垂直排列,false=水平排列
wantTab bool false 是否响应 Tab 键在项之间切换焦点
multiSel bool false 是否允许多选(由 SViewBase 提供)

说明:SOUI_ATTRS_BEGIN 的第三个参数 allredraw 表示“属性变更后是否重绘”,不是默认值。上表默认值来自构造函数成员初始化(m_bVertical(FALSE)SViewBasem_bWantTab(FALSE)m_bMultiSel(FALSE))。

列表项高度、悬停/选中背景等通过 <template> 内的子控件与 <style> 设置,不是 listview 的独立 XML 属性。

使用示例

MVC 虚表控件的核心是通过 数据适配器(Adapter) 把数据与界面解耦:listview 只负责按模板渲染“可见项”,数据由 ILvAdapter 提供。SOUI 提供了便捷基类 SAdapterBasehelper/SAdapterBase.h),继承它并实现 getCount()getView() 即可。完整可运行示例见 demos/wxDemo/CLvMessageAdapter.h

1. XML 模板

<listview pos="10,10,-10,-10" name="lv_msg"
          vertical="1" dividerSize="1">
    <template itemHeight="64" colorHover="#f1f1f1" colorSelected="#cccccc">
        <window>
            <img name="item_avatar" pos="10,|-16" skin="skin_default_personal32"/>
            <text name="item_name"     pos="[60,15" font="bold:1"/>
            <text name="item_content"  pos="[60,40" colorText="#666666"/>
            <text name="item_time"     pos="-10,15" align="right"/>
        </window>
    </template>
</listview>

模板内的子控件通过 name 属性命名,适配器在 getView() 中用 FindChildByName2<T>() 找到它们并填入数据。itemHeight 既可在 XML 模板上声明,也可由适配器的 getViewDesiredSize() 动态计算(控件默认按模板 itemHeight/defHeight 定位)。

2. 实现适配器(C++)

#include <helper/SAdapterBase.h>
#include <control/SListView.h>

struct MsgItem
{
    SStringW strName;
    SStringW strContent;
    SStringW strTime;
    SStringW strAvatar;
};

class CMsgListAdapter : public SAdapterBase
{
public:
    void AddMsg(const MsgItem &item)
    {
        m_items.Add(item);
        notifyDataSetChanged();
    }

protected:
    virtual int WINAPI getCount() override
    {
        return m_items.GetCount();
    }

    virtual void WINAPI getView(int position, SItemPanel *pItem, SXmlNode xmlTemplate) override
    {
        if (pItem->GetChildrenCount() == 0)
            pItem->InitFromXml(&xmlTemplate);

        const MsgItem &data = m_items[position];

        pItem->FindChildByName2<SImageWnd>(L"item_avatar")
             ->SetAttribute(L"skin", data.strAvatar);
        pItem->FindChildByName2<SStatic>(L"item_name")->SetWindowText(S_CW2T(data.strName));
        pItem->FindChildByName2<SStatic>(L"item_content")->SetWindowText(S_CW2T(data.strContent));
        pItem->FindChildByName2<SStatic>(L"item_time")->SetWindowText(S_CW2T(data.strTime));
    }

private:
    SArray<MsgItem> m_items;
};

3. 绑定与使用

void InitList(SListView *pList)
{
    CMsgListAdapter *pAdapter = new CMsgListAdapter;
    pAdapter->AddMsg({L"张三", L"在吗?", L"10:24", L"skin_default_personal32"});
    pAdapter->AddMsg({L"李四", L"文件已发", L"10:30", L"skin_default_personal32"});

    pList->SetAdapter(pAdapter);
    pAdapter->Release();

    pList->SetSel(0, TRUE);
    pList->SetMultiSel(TRUE);
}

SetAdapter 内部会对适配器 AddRef,因此传入后本地应 Release() 一次,避免内存泄漏。SAdapterBase 已通过 TObjRefImpl 实现引用计数,无需手动 delete

相关主题