Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android最基本的lsitvew實現下拉刷新,上拉加載更多的demo

android最基本的lsitvew實現下拉刷新,上拉加載更多的demo

編輯:關於Android編程

接著上次來講,這次來動手寫一下listview的下拉刷新功能和上拉加載更多功能。

當然google在android4.0以上的API裡面的提供了一個可以下拉加載更多的控件,這個小圓圈加載控件在豆瓣,知乎日報裡面都有運用到,而我在下一篇博客也會提到。

先來了解一下最基本的listview的的加載功能吧。

首先是下拉刷新功能,我先說一下基本的思路。listveiw的面提供了一個addheader()方法,我們可以重寫listview,然後用addheader方法加載我們自定義的加載布局。然後就是隱藏這個header,然後復寫監聽方法OnScrollListener()和OnTouch()方法,最後再提供一個接口方法來讓用戶實現加載數據。具體的我在代碼裡面都注釋好了。

再來說一下上拉加載,這個相比於下拉加載就簡單多了,我們可以addfooter()方法添加布局,然後監聽OnScrollListener就可以了,當最後一個可見的item等於總數量的item時,就可以加載數據了。具體在代碼裡面斗注釋好了。

 

效果圖:

\

\

先發布局文件:

 



    
        
    
    


header.xml

 

 




    

        

            

            
        

        
        

        
    



 

footer.xml




    

        
        
        
    


 

listitem.xml

 




    

    



自定義的listview方法:

 

 

package com.example.listview_pulltorefresh;

import java.sql.Date;
import java.text.SimpleDateFormat;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

public class RefreshListview extends ListView {
	private View header;// 頂部布局文件
	private View footer;// 底部布局
	private int headerHeight;// 頂部布局文件的高度
	private int firstVisibleItem;// 當前第一個可見item的位置
	private boolean isRemark;// 標記當前listviews是否最頂端摁下
	private int startY;// 開始的Y值

	private int mscrollState;// 當前listview的滾動狀態
	private int state;// 當前狀態
	private static final int NONE = 0;// 正常狀態
	private static final int PULL = 1;// 下拉狀態
	private static final int RELEASE = 2;// 松開狀態
	private static final int REFRESHING = 3;// 刷新狀態
	
	
	private int mtotalItemCount;//全部item的數量
	private int lastVisableItem;//最後一個可見的item
	private boolean isLoading=false;//是否正在加載

	public RefreshListview(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		// TODO Auto-generated constructor stub
		initView(context);
	}

	public RefreshListview(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		initView(context);
	}

	public RefreshListview(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		initView(context);
	}

