转载

Android中ListView封装收缩与展开

常有这种需求,即ListView中数据较多(不涉及分页),如果都展开,数据量较多,体验不好,所以需要提供用户查看更多、收缩数据的交互

截图如下:

Android中ListView封装收缩与展开 Android中ListView封装收缩与展开

如图所示,点击更多,则展开所有数据。点击收起,则自动收缩。

代码如下(主要通过继承Adapetr,控制展示的数据量getCount()方法实现,当数据量大于默认值(2)时,自动只展示2条数据,当点击更多时,则展示全部数据):

(在使用这种方法前曾想自定义ListView实现,但遇到较多问题,如:

1.由于我们通过adapter设置数据,不直接调用listview的方法,所以需要了解Adapter中notifyDataSetChanged方法的回调函数,通过分析源码了解到notifyDataSetChanged方法会回调ListView的requestLayout方法。所以通过在requestLayout中添加动态设置listview高度的方法,但设置高度会回调requestLayout,从而造成死循环,可通过设计标志位解决

2.动态设置listview高度并没有实现把多余的listitem隐藏,导致本该显示footview的高度显示了部分listitem。隐藏多余的listitem后,目前还是未显示出footview,通过网上了解到的一些解决办法,还是没有解决

3.此外还有其他问题,所以后来索性转为继承BaseAdapter实现)

  1 package com.example.android_train.adapter;   2    3 import java.util.ArrayList;   4    5 import android.annotation.SuppressLint;   6 import android.content.Context;   7 import android.view.LayoutInflater;   8 import android.view.View;   9 import android.view.View.OnClickListener;  10 import android.view.ViewGroup;  11 import android.widget.BaseAdapter;  12 import android.widget.Button;  13 import android.widget.LinearLayout;  14 import android.widget.ListAdapter;  15 import android.widget.ListView;  16   17 import com.example.android_train.R;  18   19 public abstract class BaseFootviewAdapter<E> extends BaseAdapter {  20       21     public static final int DEFAULT_SHOW_COUNT = 2;  22       23     protected Context mContext;  24     protected ListView mListView;  25     protected LayoutInflater inflater;  26     protected LinearLayout headView;  27     protected Button btn_loadmore;  28     protected ArrayList<E> mShowObjects = new ArrayList<E>();  29     protected ArrayList<E> mAllObjects = null;  30     protected boolean shrink = true;  31   32     @SuppressWarnings("unused")  33     private BaseFootviewAdapter() {  34     }  35   36     @SuppressLint("InflateParams")  37     public BaseFootviewAdapter( Context mContext, ListView mListView) {  38         this.mContext = mContext;  39         this.mListView = mListView;  40         inflater = LayoutInflater.from(mContext);  41         headView = (LinearLayout) inflater.inflate(R.layout.lv_footer_button, null);  42         btn_loadmore = (Button) headView.findViewById(R.id.btn_loadmore);  43         btn_loadmore.setOnClickListener(new OnClickListener() {  44             @Override  45             public void onClick(View v) {  46                 changeShow();  47             }  48         });  49         mListView.addFooterView(headView, null, false);  50     }  51       52     public void setAdapterData( ArrayList<E> mAllObjects ) {  53         this.mAllObjects = mAllObjects;  54         mShowObjects.clear();  55         if( mAllObjects != null ) {  56             if( mAllObjects.size() <= DEFAULT_SHOW_COUNT ) {  57                 headView.setVisibility(View.GONE);  58                 mShowObjects.addAll(mAllObjects);  59             } else {  60                 headView.setVisibility(View.VISIBLE);  61                 for (int i = 0; i < DEFAULT_SHOW_COUNT; i++) {  62                     mShowObjects.add(mAllObjects.get(i));  63                 }  64             }  65         }  66         notifyDataSetChanged();  67         setListViewHeightBasedOnChildren(mListView);  68     }  69       70     @Override  71     public int getCount() {  72         int showCount = 0;  73         if( mShowObjects != null ) {  74             showCount = mShowObjects.size();  75         }  76         return showCount;  77     }  78   79     @Override  80     public E getItem(int position) {  81         E object = null;  82         if( mShowObjects != null ) {  83             object = mShowObjects.get(position);  84         }  85         return object;  86     }  87   88     @Override  89     public long getItemId(int position) {  90         return position;  91     }  92   93     private void changeShow() {  94         if( headView.getVisibility() == View.GONE ) {  95             headView.setVisibility(View.VISIBLE);  96         }  97         mShowObjects.clear();  98         if( shrink ) {  99             shrink = false; 100             mShowObjects.addAll(mAllObjects); 101             btn_loadmore.setText("收起"); 102         } else { 103             shrink = true; 104             for (int i = 0; i < DEFAULT_SHOW_COUNT; i++) { 105                 mShowObjects.add(mAllObjects.get(i)); 106             } 107             btn_loadmore.setText("更多"); 108         } 109         notifyDataSetChanged(); 110         setListViewHeightBasedOnChildren(mListView); 111     } 112      113     /** 114      * 当ListView外层有ScrollView时,需要动态设置ListView高度 115      * @param listView 116      */ 117     protected void setListViewHeightBasedOnChildren(ListView listView) {  118         if(listView == null) return; 119         ListAdapter listAdapter = listView.getAdapter();  120         if (listAdapter == null) {  121             return;  122         }  123         int totalHeight = 0;  124         for (int i = 0; i < listAdapter.getCount(); i++) {  125             View listItem = listAdapter.getView(i, null, listView);  126             listItem.measure(0, 0);  127             totalHeight += listItem.getMeasuredHeight();  128         } 129         ViewGroup.LayoutParams params = listView.getLayoutParams();  130         params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));  131         listView.setLayoutParams(params);  132     } 133  134 }

