編輯: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實現)
package com.example.android_train.adapter;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.example.android_train.R;
public abstract class BaseFootviewAdapter<E> extends BaseAdapter {
public static final int DEFAULT_SHOW_COUNT = 2;
protected Context mContext;
protected ListView mListView;
protected LayoutInflater inflater;
protected LinearLayout headView;
protected Button btn_loadmore;
protected ArrayList<E> mShowObjects = new ArrayList<E>();
protected ArrayList<E> mAllObjects = null;
protected boolean shrink = true;
@SuppressWarnings("unused")
private BaseFootviewAdapter() {
}
@SuppressLint("InflateParams")
public BaseFootviewAdapter( Context mContext, ListView mListView) {
this.mContext = mContext;
this.mListView = mListView;
inflater = LayoutInflater.from(mContext);
headView = (LinearLayout) inflater.inflate(R.layout.lv_footer_button, null);
btn_loadmore = (Button) headView.findViewById(R.id.btn_loadmore);
btn_loadmore.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
changeShow();
}
});
mListView.addFooterView(headView, null, false);
}
public void setAdapterData( ArrayList<E> mAllObjects ) {
this.mAllObjects = mAllObjects;
mShowObjects.clear();
if( mAllObjects != null ) {
if( mAllObjects.size() <= DEFAULT_SHOW_COUNT ) {
headView.setVisibility(View.GONE);
mShowObjects.addAll(mAllObjects);
} else {
headView.setVisibility(View.VISIBLE);
for (int i = 0; i < DEFAULT_SHOW_COUNT; i++) {
mShowObjects.add(mAllObjects.get(i));
}
}
}
notifyDataSetChanged();
setListViewHeightBasedOnChildren(mListView);
}
@Override
public int getCount() {
int showCount = 0;
if( mShowObjects != null ) {
showCount = mShowObjects.size();
}
return showCount;
}
@Override
public E getItem(int position) {
E object = null;
if( mShowObjects != null ) {
object = mShowObjects.get(position);
}
return object;
}
@Override
public long getItemId(int position) {
return position;
}
private void changeShow() {
if( headView.getVisibility() == View.GONE ) {
headView.setVisibility(View.VISIBLE);
}
mShowObjects.clear();
if( shrink ) {
shrink = false;
mShowObjects.addAll(mAllObjects);
btn_loadmore.setText("收起");
} else {
shrink = true;
for (int i = 0; i < DEFAULT_SHOW_COUNT; i++) {
mShowObjects.add(mAllObjects.get(i));
}
btn_loadmore.setText("更多");
}
notifyDataSetChanged();
setListViewHeightBasedOnChildren(mListView);
}
/**
* 當ListView外層有ScrollView時,需要動態設置ListView高度
* @param listView
*/
protected void setListViewHeightBasedOnChildren(ListView listView) {
if(listView == null) return;
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
}
資源文件lv_footer_button.xml(此處需注意,不要在fl_loadmore這個外部LinearLayout設置高度,而應在Button中設置,否則listview展示的高度與設置的不符(暫不了解原因))
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fl_loadmore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical" >
<LinearLayout android:layout_width="match_parent"
android:layout_height="1px"
android:orientation="vertical"
android:background="#000000"/>
<Button
android:id="@+id/btn_loadmore"
android:layout_width="match_parent"
android:layout_height="32dp"
android:gravity="center"
android:background="#00000000"
android:text="更多"
android:textSize="14sp" />
</LinearLayout>
外部調用例子:
對象Bean(StationImage):
package com.example.android_train.bean;
public class StationImage {
public String img_name = "";
public String img_url_s = "";
public String img_url_l = "";
public String getImg_name() {
return img_name;
}
public void setImg_name(String img_name) {
this.img_name = img_name;
}
public String getImg_url_s() {
return img_url_s;
}
public void setImg_url_s(String img_url_s) {
this.img_url_s = img_url_s;
}
public String getImg_url_l() {
return img_url_l;
}
public void setImg_url_l(String img_url_l) {
this.img_url_l = img_url_l;
}
}
FootviewAdapter繼承BaseFootviewAdapter,並實現getView()方法
package com.example.android_train.adapter;
import android.content.Context;
import android.graphics.Paint;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.example.android_train.R;
import com.example.android_train.bean.StationImage;
public class FootviewAdapter extends BaseFootviewAdapter<StationImage>{
private ListItemView listItemView = null;
public final class ListItemView {
public LinearLayout gas_station_groupon_ll;
public TextView gpn_name;
public TextView gpn_price;
public TextView gpn_old_price;
}
public FootviewAdapter( Context mContext, ListView mListView) {
super(mContext, mListView);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final StationImage object = (StationImage)getItem(position);
if (convertView == null) {
convertView = inflater.inflate(R.layout.lv_gas_station_detail_groupon, parent, false);
listItemView = new ListItemView();
creatView(convertView, listItemView);
convertView.setTag(listItemView);
} else {
listItemView = (ListItemView) convertView.getTag();
}
listItemView.gpn_name.setText(object.getImg_name());
listItemView.gpn_price.setText("¥" + object.getImg_url_l());
listItemView.gpn_old_price.setText("¥" + object.getImg_url_s());
listItemView.gpn_old_price.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); //中劃線
return convertView;
}
private void creatView(View rowView, ListItemView listItemView) {
listItemView.gas_station_groupon_ll = (LinearLayout) rowView.findViewById(R.id.gas_station_groupon_ll);
listItemView.gpn_name = (TextView) rowView.findViewById(R.id.gpn_name);
listItemView.gpn_price = (TextView) rowView.findViewById(R.id.gpn_price);
listItemView.gpn_old_price = (TextView) rowView.findViewById(R.id.gpn_old_price);
}
}
資源文件(lv_gas_station_detail_groupon)如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gas_station_groupon_ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:paddingLeft="16dp"
android:paddingRight="16dp" >
<TextView
android:id="@+id/gpn_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="ahah"
android:textSize="16sp" />
<TextView
android:id="@+id/gpn_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginRight="16dp"
android:singleLine="true"
android:text="abc" />
<TextView
android:id="@+id/gpn_old_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@id/gpn_price"
android:singleLine="true"
android:text="qew"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>
Activity中的調用(實例化FootviewAdapter子類,然後設置相應數據即可):
ArrayList<StationImage> mStationImages = new ArrayList<StationImage>();
ListView listview = null;
for (int i = 0; i < 5; i++) {
StationImage mStationImage = new StationImage();
mStationImage.setImg_name("第" + i + "個項目的名字");
mStationImage.setImg_url_l("第" + i + "個項目的長URL");
mStationImage.setImg_url_s("第" + i + "個項目的短URL");
mStationImages.add(mStationImage);
}
listview = (ListView) findViewById(R.id.listview);
FootviewAdapter mFootviewAdapter = new FootviewAdapter(this, listview);
listview.setAdapter(mFootviewAdapter);
mFootviewAdapter.setAdapterData(mStationImages);
再次探究Android ListView緩存機制
概述 雖然現在5.0後Google推出了RecycleView,但在5.0 Lollipop普及前Listview仍會被廣泛使用,所以打算再次探究一下Listvi
Android訪問和加載本地聯系人的代碼實現
在Android開發中,我們經常會遇到訪問和加載本地聯系人的情況,畢竟手機中聯系人是最重要的數據之一,很多手機應用都會需要手機聯系人的信息,比如姓名、手機號碼等。
如何用PHP開發Android應用程序
Google的開源Android移動操作系統正在席卷全球智能手機市場,和蘋果不一樣,它對那些想將應用程序提交到iPhone App Store的開發人員有著嚴格的
Android 自定義 AlertDialog 提示框
在Android開發中,因項目需要,大部分情況下需要自定義Dialog來滿足項目需求,系統雖然也有,但是界面美觀方面,不忍直視。 下面貼出Android項目中使用