	/**
	 * 添加頂部布局文件
	 * 
	 * @param context
	 */
	private void initView(Context context) {
		LayoutInflater inflater = LayoutInflater.from(context);
		footer = inflater.inflate(R.layout.footer_loading, null, false);
		header = inflater.inflate(R.layout.header_layout, null, false);
		measureView(header);
		headerHeight = header.getMeasuredHeight();
		Log.i("test", "headHeight:" + headerHeight);
		topPadding(-headerHeight);
		this.addHeaderView(header);
		//先設置底部隱藏
		footer.setVisibility(View.GONE);
		this.addFooterView(footer);
		this.setOnScrollListener(new OnScrollListener() {

			@Override
			public void onScrollStateChanged(AbsListView view, int scrollState) {
				// TODO Auto-generated method stub
				mscrollState = scrollState;
				
				//最後一個可見的item是總數量,並且當前滾動狀態停止,就加載數據
				if (mtotalItemCount==lastVisableItem&&scrollState==OnScrollListener.SCROLL_STATE_IDLE) {
					if (!isLoading) {
						//加載數據
						isLoading=true;
						footer.setVisibility(VISIBLE);
						mListener2.onReflashMore();
						
					}
					
					
				}
			}

			/**
			 * firstvisebleitem第一個可見的位置
			 */
			@Override
			public void onScroll(AbsListView view, int firstVisibleItem,
					int visibleItemCount, int totalItemCount) {
				// TODO Auto-generated method stub
				lastVisableItem=firstVisibleItem+visibleItemCount;
				mtotalItemCount=totalItemCount;
			}

		});

		this.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				// TODO Auto-generated method stub
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					if (firstVisibleItem == 0) {
						isRemark = true;
						startY = (int) event.getY();
					}
				case MotionEvent.ACTION_MOVE:
					onMove(event);

					break;
				case MotionEvent.ACTION_UP:
					if (state == RELEASE) {

						state = REFRESHING;
						reflashViewByState();
						mListener.onrReflash(); // 加載數據
						// 在外部調用reflashcomplete
					} else if (state == PULL) {
						state = NONE;
						isRemark = false;
						reflashViewByState();
					}
					break;

				default:
					break;
				}
				return false;
			}
		});
	}

	/**
	 * 通過view獲取layoutparams,然後初始化lp, 要調用measure()方法來設置子view的寬高
	 * measure的方法參數有變化的是用MeasureSpec.makeMeasureSpec設置
	 * 沒有變化的用getChildMeasureSpec()方法設置
	 * 
	 * @param view
	 */

	public void measureView(View view) {
		ViewGroup.LayoutParams lParams = view.getLayoutParams();
		if (lParams == null) {
			lParams = new ViewGroup.LayoutParams(
					ViewGroup.LayoutParams.MATCH_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT);
			// spec左右邊距,padding內邊距
			int width = ViewGroup.getChildMeasureSpec(0, 0, lParams.width);
			int height;
			int tempHeight = lParams.height;
			if (tempHeight > 0) {
				// 填充用exactly
				height = MeasureSpec.makeMeasureSpec(tempHeight,
						MeasureSpec.EXACTLY);

			} else {
				// 意思就是<=0時,則告訴父布局子view高度填充0
				height = MeasureSpec
						.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
			}
			view.measure(width, height);
		}

	}

	/**
	 * 設置header布局的上邊距
	 * 
	 * @param topPadding
	 */
	public void topPadding(int topPadding) {
		header.setPadding(header.getPaddingLeft(), topPadding,
				header.getPaddingRight(), header.getPaddingBottom());
		header.invalidate();
	}

	/**
	 * 判斷移動過程中的操作
	 * 
	 * @param event
	 */
	private void onMove(MotionEvent event) {
		// TODO Auto-generated method stub
		if (!isRemark) {
			return;
		}
		int tempY = (int) event.getY();// 獲取當前y
		int space = tempY - startY;// 顯示的高度
		int topPadding = space - headerHeight;// 因為是要用負值,所以減去高度
		switch (state) {
		case NONE:
			if (space > 0) {
				state = PULL;
				reflashViewByState();
			}

			break;
		case PULL:
			topPadding(topPadding);
			// 大於heigh+30且在滑動時,則是可以刷新
			if (space > headerHeight + 30
					&& mscrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
				state = RELEASE;
				reflashViewByState();
			}

			break;

		case RELEASE:
			topPadding(topPadding);
			// 為釋放狀態時,則可以回到下拉狀態
			if (space < headerHeight + 30) {
				state = PULL;
				reflashViewByState();
			} else if (space <= 0) {
				state = NONE;
				isRemark = false;
				reflashViewByState();
			}

			break;

		case REFRESHING:

			break;

		default:
			break;
		}
	}

	/**
	 * 改變下拉過程中的header布局中的控件的內容
	 */
	public void reflashViewByState() {
		TextView tip = (TextView) header.findViewById(R.id.tip);
		ImageView arrow = (ImageView) header.findViewById(R.id.arrow);
		ProgressBar progressBar = (ProgressBar) header
				.findViewById(R.id.progress);
		// RotateAnimation旋轉動畫,旋轉的角度,相對與自己,中心位置
		RotateAnimation animation = new RotateAnimation(0, 180,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		animation.setDuration(500);// 時間間隔
		animation.setFillAfter(true);// 保存狀態
		RotateAnimation animation2 = new RotateAnimation(180, 0,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		animation2.setDuration(500);// 時間間隔
		animation2.setFillAfter(true);// 保存狀態
		switch (state) {
		case NONE:
			arrow.clearAnimation();
			topPadding(-headerHeight);
			break;
		case PULL:
			arrow.setVisibility(View.VISIBLE);
			progressBar.setVisibility(GONE);
			arrow.clearAnimation();
			arrow.setAnimation(animation2);
			tip.setText("下拉可以刷新");
			break;
		case RELEASE:
			arrow.setVisibility(View.VISIBLE);
			progressBar.setVisibility(GONE);
			arrow.clearAnimation();
			arrow.setAnimation(animation);
			tip.setText("松開可以刷新");
			break;
		case REFRESHING:
			topPadding(50);
			arrow.clearAnimation();
			arrow.setVisibility(View.GONE);
			progressBar.setVisibility(VISIBLE);
			tip.setText("正在刷新");
			break;

		default:
			break;
		}
	}

	/**
	 * 獲取完數據
	 */
	public void reflashComplete() {
		state = NONE;
		isRemark = false;
		reflashViewByState();
		TextView lastTimeReflash = (TextView) header
				.findViewById(R.id.lastrefresh_time);
		SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
		Date date = new Date(System.currentTimeMillis());
		String timeString = format.format(date);
		lastTimeReflash.setText(timeString);
	}
	
	/**
	 * 底部加載完畢
	 */
	public void reflashFooterComplete() {
		isLoading=false;
		footer.setVisibility(GONE);
	}

	/**
	 * 刷新數據接口
	 * 
	 * @author nickming
	 *
	 */
	public interface OnReflashListener {
		public void onrReflash();
	}

	public OnReflashListener mListener;// 刷新數據的接口

	public void setOnReflashListener(OnReflashListener listener) {
		mListener = listener;
	}
	
	
	/**
	 * 加載更多接口
	 * @author nickming
	 *
	 */
	public interface OnReflashMoreListener{
		public void onReflashMore();
	}
	
	public OnReflashMoreListener mListener2;
	
	public void  setOnReflashMoreListener(OnReflashMoreListener listener) {
		mListener2=listener;
	}

}


 

MainActivity.class

 

package com.example.listview_pulltorefresh;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;

import com.example.listview_pulltorefresh.RefreshListview.OnReflashListener;
import com.example.listview_pulltorefresh.RefreshListview.OnReflashMoreListener;

public class MainActivity extends Activity {
	private RefreshListview mlistview;
	MyAdapter adapter;
	List mdata;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mlistview = (RefreshListview) findViewById(R.id.listview);
		mdata = new ArrayList();
		for (int i = 0; i < 20; i++) {
			DataBean dataBean = new DataBean();
			dataBean.setTextString("數據列:" + i);
			mdata.add(dataBean);
		}
		adapter = new MyAdapter(this, mdata);
		mlistview.setAdapter(adapter);
		mlistview.setOnReflashListener(new OnReflashListener() {

			@Override
			public void onrReflash() {
				// TODO Auto-generated method stub
				// 模擬網絡延時
				Handler mHandler = new Handler();
				mHandler.postDelayed(new Runnable() {

					@Override
					public void run() {
						// TODO Auto-generated method stub
						// 獲取最新數據
						addHeaderData();
						// 通知布局顯示
						adapter.notifyDataSetChanged();
						// listview刷新
						mlistview.reflashComplete();
					}
				}, 3000);

			}
		});
		
		mlistview.setOnReflashMoreListener(new OnReflashMoreListener() {
			
			@Override
			public void onReflashMore() {
				// TODO Auto-generated method stub
				Handler mHandler=new Handler();
				mHandler.postDelayed(new Runnable() {
					
					@Override
					public void run() {
						// TODO Auto-generated method stub
						addFooterData();
						adapter.notifyDataSetChanged();
						mlistview.reflashFooterComplete();
						
					}
				}, 2000);
			}
		});
	}

	public void addHeaderData() {
		for (int i = 0; i < 10; i++) {
			DataBean dataBean = new DataBean();
			String nameString = UUID.randomUUID().toString();
			dataBean.setTextString("最新數據:" + nameString);
			mdata.add(0, dataBean);// 放在最前面
		}
	}
	
	public void addFooterData() {
		for (int i = 0; i < 10; i++) {
			DataBean dataBean = new DataBean();
			String nameString = UUID.randomUUID().toString();
			dataBean.setTextString("最新數據:" + nameString);
			mdata.add( dataBean);// 放在最後面
		}
	}
}

