常有这种需求,即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);