Android中ListView封装收缩与展开

常有这种需求,即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);
时间: 2024-10-10 00:17:46

Android中ListView封装收缩与展开的相关文章

Extjs中FieldSet的收缩和展开实例

Extjs中FieldSet的收缩和展开实例: FieldSet表单控件属于Ext.form.FieldSet的类,继承自:Ext.Panel,表示对某一组字段的标准容器,其中最主要的一个功能就是收缩和展开收缩与展开demo: items: [ id:'check_email_hacklog_send', xtype: 'fieldset', height:'auto', checkboxToggle: true, checkboxName: 'enable_email_hacklog_send

Android中ListView分类

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "fill_parent" android:layo

Android中ListView字母排序,实现字母挤压效果以及右侧快速选中字母,搜索关键字功能

Android中ListView字母排序,实现字母挤压效果以及右侧快速选中字母,搜索关键字功能 本文中阐述如何自定义EditText实现搜索框自定义的样式以及挤压字母的思路等 自定义EditText 相关的drawable文件 主界面以及相关的适配器 结果展示 定义要呈现的EditText的样式 public class ClearEditText extends EditText implements OnFocusChangeListener, TextWatcher { /** * 定义删

android中listview点击事件失效的灵异事件

首先说明一下我想实现的功能: 点击某个item之后,让其颜色发生变化.如果变化网上有很多例子,我就不班门弄斧了.Listview之所以点击没有反应是因为上图中绿色部分(自己定义的一个继承BaseAdapter的adapter来适应listview)将listview的item覆盖了.现在点击的只是自定义的adapter中的convertView. 其次,自定义的adapter中包含一个ImageView和二个TextView.代码如下: <?xml version="1.0" e

Android中ListView的addFooterView不显示的问题

mListView.addFooterView(btn_more, null, false); mListView.setAdapter(mBlogListAdapter); 把addFootView放在setAdapter之前就可解决. Android中ListView的addFooterView不显示的问题

Android中ListView选中时的黄色底色

Android的ListView中默认选中时底色为黄色,如何去掉呢 其中会用到一个属性: android:listSelector="#00000000" 这样就行了 Android中ListView选中时的黄色底色

Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

Android中ListView异步加载图片错位.重复.闪烁问题分析及解决方案 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而ImageView控件就是View对象通

Android 中 ListView 常用属性合集

class ListView.FixedViewInfo//用来在列表内展现一个固定位置视图,如在列表顶端的header和在列表底端的footer 一.XML属性 1.ListView的XML属性 android:divider//在列表条目之间显示的drawable或color android:dividerHeight//用来指定divider的高度 android:entries//构成ListView的数组资源的引用.对于某些固定的资源,这个属性提供了比在程序中添加资源更加简便的方式 a

Android中ListView分页加载数据

熟悉Android的朋友们都知道,不管是微博客户端还是新闻客户端,都离不开列表组件,可以说列表组件是Android数据展现方面最重要的组件,我们今天就要讲一讲列表组件ListView加载数据的相关内容.通常来说,一个应用在展现大量数据时,不会将全部的可用数据都呈现给用户,因为这不管对于服务端还是客户端来说都是不小的压力,因此,很多应用都是采用分批次加载的形式来获取用户所需的数据.比如:微博客户端可能会在用户滑动至列表底端时自动加载下一页数据,也可能在底部放置一个“加载更多”按钮,用户点击后,加载