adapter

 

 

package com.example.listview_pulltorefresh;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MyAdapter extends BaseAdapter {

	private Context mcontext;
	private List mData;
	LayoutInflater inflater;

	public MyAdapter(Context context, List mData) {
		super();
		this.mcontext = context;
		this.mData = mData;
		inflater=LayoutInflater.from(context);
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mData.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return mData.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		viewHolder holder=null;
		if (convertView == null) {
			convertView = inflater.inflate(R.layout.listitem, parent,false);
			holder = new viewHolder();
			holder.textView = (TextView) convertView
					.findViewById(R.id.textView1);
			convertView.setTag(holder);

		}else {
			holder=(viewHolder) convertView.getTag();
		}
		holder.textView.setText(mData.get(position).getTextString());

		return convertView;
	}

	class viewHolder {
		TextView textView;
	}

}

DataBean.class

 

 

package com.example.listview_pulltorefresh;

import android.widget.TextView;

public class DataBean {
	
	String textString;
	
	public DataBean() {
		// TODO Auto-generated constructor stub
	}

	public DataBean(String textString) {
		super();
		this.textString = textString;
	}

	public String getTextString() {
		return textString;
	}

	public void setTextString(String textString) {
		this.textString = textString;
	}
	
	 
	
	

}

基本上沒什麼問題了,其實實現還是很簡單的,不過就是要多多練習。

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved