ListView下拉刷新及上拉更多兩種狀態


一、前言:

        很多應用都會用到ListView,當然如果是iOS就會用UITableViewController,這兩個控件在不同的OS上,功能是一樣的,只是有些細微的不同(iOS的UITableViewController支持靜態與動態兩種),不過,大多數應用都用的是動態屬性,那么,這里就涉及到一個問題:刷新及加載更多內容。

        目前網上流行的有兩種方式:

        1. 通用的方法,即將ListView, GridView和ScrollView當成ChildView,在這頂部及底部各加一個Layout,但是,一但出現了,就一直顯示在頂部或底部,並不會隨着ChildView的滾動而滾動,功能實用,就是有點破壞美感;

        2. 各自實現,即如果需要實現ListView的下拉刷新和上拉更多,那么就得去繼承ListView,並對它的HeaderView和FooterView做一些擴展,同理,GridView和ScrollView;

        本篇將使用第二種方法來實現,如果通過繼承ListView的方式,來實現下拉刷新,以及上拉更多,或者是點擊底部加載更多的。

二、實現:

2.1 HeaderView的布局,以及代碼實現

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ffffff"
    android:gravity="bottom">
    
    <RelativeLayout 
        android:id="@+id/header_content"
        android:layout_width="match_parent"
        android:layout_height="60dip">
        
        <LinearLayout 
            android:id="@+id/layoutTitle"
            android:layout_width="wrap_content"
        	   android:layout_height="wrap_content"
        	   android:layout_centerInParent="true"
        	   android:gravity="center"
        	   android:orientation="vertical">
        	
            <TextView 
	            android:id="@+id/refresh_tips"
	            android:layout_width="wrap_content"
	            android:layout_height="wrap_content"
	            android:textSize="15sp"
	            android:text="@string/pull_down_for_refresh"/>
            
            <LinearLayout 
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:layout_marginTop="4dip">
                
                <TextView 
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:textSize="12sp"
		            android:text="@string/label_update"/>
                <TextView 
		            android:id="@+id/refresh_last_time"
		            android:layout_width="wrap_content"
		            android:layout_height="wrap_content"
		            android:textSize="12sp"
		            android:text="@string/label_last_time"/>
                
            </LinearLayout>
            
        </LinearLayout>
        
        <ImageView 
	        android:id="@+id/ivArrow"
	        android:layout_height="wrap_content"
	        android:layout_width="wrap_content"
	        android:layout_toLeftOf="@id/layoutTitle"
	        android:layout_centerInParent="true"
	        android:layout_marginRight="30dip"
	        android:contentDescription="@string/image_desc"
	        android:src="@drawable/refresh_arrow_down"/>
        
        <ProgressBar 
	        android:id="@+id/pbWaiting"
	        android:visibility="gone"
	        android:layout_height="wrap_content"
	        android:layout_width="wrap_content"
	        android:layout_toLeftOf="@id/layoutTitle"
	        android:layout_centerInParent="true"
	        android:layout_marginRight="30dip"
	        style="?android:attr/progressBarStyleSmall"/>

    </RelativeLayout>

</LinearLayout>

布局很簡單,一些TextView,一個ImageView和一個ProgressBar。再來看看代碼實現

package com.chris.list.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

public class HeaderView extends LinearLayout {

	public final static int STATE_NORMAL = 0;
	public final static int STATE_WILL_RELEASE = 1;
	public final static int STATE_REFRESHING = 2;
	private int mState = STATE_NORMAL;
	
	private View mHeader = null;
	private ImageView mArrow = null;
	private ProgressBar mProgressBar = null;
	private TextView mRefreshTips = null;
	//private TextView mRefreshLastTime = null;
	private RotateAnimation mRotateUp = null;
	private RotateAnimation mRotateDown = null;
	private final static int ROTATE_DURATION = 250;
	
	public HeaderView(Context context) {
		this(context, null);
	}
	
	public HeaderView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initHeaderView(context);
	}

	private void initHeaderView(Context context){
		LinearLayout.LayoutParams lp = new LayoutParams(
				LayoutParams.MATCH_PARENT, 0);
		mHeader = LayoutInflater.from(context).inflate(R.layout.refresh_header, null);
		addView(mHeader, lp);
		setGravity(Gravity.BOTTOM);
		
		mArrow = (ImageView) mHeader.findViewById(R.id.ivArrow);
		mProgressBar = (ProgressBar) mHeader.findViewById(R.id.pbWaiting);
		mRefreshTips = (TextView) mHeader.findViewById(R.id.refresh_tips);
		//mRefreshLastTime = (TextView) mHeader.findViewById(R.id.refresh_last_time);
		
		mRotateUp = new RotateAnimation(0.0f, -180.0f,  
				Animation.RELATIVE_TO_SELF, 0.5f, 
				Animation.RELATIVE_TO_SELF, 0.5f);
		mRotateUp.setDuration(ROTATE_DURATION);
		mRotateUp.setFillAfter(true);
		
		mRotateDown = new RotateAnimation(-180.0f, 0.0f,
				Animation.RELATIVE_TO_SELF, 0.5f, 
				Animation.RELATIVE_TO_SELF, 0.5f);
		mRotateDown.setDuration(ROTATE_DURATION);
		mRotateDown.setFillAfter(true);
	}
	
	public void setHeaderState(int state){
		if(mState == state){
			return;
		}
		
		mArrow.clearAnimation();
		if(state == STATE_REFRESHING){
			mProgressBar.setVisibility(View.VISIBLE);
			mArrow.setVisibility(View.GONE);
		}else{
			mProgressBar.setVisibility(View.GONE);
			mArrow.setVisibility(View.VISIBLE);
		}
		
		switch(state){
		case STATE_NORMAL:
			mArrow.startAnimation(mRotateDown);
			mRefreshTips.setText(R.string.pull_down_for_refresh);
			break;
			
		case STATE_WILL_RELEASE:
			mArrow.startAnimation(mRotateUp);
			mRefreshTips.setText(R.string.release_for_refresh);
			break;
			
		case STATE_REFRESHING:
			mRefreshTips.setText(R.string.refreshing);
			break;
		
		default:
			break;
		}
		
		mState = state;
	}
	
	public int getCurrentState(){
		return mState;
	}
	
	public void setHeaderHeight(int height){
		if(height <= 0){
			height = 0;
		}
		LayoutParams lp = (LayoutParams) mHeader.getLayoutParams();
		lp.height = height;
		mHeader.setLayoutParams(lp);
	}
	public int getHeaderHeight(){
		return mHeader.getHeight();
	}
}

這個代碼中,主要就兩個函數:setHeaderState 和 setHeaderHeight。 前者是根據TouchEvent,以及當前移動的距離,來設置狀態,同時,移動的距離去設置HeaderView的高度,達到一點一點的顯示出來。

2.2 FooterView的布局,以及代碼實現

看了HeaderView的布局與實現后,FooterView的布局與實現也差不多,咱們一起來看看吧

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="top" >

    <RelativeLayout
        android:id="@+id/footer_content"
        android:layout_width="match_parent"
        android:layout_height="60dip" >

        <TextView
            android:id="@+id/loader_tips"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/pull_up_for_more"
            android:textSize="15sp" />

        <ImageView
            android:id="@+id/ivLoaderArrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginRight="30dip"
            android:layout_toLeftOf="@id/loader_tips"
            android:contentDescription="@string/image_desc"
            android:src="@drawable/refresh_arrow_up" />

        <ProgressBar
            android:id="@+id/pbLoaderWaiting"
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginRight="30dip"
            android:layout_toLeftOf="@id/loader_tips"
            android:visibility="gone" />
    </RelativeLayout>

</LinearLayout>

哇,這個布局比HeaderView布局還要簡單!?這個布局涵蓋了兩部分,不過,在布局中無法體現出來,但在代碼實現中體現出來了:

1. 上拉更多,這個布局全部顯示;

2. 如果是滑到底部點擊加載,就不會有ImageView;

還是來看看代碼實現吧

package com.chris.list.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

public class FooterView extends LinearLayout {

	public final static int FOOTER_OPTIONS_PULL = 0;
	public final static int FOOTER_OPTIONS_CLICK = 1;
	private static int sFooterOps = FOOTER_OPTIONS_PULL;
	
	public final static int STATE_NORMAL = 0;
	public final static int STATE_WILL_RELEASE = 1;
	public final static int STATE_LOADING = 2;
	private int mState = STATE_NORMAL;
	
	private View mFooter = null;
	private ImageView mArrow = null;
	private ProgressBar mProgressBar = null;
	private TextView mLoaderTips = null;
	
	private RotateAnimation mRotateUp = null;
	private RotateAnimation mRotateDown = null;
	private final static int ROTATE_DURATION = 250;
	
	public FooterView(Context context) {
		this(context, null);
	}
	
	public FooterView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initFooterView(context);
	}
	
	private void initFooterView(Context context){
		LinearLayout.LayoutParams lp = new LayoutParams(
				LayoutParams.MATCH_PARENT, 0);
		mFooter = LayoutInflater.from(context).inflate(R.layout.loader_footer, null);
		addView(mFooter, lp);
		
		mArrow = (ImageView) mFooter.findViewById(R.id.ivLoaderArrow);
		mProgressBar = (ProgressBar) mFooter.findViewById(R.id.pbLoaderWaiting);
		mLoaderTips = (TextView) mFooter.findViewById(R.id.loader_tips);
		
		mRotateDown = new RotateAnimation(0.0f, 180.0f,  
				Animation.RELATIVE_TO_SELF, 0.5f, 
				Animation.RELATIVE_TO_SELF, 0.5f);
		mRotateDown.setDuration(ROTATE_DURATION);
		mRotateDown.setFillAfter(true);
		
		mRotateUp = new RotateAnimation(180.0f, 0.0f,
				Animation.RELATIVE_TO_SELF, 0.5f, 
				Animation.RELATIVE_TO_SELF, 0.5f);
		mRotateUp.setDuration(ROTATE_DURATION);
		mRotateUp.setFillAfter(true);
		
		setFooterViewOptions(FOOTER_OPTIONS_CLICK);
	}
	
	public void setFooterViewOptions(int options){
		sFooterOps = options;
		
		switch(sFooterOps){
		case FOOTER_OPTIONS_PULL:
			hide();
			break;
			
		case FOOTER_OPTIONS_CLICK:
			show();
			break;
			
		default:
			break;
		}
	}
	
	public int getFooterViewOptions(){
		return sFooterOps;
	}
	
	public void setFooterState(int state){
		if(mState == state){
			return;
		}
		
		mArrow.clearAnimation();
		if(state == STATE_LOADING){
			mProgressBar.setVisibility(View.VISIBLE);
			mArrow.setVisibility(View.GONE);
		}else{
			mProgressBar.setVisibility(View.GONE);
			mArrow.setVisibility(View.VISIBLE);
		}
		
		switch(state){
		case STATE_NORMAL:
			mArrow.startAnimation(mRotateUp);
			mLoaderTips.setText(R.string.pull_up_for_more);
			break;
			
		case STATE_WILL_RELEASE:
			mArrow.startAnimation(mRotateDown);
			mLoaderTips.setText(R.string.release_for_more);
			break;
			
		case STATE_LOADING:
			mLoaderTips.setText(R.string.loading);
			break;
		
		default:
			break;
		}
		mState = state;
	}
	
	public int getCurrentState(){
		return mState;
	}
	
	public void setFooterHeight(int height){
		if(height <= 0){
			height = 0;
		}
		
		LayoutParams lp = (LayoutParams) mFooter.getLayoutParams();
		lp.height = height;
		mFooter.setLayoutParams(lp);
	}
	
	public int getFooterHeight(){
		return mFooter.getHeight();
	}
	
	public void hide(){
		mArrow.clearAnimation();
		mArrow.setVisibility(View.VISIBLE);
		mLoaderTips.setText(R.string.pull_up_for_more);
		setFooterHeight(0);
	}
	
	public void show(){
		mArrow.clearAnimation();
		mArrow.setVisibility(View.GONE);
		mLoaderTips.setText(R.string.click_for_more);
		
		LayoutParams lp = (LayoutParams) mFooter.getLayoutParams();
		lp.height = LayoutParams.WRAP_CONTENT;
		mFooter.setLayoutParams(lp);
	}
}

代碼中,有個Options函數,用來提供設置:上拉或點擊。同樣,也有設置狀態,和設計高度。

2.3 擴展ListView的實現

package com.chris.list.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.AbsListView.OnScrollListener;

public class ListViewExt extends ListView implements OnScrollListener {

	private final static String TAG = "ChrisLV";
	
	private HeaderView mHeaderView = null;
	private RelativeLayout mHeaderContent = null;
	private int iHeaderHeight = 0;
	
	private FooterView mFooterView = null;
	private RelativeLayout mFooterContent = null;
	private int iFooterHeight = 0;
	
	private final static int SCROLL_HEADER = 0;
	private final static int SCROLL_FOOTER = 1;
	private int iScrollWhich = SCROLL_HEADER;
	
	private Scroller mScroller = null;
	private final static float OFFSET_Y = 0.7f;
	private float iLastY = 0;
	private int mTotalNumber = 0;
	
	public ListViewExt(Context context) {
		this(context, null, 0);
	}
	public ListViewExt(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}
	public ListViewExt(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView(context);
	}

	private void initView(Context context){
		/*
		 * mScroller用來回彈下拉刷新/上拉更多
		 * 配合computerScroll來使用
		 */
		mScroller = new Scroller(context, new DecelerateInterpolator());
		super.setOnScrollListener(this);
		
		initHeaderView(context);
		initFooterView(context);
	}
	
	@Override
	public void setAdapter(ListAdapter adapter) {
		if(getFooterViewsCount() == 0){
			addFooterView(mFooterView);
		}
		super.setAdapter(adapter);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		
		switch(ev.getAction()){
		case MotionEvent.ACTION_DOWN:
			iLastY = ev.getY();
			break;
			
		case MotionEvent.ACTION_MOVE:
			float deltaY = ev.getY() - iLastY;
			iLastY = ev.getY();
			if(canHeaderPull() && getFirstVisiblePosition() == 0 &&
			   (deltaY > 0 || mHeaderView.getHeaderHeight() > 0)){
				updateHeaderState(deltaY * OFFSET_Y);
			}else if(canFooterPull() && getLastVisiblePosition() == mTotalNumber - 1
					&& (deltaY < 0 || mFooterView.getFooterHeight() > 0)){
				updateFooterState(-deltaY * OFFSET_Y);
			}
			break;
			
		case MotionEvent.ACTION_UP:
			if(getFirstVisiblePosition() == 0){
				if(mHeaderView.getHeaderHeight() > iHeaderHeight){
				   mHeaderView.setHeaderState(HeaderView.STATE_REFRESHING);
				   if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
						mFooterView.hide();
					}
				}
				resetHeader();
			}else if(getLastVisiblePosition() == mTotalNumber - 1){
				if(mFooterView.getFooterHeight() > iFooterHeight){
					mFooterView.setFooterState(FooterView.STATE_LOADING);
				}
				resetFooter();
			}
			break;
		
		default:
			break;
		}
		return super.onTouchEvent(ev);
	}

	@Override
	public void computeScroll() {
		if(mScroller.computeScrollOffset()){
			if(iScrollWhich == SCROLL_HEADER){
				mHeaderView.setHeaderHeight(mScroller.getCurrY());
			}else if(iScrollWhich == SCROLL_FOOTER){
				mFooterView.setFooterHeight(mScroller.getCurrY());
			}
		}
		super.computeScroll();
	}
	
	/*
	 * 獲取ListView有多少個item:
	 * 1. 在init中,需要設置super.setOnScrollListener;
	 * 2. 重載以下兩個函數;
	 * 3. 在onScroll中取得totalItemCount即可;
	 */
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		mTotalNumber = totalItemCount;
	}
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
	}
	/////////////////////////////////////////////////////////////////////////////
	private boolean canHeaderPull(){
		if(mFooterView.getCurrentState() == FooterView.STATE_NORMAL){
			return true;
		}
		return false;
	}
	
	private boolean canFooterPull(){
		if(mHeaderView.getCurrentState() == HeaderView.STATE_NORMAL){
			return true;
		}
		return false;
	}
	///////////////////////////////////// Header ////////////////////////////////
	public void stopRefresh(){
		if(mHeaderView.getCurrentState() == HeaderView.STATE_REFRESHING){
			mHeaderView.setHeaderState(HeaderView.STATE_NORMAL);
			resetHeader();
			if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
				mFooterView.show();
			}
		}
	}
	
	private void initHeaderView(Context context){
		mHeaderView = new HeaderView(context);
		mHeaderContent = (RelativeLayout) mHeaderView.findViewById(R.id.header_content);
		addHeaderView(mHeaderView);
		mHeaderView.getViewTreeObserver()
				   .addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
			@Override
			public void onGlobalLayout() {
				iHeaderHeight = mHeaderContent.getHeight();
				Log.d(TAG, "iHeaderHeight = " + iHeaderHeight);
				getViewTreeObserver().removeGlobalOnLayoutListener(this);
			}
		});
	}
	
	private void updateHeaderState(float delta){
		mHeaderView.setHeaderHeight((int)(delta + mHeaderView.getHeaderHeight()));
		if(mHeaderView.getCurrentState() != HeaderView.STATE_REFRESHING){
			if(mHeaderView.getHeaderHeight() > iHeaderHeight){
				mHeaderView.setHeaderState(HeaderView.STATE_WILL_RELEASE);
			}else{
				mHeaderView.setHeaderState(HeaderView.STATE_NORMAL);
			}
		}
		setSelection(0);
	}
	
	private void resetHeader(){
		int height = mHeaderView.getHeaderHeight();
		if(height == 0){
			return;
		}

		int finalHeight = 0;
		if(height > iHeaderHeight){
			/*
			 * 如果超過HeaderView高度,則回滾到HeaderView高度即可
			 */
			finalHeight = iHeaderHeight;
		}else if(mHeaderView.getCurrentState() == HeaderView.STATE_REFRESHING){
			/*
			 * 如果HeaderView未完全顯示
			 * 1. 處於正在刷新中,則不管;
			 * 2. 回滾HeaderView當前可視高度
			 */
			return;
		}
		
		iScrollWhich = SCROLL_HEADER;
		mScroller.startScroll(0, height, 0, finalHeight - height, 250);
		invalidate();
	}
	/////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////// Footer ////////////////////////////////
	public void setFooterMode(int options){
		mFooterView.setFooterViewOptions(options);
	}
	
	public void stopLoad(){
		if(mFooterView.getCurrentState() == FooterView.STATE_LOADING){
			mFooterView.setFooterState(FooterView.STATE_NORMAL);
			resetFooter();
		}
	}
	
	private void initFooterView(Context context){
		mFooterView = new FooterView(context);
		mFooterContent = (RelativeLayout) mFooterView.findViewById(R.id.footer_content);
		mFooterContent.setOnClickListener(new OnClickListener(){
			@Override
			public void onClick(View v) {
				if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK
						&& mFooterView.getCurrentState() == FooterView.STATE_NORMAL){
					mFooterView.setFooterState(FooterView.STATE_LOADING);
				}
			}
		});
		mFooterView.getViewTreeObserver()
				   .addOnGlobalLayoutListener(new OnGlobalLayoutListener(){
			@Override
			public void onGlobalLayout() {
				iFooterHeight = mFooterContent.getHeight();
				Log.d(TAG, "iFooterHeight = " + iFooterHeight);
				getViewTreeObserver().removeGlobalOnLayoutListener(this);
			}
		});
	}
	
	private void updateFooterState(float delta){
		if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
			return;
		}
		
		mFooterView.setFooterHeight((int)(delta + mFooterView.getFooterHeight()));
		if(mFooterView.getCurrentState() != FooterView.STATE_LOADING){
			if(mFooterView.getFooterHeight() > iFooterHeight){
				mFooterView.setFooterState(FooterView.STATE_WILL_RELEASE);
			}else{
				mFooterView.setFooterState(FooterView.STATE_NORMAL);
			}
		}
	}
	
	private void resetFooter(){
		int height = mFooterView.getFooterHeight();
		if(height == 0){
			return;
		}
		
		if(mFooterView.getFooterViewOptions() == FooterView.FOOTER_OPTIONS_CLICK){
			return;
		}
		
		int finalHeight = 0;
		if(height > iFooterHeight){
			finalHeight = iFooterHeight;
		}else if(mFooterView.getCurrentState() == FooterView.STATE_LOADING){
			return;
		}

		iScrollWhich = SCROLL_FOOTER;
		mScroller.startScroll(0, height, 0, finalHeight - height, 250);
		invalidate();
	}
	/////////////////////////////////////////////////////////////////////////////
}

代碼結構比較清楚,相關的都集中在一起,大致流程是:

1. down時,記住坐標;

2. move時,判斷當前可見是否是第一個或是最后一個,如果是,則將移動的距離去設置HeaderView或FooterView的高度,達到一點一點的顯示出來;

3. up時,判斷HeaderView或FooterView是否滾動的距離超過它們的高度,如果是,則表示是刷新或加載,且回彈到移動的距離-高度;

4. 代碼還提供了沖突設置,即如果當前正在刷新中,則不允許滾動到底部上拉更多,或者顯示“點擊加載更多”,同樣,如果是底部正在加載,則不允許滾動到頂多,下拉刷新;

2.4 使用舉例

首頁布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.chris.list.refresh.ListViewExt 
        android:id="@+id/listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="#000000"
        android:dividerHeight="0.5dip"/>

</RelativeLayout>

首頁Activity代碼實現,和一般的使用ListView方法一樣

package com.chris.list.refresh;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.app.Activity;

public class MainActivity extends Activity {

	private final static String TAG = "ChrisLV";
	private ListViewExt mListView = null;
	private String[] mList = {
		"abcd1", "abcd2", "abcd3", "abcd4", "abcd5", "abcd6",
		"abcd7", "abcd8", "abcd9", "abcd10", "abcd11", "abcd12",
		"abcd13", "abcd14", "abcd15", "abcd16", "abcd17", "abcd18",
		"abcd19", "abcd20", "abcd21", "abcd22", "abcd23", "abcd24"
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mListView = (ListViewExt) findViewById(R.id.listview);
		mListView.setAdapter(new ArrayAdapter<String>(this, 
				android.R.layout.simple_list_item_1, 
				mList));
		
		mListView.setOnItemClickListener(new OnItemClickListener(){
			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				Log.d(TAG, "arg2 = " + arg2);
				if(arg2 > 0){
					mListView.stopRefresh();
					mListView.stopLoad();
				}
				
				mListView.setFooterMode(arg2 % 2);
			}
		});
	}

}

在onItemClick中,只是做了簡單的將HeaderView或FooterView停止,並設置FooterView的加載模式:是上拉更多,還是點擊加載更多。

三、小結

本篇文章,大致就這么多,雖然,為了UI體驗友好,花了很多精力,但是一通百通,其它的也不外乎是這些,所以大家學習后,希望能舉一反三,同時,咱們也交流交流。

 

源碼下載地址: http://download.csdn.net/detail/qingye_love/5597623


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM