2020征文-手機圖解鴻蒙列表組件ListContainer
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz
一、什么是ListContainer
ListContainer是用來呈現(xiàn)連續(xù)、多行數(shù)據(jù)的列表組件,包含一系列相同類型的列表項。如下圖所示:

二、ListContainer的架構(gòu)視圖
ListContainer的架構(gòu)視圖如下所示:
ListContainer作為列表,其中的列表項數(shù)據(jù)是由適配器Adapter提供的,適配器Adapter作為ListContainer和數(shù)據(jù)源之間的中介&橋梁,將數(shù)據(jù)源中的數(shù)據(jù)映射到要展示的ListContainer中,ListContainer負責(zé)以列表的形式顯示適配器Adapter提供的數(shù)據(jù)。
三、ListContainer的使用步驟
ListContainer的使用步驟主要包括:
1、創(chuàng)建ListContainer
2、創(chuàng)建列表項的布局
3、使用POJO類封裝數(shù)據(jù)源中與每個列表項對應(yīng)的數(shù)據(jù)
4、構(gòu)造數(shù)據(jù)源
5、構(gòu)造適配器Adapter
6、將數(shù)據(jù)源關(guān)聯(lián)到適配器Adapter
7、將適配器Adapter應(yīng)用到ListContainer
四、ListContainer的使用示例
示例的運行效果如下圖所示:
開發(fā)步驟如下:
1、創(chuàng)建ListContainer(ability_main.xml)
- xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:id="$+id:list_container"
- ohos:height="match_parent"
- ohos:width="match_parent"/>
2、創(chuàng)建列表項的布局(item.xml)
- xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:height="match_content"
- ohos:width="match_parent"
- ohos:orientation="vertical">
- ohos:id="$+id:name"
- ohos:height="50vp"
- ohos:width="match_parent"
- ohos:padding="5vp"
- ohos:auto_font_size="true"
- ohos:text_alignment="center"/>
- ohos:height="1vp"
- ohos:width="match_parent"
- ohos:background_element="#CCCCCC"/>
3、使用POJO類封裝數(shù)據(jù)源中與每個列表項對應(yīng)的數(shù)據(jù)(Item.java)
POJO類指的是:只包含屬性和相應(yīng)的getter和setter,而沒有業(yè)務(wù)邏輯的類。
- public class Item {
- private String name;
- public Item(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
4、構(gòu)造數(shù)據(jù)源(MainAbilitySlice.java)
- public class MainAbilitySlice extends AbilitySlice {
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_main);
- List list = getData();
- }
- private List getData() {
- List list = new ArrayList<>();
- for (int i = 1; i <= 100; i++) {
- list.add(new Item("Item " + i));
- }
- return list;
- }
- }
5、構(gòu)造適配器Adapter(MyItemProvider.java)
常用的適配器類是RecycleItemProvider,繼承該類時需要重寫四個方法:getCount()、getItem()、getItemId()和getComponent()。其中,對于方法getComponent(),當(dāng)某個列表項從不可見變?yōu)榭梢姇r會自動調(diào)用該方法,在該方法中適配器Adapter會從數(shù)據(jù)源取數(shù)據(jù),并將返回的數(shù)據(jù)封裝在一個Component對象中,以便將該對象返回給ListContainer,從而將數(shù)據(jù)映射到對應(yīng)的列表項。
- public class MyItemProvider extends RecycleItemProvider {
- private List list;
- private AbilitySlice slice;
- public MyItemProvider(List list, AbilitySlice slice) {
- this.list = list;
- this.slice = slice;
- }
- @Override
- public int getCount() {
- return list.size();
- }
- @Override
- public Object getItem(int position) {
- return list.get(position);
- }
- @Override
- public long getItemId(int position) {
- return position;
- }
- @Override
- public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) {
- convertComponent = LayoutScatter.getInstance(slice)
- .parse(ResourceTable.Layout_item, null, false);
- Text text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
- text.setText(list.get(position).getName());
- return convertComponent;
- }
- }
6、將數(shù)據(jù)源關(guān)聯(lián)到適配器Adapter(MainAbilitySlice.java)
- public class MainAbilitySlice extends AbilitySlice {
- @Override
- public void onStart(Intent intent) {
- ......
- List list = getData();
- MyItemProvider myItemProvider = new MyItemProvider(list, this);
- }
- ......
- }
7、將適配器Adapter應(yīng)用到ListContainer(MainAbilitySlice.java)
- public class MainAbilitySlice extends AbilitySlice {
- @Override
- public void onStart(Intent intent) {
- ......
- MyItemProvider myItemProvider = new MyItemProvider(list, this);
- ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_list_container);
- listContainer.setItemProvider(myItemProvider);
- }
- ......
- }
五、適配器Adapter的優(yōu)化
對于上面的第5步,當(dāng)某個列表項從不可見變?yōu)榭梢姇r,對于自動調(diào)用的方法getComponent(),我們是根據(jù)列表項的布局文件item.xml創(chuàng)建了一個列表項的實例。這樣的做法性能較差。因為系統(tǒng)會對變?yōu)椴豢梢姷牧斜眄棇嵗M行緩存,所以對于方法getComponent()中的第二個參數(shù)convertComponent有可能不為null。當(dāng)convertComponent不為null時,說明系統(tǒng)把緩存中的某個列表項實例傳遞過來了,因此,完全可以復(fù)用該列表項實例,而沒有必要重新創(chuàng)建一個列表項實例。優(yōu)化方式如下:
- public class MyItemProvider extends RecycleItemProvider {
- ......
- @Override
- public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) {
- if (convertComponent == null) {
- convertComponent = LayoutScatter.getInstance(slice)
- .parse(ResourceTable.Layout_item, null, false);
- }
- Text text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
- text.setText(list.get(position).getName());
- return convertComponent;
- }
- }
六、使用ViewHolder對適配器Adapter做終極優(yōu)化
在上面的代碼中,得到列表項實例后(不管是新創(chuàng)建的列表項實例,還是從緩存中獲得的列表項實例),都要調(diào)用方法findComponentById()以獲得列表項中的子組件。調(diào)用方法findComponentById()是比較耗費性能的,所以好的做法是:在新創(chuàng)建列表項實例時,就調(diào)用方法findComponentById()以獲得列表項中的所有子組件,并且將所有子組件通過ViewHolder綁定到列表項實例。這樣,當(dāng)從緩存中獲得列表項實例后,就無需再調(diào)用方法findComponentById()了,直接獲得列表項實例綁定的ViewHolder就可以得到所有子組件了。優(yōu)化方式如下:
- public class MyItemProvider extends RecycleItemProvider {
- ......
- @Override
- public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) {
- ViewHolder viewHolder;
- if (convertComponent == null) {
- convertComponent = LayoutScatter.getInstance(slice)
- .parse(ResourceTable.Layout_item, null, false);
- viewHolder = new ViewHolder();
- viewHolder.text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
- convertComponent.setTag(viewHolder);
- } else {
- viewHolder = (ViewHolder) convertComponent.getTag();
- }
- viewHolder.text.setText(list.get(position).getName());
- return convertComponent;
- }
- class ViewHolder {
- Text text;
- }
- }
如果你理解了為什么要這么優(yōu)化,相信你會發(fā)現(xiàn):當(dāng)列表項中只有一個子組件時,也可以不引入ViewHolder,而是將這個子組件直接綁定到列表項實例。代碼如下所示:
- public class MyItemProvider extends RecycleItemProvider {
- ......
- @Override
- public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) {
- Text text;
- if (convertComponent == null) {
- convertComponent = LayoutScatter.getInstance(slice)
- .parse(ResourceTable.Layout_item, null, false);
- text = (Text) convertComponent.findComponentById(ResourceTable.Id_name);
- convertComponent.setTag(text);
- } else {
- text = (Text) convertComponent.getTag();
- }
- text.setText(list.get(position).getName());
- return convertComponent;
- }
- }
示例源代碼,請見附件。
歡迎訂閱我的專欄【圖解鴻蒙】:
https://harmonyos.51cto.com/column/27
©著作權(quán)歸作者和HarmonyOS技術(shù)社區(qū)共同所有,如需轉(zhuǎn)載,請注明出處,否則將追究法律責(zé)任
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz