• 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);
  • 相关阅读:
    再回首,Java温故知新(八):Java基础之字符串
    《Prism 5.0源码走读》 设计模式
    《Prism 5.0源码走读》Bootstrapper
    VS编译时自动下载NuGet管理的库
    《Prism 5.0源码走读》Prism 5.0简介
    代码阅读
    如何建设个人品牌
    Hexo建站教程
    Codeforce:131A. cAPS lOCK
    一文看懂《最大子序列和问题》
  • 原文地址:https://www.cnblogs.com/creasylai19/p/4318808.html
Copyright © 2020-2023  润新知