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

二、ListContainer的架構(gòu)視圖
ListContainer的架構(gòu)視圖如下所示:
ListContainer作為列表,其中的列表項(xiàng)數(shù)據(jù)是由適配器Adapter提供的,適配器Adapter作為L(zhǎng)istContainer和數(shù)據(jù)源之間的中介&橋梁,將數(shù)據(jù)源中的數(shù)據(jù)映射到要展示的ListContainer中,ListContainer負(fù)責(zé)以列表的形式顯示適配器Adapter提供的數(shù)據(jù)。
三、ListContainer的使用步驟
ListContainer的使用步驟主要包括:
1、創(chuàng)建ListContainer
2、創(chuàng)建列表項(xiàng)的布局
3、使用POJO類封裝數(shù)據(jù)源中與每個(gè)列表項(xiàng)對(duì)應(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的使用示例
示例的運(yùn)行效果如下圖所示:
開發(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)建列表項(xià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ù)源中與每個(gè)列表項(xiàng)對(duì)應(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,繼承該類時(shí)需要重寫四個(gè)方法:getCount()、getItem()、getItemId()和getComponent()。其中,對(duì)于方法getComponent(),當(dāng)某個(gè)列表項(xiàng)從不可見變?yōu)榭梢姇r(shí)會(huì)自動(dòng)調(diào)用該方法,在該方法中適配器Adapter會(huì)從數(shù)據(jù)源取數(shù)據(jù),并將返回的數(shù)據(jù)封裝在一個(gè)Component對(duì)象中,以便將該對(duì)象返回給ListContainer,從而將數(shù)據(jù)映射到對(duì)應(yīng)的列表項(xià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)化
對(duì)于上面的第5步,當(dāng)某個(gè)列表項(xiàng)從不可見變?yōu)榭梢姇r(shí),對(duì)于自動(dòng)調(diào)用的方法getComponent(),我們是根據(jù)列表項(xiàng)的布局文件item.xml創(chuàng)建了一個(gè)列表項(xiàng)的實(shí)例。這樣的做法性能較差。因?yàn)橄到y(tǒng)會(huì)對(duì)變?yōu)椴豢梢姷牧斜眄?xiàng)實(shí)例進(jìn)行緩存,所以對(duì)于方法getComponent()中的第二個(gè)參數(shù)convertComponent有可能不為null。當(dāng)convertComponent不為null時(shí),說明系統(tǒng)把緩存中的某個(gè)列表項(xiàng)實(shí)例傳遞過來(lái)了,因此,完全可以復(fù)用該列表項(xiàng)實(shí)例,而沒有必要重新創(chuàng)建一個(gè)列表項(xiàng)實(shí)例。優(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對(duì)適配器Adapter做終極優(yōu)化
在上面的代碼中,得到列表項(xiàng)實(shí)例后(不管是新創(chuàng)建的列表項(xiàng)實(shí)例,還是從緩存中獲得的列表項(xiàng)實(shí)例),都要調(diào)用方法findComponentById()以獲得列表項(xiàng)中的子組件。調(diào)用方法findComponentById()是比較耗費(fèi)性能的,所以好的做法是:在新創(chuàng)建列表項(xiàng)實(shí)例時(shí),就調(diào)用方法findComponentById()以獲得列表項(xiàng)中的所有子組件,并且將所有子組件通過ViewHolder綁定到列表項(xiàng)實(shí)例。這樣,當(dāng)從緩存中獲得列表項(xiàng)實(shí)例后,就無(wú)需再調(diào)用方法findComponentById()了,直接獲得列表項(xiàng)實(shí)例綁定的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)化,相信你會(huì)發(fā)現(xiàn):當(dāng)列表項(xiàng)中只有一個(gè)子組件時(shí),也可以不引入ViewHolder,而是將這個(gè)子組件直接綁定到列表項(xiàng)實(shí)例。代碼如下所示:
- 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;
- }
- }
示例源代碼,請(qǐng)見附件。
歡迎訂閱我的專欄【圖解鴻蒙】:
https://harmonyos.51cto.com/column/27
©著作權(quán)歸作者和HarmonyOS技術(shù)社區(qū)共同所有,如需轉(zhuǎn)載,請(qǐng)注明出處,否則將追究法律責(zé)任
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
https://harmonyos.51cto.com/#zz