listview分组实现、性能优化及错位解决

xiaoxiao2021-02-28  58

listview是Android开发中最常见的组件之一。在项目开发中,经常需要将listview分组。关于listview分组的原理可以参考android之listview分组实现,简单说就是:将分组的内容和分组的标题按顺序统一放在一个list中,根据list中的内容决定展示分组标题还是分组内容。本文主要讨论分组listview优化的问题,第一部分“listview分组实现”只做一个简单介绍,代码详见:demo下载

一、listview分组实现

activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/lv_list" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout> 2. MainActivity.java public class MainActivity extends AppCompatActivity { private Context mContext; private Button btn_compare; private ListView lv_list; private List<DataModel> list=null; private List<DataModel> groupkey=new ArrayList<DataModel>(); private List<DataModel> aList = new ArrayList<DataModel>(); private List<DataModel> bList = new ArrayList<DataModel>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; btn_compare = (Button) findViewById(R.id.btn_compare); btn_compare.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(mContext, CompareActivity.class); startActivity(intent); } }); lv_list = (ListView) findViewById(R.id.lv_list); initData(); } private void initData(){ list = new ArrayList<DataModel>(); DataModel model = new DataModel(); model.setTitle("------1------"); groupkey.add(model); model = new DataModel(); model.setTitle("------2------"); groupkey.add(model); for(int i=0; i<8; i++){ model = new DataModel(); model.setContent("上海"); model.setStartTime("20170505"+i); model.setStartTime("20170505"+(i+10)); aList.add(model); } list.add(groupkey.get(0)); list.addAll(aList); for(int i=0; i<25; i++){ model = new DataModel(); model.setStartTime("20170905"+i); model.setStartTime("20170905"+(i+10)); model.setContent("科技"); bList.add(model); } list.add(groupkey.get(1)); list.addAll(bList); lv_list.setAdapter(new GroupListAdapter(mContext, groupkey, list)); } } 3. GroupListAdapter.java public class GroupListAdapter extends BaseAdapter { private Context mContext; private List<DataModel> list_group = new ArrayList<DataModel>(); private List<DataModel> list_event = new ArrayList<DataModel>(); public GroupListAdapter(Context context, List<DataModel> list_group, List<DataModel> list_event){ mContext = context; this.list_group = list_group; this.list_event = list_event; } @Override public int getCount() { return list_event.size(); } @Override public DataModel getItem(int position) { return list_event.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view=convertView; if(list_group.contains(getItem(position))){ view= LayoutInflater.from(getApplicationContext()).inflate(R.layout.list_group_items, null); TextView tv_content = (TextView) view.findViewById(R.id.tv_content); tv_content.setText(getItem(position).getContent()); }else{ view=LayoutInflater.from(getApplicationContext()).inflate(R.layout.list_items, null); TextView tv_start_time = (TextView) view.findViewById(R.id.tv_start_time); TextView tv_end_time = (TextView) view.findViewById(R.id.tv_end_time); TextView tv_content = (TextView) view.findViewById(R.id.tv_content); tv_start_time.setText(getItem(position).getStartTime()); tv_end_time.setText(getItem(position).getEndTime()); tv_content.setText(getItem(position).getContent()); } return convertView; } @Override public boolean isEnabled(int position) { if (list_group.contains(list_event.get(position))){ return false; } return super.isEnabled(position); } } 4. DataModel.java public class DataModel { private String title; private String startTime; private String endTime; private String content; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getStartTime() { return startTime; } public void setStartTime(String startTime) { this.startTime = startTime; } public String getEndTime() { return endTime; } public void setEndTime(String endTime) { this.endTime = endTime; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } } 5. list_group_items.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="30dp" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="5dp" android:paddingBottom="5dp" android:layout_gravity="center_vertical" android:background="#efeff4"> <TextView android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#f00" android:textSize="16sp" android:text="------1------" /> </RelativeLayout> 5. list_items.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/ll_list_items" android:layout_width="match_parent" android:layout_height="50dp" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingLeft="10dp" android:paddingRight="10dp" android:background="#fff"> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:paddingLeft="10dp" android:paddingRight="10dp" android:orientation="vertical"> <TextView android:id="@+id/tv_start_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="12sp" android:layout_gravity="right" android:text="8:00"/> <TextView android:id="@+id/tv_end_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:textSize="12sp" android:text="9:00"/> </LinearLayout> <View android:layout_width="2dp" android:layout_height="match_parent" android:padding="5dp" android:background="#f73066d4"/> <TextView android:id="@+id/tv_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_gravity="center" android:singleLine="true" android:textSize="16sp" android:text="测试数据" /> </LinearLayout> </LinearLayout>

二、listview分组优化

上面的代码并没有对listview优化,listview最常用的优化方法就是使用ViewHolder。我们只需要对GroupListAdapter.java进行修改。

public class GroupListAdapter extends BaseAdapter { private Context mContext; private List<DataModel> list_group = new ArrayList<DataModel>(); private List<DataModel> list_event = new ArrayList<DataModel>(); public GroupListAdapter(Context context, List<DataModel> list_group, List<DataModel> list_event){ mContext = context; this.list_group = list_group; this.list_event = list_event; } @Override public int getCount() { return list_event.size(); } @Override public DataModel getItem(int position) { return list_event.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null){ viewHolder = new ViewHolder(); if (list_group.contains(getItem(position))){ convertView = View.inflate(mContext, R.layout.list_group_items, null); viewHolder.tv_content = (TextView) convertView.findViewById(R.id.tv_content); }else{ convertView = View.inflate(mContext, R.layout.list_items, null); viewHolder.tv_start_time = (TextView) convertView.findViewById(R.id.tv_start_time); viewHolder.tv_end_time = (TextView) convertView.findViewById(R.id.tv_end_time); viewHolder.tv_content = (TextView) convertView.findViewById(R.id.tv_content); } convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } if(viewHolder.tv_start_time != null) { viewHolder.tv_start_time.setText(getItem(position).getStartTime()); } if(viewHolder.tv_end_time != null) { viewHolder.tv_end_time.setText(getItem(position).getEndTime()); } viewHolder.tv_content.setText(getItem(position).getTitle()); return convertView; } @Override public boolean isEnabled(int position) { if (list_group.contains(list_event.get(position))){ return false; } return super.isEnabled(position); } class ViewHolder{ LinearLayout ll_list_items; RelativeLayout rl_group_items; TextView tv_start_time, tv_end_time, tv_content, tv_title; } }

虽然对listview性能优化了,但是当快速滑动listview时,会出现错位问题。

三、解决listview分组优化错位问题

为了解决listview分组优化错位问题,我们将分组标题和分组内容item放在同一个item中,判断getItem(position)是否包含在list_group中(即当前getItem(position)是否为分组标题),决定显示分组标题还是分组内容。 我们再次修改GroupListAdapter.java:

public class GroupListAdapter extends BaseAdapter { private Context mContext; private List<DataModel> list_group = new ArrayList<DataModel>(); private List<DataModel> list_event = new ArrayList<DataModel>(); public GroupListAdapter(Context context, List<DataModel> list_group, List<DataModel> list_event){ mContext = context; this.list_group = list_group; this.list_event = list_event; } @Override public int getCount() { return list_event.size(); } @Override public DataModel getItem(int position) { return list_event.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null){ viewHolder = new ViewHolder(); convertView = View.inflate(mContext, R.layout.list_items, null); viewHolder.ll_list_items = (LinearLayout) convertView.findViewById(R.id.ll_list_items); viewHolder.tv_start_time = (TextView) convertView.findViewById(R.id.tv_start_time); viewHolder.tv_end_time = (TextView) convertView.findViewById(R.id.tv_end_time); viewHolder.tv_content = (TextView) convertView.findViewById(R.id.tv_content); viewHolder.rl_group_items = (RelativeLayout) convertView.findViewById(R.id.rl_group_items); viewHolder.tv_title = (TextView) convertView.findViewById(R.id.tv_title); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } if (list_group.contains(getItem(position))){ viewHolder.ll_list_items.setVisibility(View.GONE); viewHolder.rl_group_items.setVisibility(View.VISIBLE); viewHolder.tv_title.setText(getItem(position).getTitle()); } else { viewHolder.ll_list_items.setVisibility(View.VISIBLE); viewHolder.rl_group_items.setVisibility(View.GONE); viewHolder.tv_start_time.setText(getItem(position).getStartTime()); viewHolder.tv_end_time.setText(getItem(position).getEndTime()); viewHolder.tv_content.setText(getItem(position).getContent()); } return convertView; } @Override public boolean isEnabled(int position) { if (list_group.contains(list_event.get(position))){ return false; } return super.isEnabled(position); } class ViewHolder{ LinearLayout ll_list_items; RelativeLayout rl_group_items; TextView tv_start_time, tv_end_time, tv_content, tv_title; } }

这样就能实现listview分组性能优化,并解决分组错位问题。但是无论item是分组标题还是分组内容,都需要同时渲染分组标题和分组内容,只是简单的进行了隐藏,性能并不是最好的。大家如果有更好的方法,可以贴出来讨论。

转载请注明原文地址: https://www.6miu.com/read-56352.html

最新回复(0)