资源文件lv_footer_button.xml(此处需注意,不要在fl_loadmore这个外部LinearLayout设置高度,而应在Button中设置,否则listview展示的高度与设置的不符(暂不了解原因))

 1 <?xml version="1.0" encoding="utf-8"?>  2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  3     android:id="@+id/fl_loadmore"  4     android:layout_width="match_parent"  5     android:layout_height="wrap_content"  6     android:background="#ffffff"  7     android:orientation="vertical" >  8       9     <LinearLayout android:layout_width="match_parent" 10         android:layout_height="1px" 11         android:orientation="vertical" 12         android:background="#000000"/> 13  14     <Button 15         android:id="@+id/btn_loadmore" 16         android:layout_width="match_parent" 17         android:layout_height="32dp" 18         android:gravity="center" 19         android:background="#00000000" 20         android:text="更多" 21         android:textSize="14sp" /> 22  23 </LinearLayout>

外部调用例子:

对象Bean(StationImage):

 1 package com.example.android_train.bean;  2   3 public class StationImage {  4   5     public String img_name = "";  6     public String img_url_s = "";  7     public String img_url_l = "";  8   9     public String getImg_name() { 10         return img_name; 11     } 12  13     public void setImg_name(String img_name) { 14         this.img_name = img_name; 15     } 16  17     public String getImg_url_s() { 18         return img_url_s; 19     } 20  21     public void setImg_url_s(String img_url_s) { 22         this.img_url_s = img_url_s; 23     } 24  25     public String getImg_url_l() { 26         return img_url_l; 27     } 28  29     public void setImg_url_l(String img_url_l) { 30         this.img_url_l = img_url_l; 31     } 32  33 }

FootviewAdapter继承BaseFootviewAdapter,并实现getView()方法

 1 package com.example.android_train.adapter;  2   3 import android.content.Context;  4 import android.graphics.Paint;  5 import android.view.View;  6 import android.view.ViewGroup;  7 import android.widget.LinearLayout;  8 import android.widget.ListView;  9 import android.widget.TextView; 10  11 import com.example.android_train.R; 12 import com.example.android_train.bean.StationImage; 13  14 public class FootviewAdapter extends BaseFootviewAdapter<StationImage>{ 15      16     private ListItemView listItemView = null; 17  18     public final class ListItemView { 19         public LinearLayout gas_station_groupon_ll; 20         public TextView gpn_name; 21         public TextView gpn_price; 22         public TextView gpn_old_price; 23     } 24  25     public FootviewAdapter( Context mContext, ListView mListView) { 26         super(mContext, mListView); 27     } 28      29     @Override 30     public View getView(int position, View convertView, ViewGroup parent) { 31         final StationImage object = (StationImage)getItem(position); 32         if (convertView == null) { 33             convertView = inflater.inflate(R.layout.lv_gas_station_detail_groupon, parent, false); 34             listItemView = new ListItemView(); 35             creatView(convertView, listItemView); 36             convertView.setTag(listItemView); 37         } else { 38             listItemView = (ListItemView) convertView.getTag(); 39         } 40         listItemView.gpn_name.setText(object.getImg_name()); 41         listItemView.gpn_price.setText("¥" + object.getImg_url_l()); 42         listItemView.gpn_old_price.setText("¥" + object.getImg_url_s()); 43         listItemView.gpn_old_price.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); //中划线 44         return convertView; 45     } 46      47     private void creatView(View rowView, ListItemView listItemView) { 48         listItemView.gas_station_groupon_ll = (LinearLayout) rowView.findViewById(R.id.gas_station_groupon_ll); 49         listItemView.gpn_name = (TextView) rowView.findViewById(R.id.gpn_name); 50         listItemView.gpn_price = (TextView) rowView.findViewById(R.id.gpn_price); 51         listItemView.gpn_old_price = (TextView) rowView.findViewById(R.id.gpn_old_price); 52     } 53  54 }

资源文件(lv_gas_station_detail_groupon)如下:

 1 <?xml version="1.0" encoding="utf-8"?>  2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  3     android:id="@+id/gas_station_groupon_ll"  4     android:layout_width="match_parent"  5     android:layout_height="wrap_content"  6     android:orientation="horizontal" >  7   8     <RelativeLayout  9         android:layout_width="match_parent" 10         android:layout_height="48dp" 11         android:paddingLeft="16dp" 12         android:paddingRight="16dp" > 13  14         <TextView 15             android:id="@+id/gpn_name" 16             android:layout_width="wrap_content" 17             android:layout_height="wrap_content" 18             android:layout_alignParentLeft="true" 19             android:text="ahah" 20             android:textSize="16sp" /> 21  22         <TextView 23             android:id="@+id/gpn_price" 24             android:layout_width="wrap_content" 25             android:layout_height="wrap_content" 26             android:layout_alignParentBottom="true" 27             android:layout_alignParentLeft="true" 28             android:layout_marginRight="16dp" 29             android:singleLine="true" 30             android:text="abc" /> 31  32         <TextView 33             android:id="@+id/gpn_old_price" 34             android:layout_width="wrap_content" 35             android:layout_height="wrap_content" 36             android:layout_alignParentBottom="true" 37             android:layout_toRightOf="@id/gpn_price" 38             android:singleLine="true" 39             android:text="qew" 40             android:textSize="16sp" /> 41     </RelativeLayout> 42  43 </LinearLayout>

Activity中的调用( 实例化FootviewAdapter子类,然后设置相应数据即可 ):

 1 ArrayList<StationImage> mStationImages = new ArrayList<StationImage>();  2 ListView listview = null;  3 for (int i = 0; i < 5; i++) {  4     StationImage mStationImage = new StationImage();  5     mStationImage.setImg_name("第" + i + "个项目的名字");  6     mStationImage.setImg_url_l("第" + i + "个项目的长URL");  7     mStationImage.setImg_url_s("第" + i + "个项目的短URL");  8     mStationImages.add(mStationImage);  9 } 10 listview = (ListView) findViewById(R.id.listview); 11 FootviewAdapter mFootviewAdapter = new FootviewAdapter(this, listview); 12 listview.setAdapter(mFootviewAdapter); 13 mFootviewAdapter.setAdapterData(mStationImages);
正文到此结束
Loading...