Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android學習(45) -- 自定義控件(9) 下拉刷新 (添加footer)

Android學習(45) -- 自定義控件(9) 下拉刷新 (添加footer)

編輯:關於Android編程

樣式效果

\

 

1、創建底部的布局layout_footer.xml

 




    

    


 

2、在自定義的ListView中 初始化話FooterView ,並添加到ListView的底部

 

 

	/**
	 * 初始化FooterView
	 */
	private void initFooterView() {
		footerView = View.inflate(getContext(), R.layout.layout_footer, null);
		
		//獲取自定義組件的寬 高
		footerView.measure(0, 0);
		footerViewHeight = footerView.getMeasuredHeight();
		//將頭部進行隱藏
		footerView.setPadding(0, -footerViewHeight, 0, 0);
		//將FooterView添加到ListView的底部
		addFooterView(footerView);
	}

 

3、讓自定義View,並實現OnScrollListener並重寫 ,在初始化方法中調用監聽器

 

 

	private void init(){
		
		setOnScrollListener(this);
                .....
       }

 

 

定義一個boolean類型,用於判斷是否 加載更多

private boolean isLoadingMore = false; //當前是否正在處於加載更多

 

	/**
	 * scrollState的值:
	 * 0 = SCROLL_STATE_IDLE: 閒置狀態,就是手指松開
	 * 1 = SCROLL_STATE_TOUCH_SCROLL:   手指觸摸滑動,就是按著來滑動
	 * 2 = SCROLL_STATE_FLING:  快速滑動後松開
	 */
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//Log.e("main", scrollState + "");
		//當手指松開 並且 此時是ListView中的item是最後一條的時候    顯示FooterView
		//getCount獲取的是ListView的總的條數
		if(scrollState == OnScrollListener.SCROLL_STATE_IDLE
				&& getLastVisiblePosition() == (getCount() -1 )
				&& !isLoadingMore ){
			isLoadingMore = true;
			
			footerView.setPadding(0, 0, 0, 0);
			//將列表移動到指定的Position處
			setSelection(getCount());
			
			//如果監聽不為空  則調用加載更多方法
			if(listener!=null){
				listener.onLoadingMore();
			}
			
		}
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
	}

 

 


4、在接口中添加一個加載更多的方法

 

 

	public interface OnRefreshListener{
		//下來刷新的時候調用
		void onPullRefresh();
		
		//加載更多
		void onLoadingMore();
	}


 

5、在MainActivity中重寫 --加載更多方法

 

private void initData() {
		。。。。。

		refLv.setOnRefreshListener(new OnRefreshListener() {
			
			public void onPullRefresh() {
				//Log.e("MainActivity", "進入正在刷新狀態,此時應請求服務器數據");
				//需要聯網請求服務器數據,然後更新UI
				requestDataFromServer(false);
			}

			@Override
			public void onLoadingMore() {
				requestDataFromServer(true);
			}
		});
	}

	/**
	 * 模擬向服務器請求數據
	 * @param isLoadingMore  用於區分 是加載更多數據  還是下拉刷新
	 */
	private void requestDataFromServer(final boolean isLoadingMore){
		new Thread(){
			public void run() {
				//模擬請求服務的一個時間長度
				SystemClock.sleep(3000);
				
				//將數據添加到頭部
				if(isLoadingMore){
					list.add("加載更多的數據-1");
					list.add("加載更多的數據-2");
					list.add("加載更多的數據-3");
				}else {
					list.add(0, "下拉刷新的數據");
				}
				
				//更新UI
				handler.sendEmptyMessage(0);
			};
		}.start();
	}
	

 

 

6、修改下 自定View中的 completeRefresh(),重置footerView狀態

/**
	 * 完成刷新 重置為下拉刷新狀態
	 * 在請求完數據 更新Adapter之後  在UI線程中調用該方法
	 */
	public void completeRefresh(){
		
		
		if(isLoadingMore){
			//重置FooterView狀態
			footerView.setPadding(0, -footerViewHeight, 0, 0);
			isLoadingMore = false;
		}else{ 
			//HeaderView狀態
			//隱藏HeaderView
			headerView.setPadding(0, -headerViewHeight, 0, 0);
			//狀態改變
			currentState = PULL_REFRESH;
			//ProgressBar隱藏
			pb_rotate.setVisibility(View.INVISIBLE);
			//圖片顯示
			iv_arrow.setVisibility(View.VISIBLE);
			tv_state.setText("下拉刷新");
			tv_time.setText("最後刷新: " + getCurrentTime());
		
		}
	}

 

 

總的代碼

自定義View

 

public class RefreshListView extends ListView implements OnScrollListener {

	private View headerView;		//HeaderView
	private int headerViewHeight;	//HeaderViewHeight
	private View footerView;		// footerView
	private int footerViewHeight;	// footerViewHeight
	
	private int downY ;	//按下時 的 Y坐標點  

	private final int PULL_REFRESH = 0;			//下拉刷新的狀態
	private final int RELEASE_REFRESH = 1;		//松開刷新的狀態
	private final int REFRESHING = 2;			//正在刷新的狀態
	private int currentState = PULL_REFRESH;
	private ImageView iv_arrow;
	private ProgressBar pb_rotate;
	private TextView tv_state;
	private TextView tv_time;

	private boolean  isLoadingMore = false;	//當前是否正在處於加載更多

	//旋轉動畫
	private RotateAnimation  upAnimation, downAnimation; 
	
	public RefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	
	public RefreshListView(Context context) {
		super(context);
		init();
	}
	
	/**
	 * 初始化ListView中的數據
	 */
	private void init(){
		
		setOnScrollListener(this);
		
		//初始化HeaderView
		initHeaderView();
		//初始化動畫
		initRotateAnimation();
		//初始化FooterView
		initFooterView();
	}



	/**
	 * 初始化動畫
	 */
	private void initRotateAnimation() {
		
		//向上的動畫
		upAnimation = new RotateAnimation(0, -180, 
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		upAnimation.setDuration(300);
		upAnimation.setFillAfter(true);
		
		//向下的動畫
		downAnimation = new RotateAnimation( -180, -360,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f,
				RotateAnimation.RELATIVE_TO_SELF, 0.5f);
		downAnimation.setDuration(300);
		downAnimation.setFillAfter(true);
	}

	/**
	 * 添加一個HeaderView
	 */
	private void initHeaderView() {
		//獲取頭部的布局
		headerView = View.inflate(getContext(),
						R.layout.layout_header, null);
		
		iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);
		pb_rotate = (ProgressBar) headerView.findViewById(R.id.pb_rotate);
		
		tv_state = (TextView) headerView.findViewById(R.id.tv_state);
		tv_time = (TextView) headerView.findViewById(R.id.tv_time);
		
		//獲取自定義組件的寬 高
		headerView.measure(0, 0);
		headerViewHeight = headerView.getMeasuredHeight();
		//將頭部進行隱藏
		headerView.setPadding(0, -headerViewHeight, 0, 0);
		//將頭部添加到RefreshListView中
		addHeaderView(headerView);
	}
	
	/**
	 * 初始化FooterView
	 */
	private void initFooterView() {
		footerView = View.inflate(getContext(), R.layout.layout_footer, null);
		
		//獲取自定義組件的寬 高
		footerView.measure(0, 0);
		footerViewHeight = footerView.getMeasuredHeight();
		//將頭部進行隱藏
		footerView.setPadding(0, -footerViewHeight, 0, 0);
		//將FooterView添加到ListView的底部
		addFooterView(footerView);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			downY = (int) ev.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			//如果在刷新中的話 就不讓操作了
			if(currentState == REFRESHING){
				break;
			}
			
			//獲取到移動的大小
			int delaY = (int)(ev.getY() - downY) ;
			//計算出新的headerViewHeight
			int paddingTop = -headerViewHeight + delaY;

			if(paddingTop > -headerViewHeight 
					&& getFirstVisiblePosition() ==  0){
				headerView.setPadding(0, paddingTop, 0, 0);
				
				if(paddingTop >= 0  
						&¤tState == PULL_REFRESH){
					//下拉刷新狀態 進入松開刷新狀態
					currentState = RELEASE_REFRESH;
					refreshHeaderView();
					
				}else if(paddingTop < 0
						&& currentState == RELEASE_REFRESH){
					//松開刷新狀態 進入下拉刷新狀態
					currentState = PULL_REFRESH;
					refreshHeaderView();
				}
				
				//攔截TouchMove,不讓listview處理該次move事件,會造成listview無法滑動
				return true;
			}
			
			break;
		case MotionEvent.ACTION_UP:
			if(currentState == PULL_REFRESH){
				//隱藏HeaderView
				headerView.setPadding(0, -headerViewHeight, 0, 0);
			}else if(currentState == RELEASE_REFRESH){
				headerView.setPadding(0, 0, 0, 0);
				currentState = REFRESHING;
				refreshHeaderView();
				
				//模擬延時
//				new Handler().postDelayed(new Runnable() {
//					
//					@Override
//					public void run() {
//						completeRefresh();
//					}
//				}, 3000);
				
				if(listener != null){
					listener.onPullRefresh();
				}
			}
			
			break;
		}
		
		return super.onTouchEvent(ev);
	}
	
	/**
	 * 根據  currentState 來更新 HeaderView
	 */
	private void refreshHeaderView(){
		switch (currentState) {
		case PULL_REFRESH: //下拉刷新的狀態
			tv_state.setText("下拉刷新");
			iv_arrow.startAnimation(downAnimation);
			break;
		case RELEASE_REFRESH: //松開刷新的狀態
			tv_state.setText("松開刷新");
			iv_arrow.startAnimation(upAnimation);
			break;
		case REFRESHING://正在刷新的狀態
			//清除動畫  可能動畫未執行完畢  所以需要清除動畫
			iv_arrow.clearAnimation();
			//讓圖標隱藏
			iv_arrow.setVisibility(View.INVISIBLE);
			//ProgressBar 顯示可見
			pb_rotate.setVisibility(View.VISIBLE);
			tv_state.setText("正在刷新...");
			
			break;
		}
	}
	
	/**
	 * 完成刷新 重置為下拉刷新狀態
	 * 在請求完數據 更新Adapter之後  在UI線程中調用該方法
	 */
	public void completeRefresh(){
		
		
		if(isLoadingMore){
			//重置FooterView狀態
			footerView.setPadding(0, -footerViewHeight, 0, 0);
			isLoadingMore = false;
		}else{ 
			//HeaderView狀態
			//隱藏HeaderView
			headerView.setPadding(0, -headerViewHeight, 0, 0);
			//狀態改變
			currentState = PULL_REFRESH;
			//ProgressBar隱藏
			pb_rotate.setVisibility(View.INVISIBLE);
			//圖片顯示
			iv_arrow.setVisibility(View.VISIBLE);
			tv_state.setText("下拉刷新");
			tv_time.setText("最後刷新: " + getCurrentTime());
		
		}
	}
	/**
	 * 獲取當前時間
	 * @return
	 */
	private String getCurrentTime(){
		SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
		return format.format(new Date());
	}
	
	/**
	 * 定義刷新監聽接口,用於處理刷新過程中業務邏輯請求的處理
	 * @author Denny
	 * @date 2016-4-26
	 */
	public interface OnRefreshListener{
		//下來刷新的時候調用
		void onPullRefresh();
		
		//加載更多
		void onLoadingMore();
	}
	
	private OnRefreshListener  listener;

	
	public 	void setOnRefreshListener( OnRefreshListener listener){
		this.listener = listener;
	}

	/**
	 * scrollState的值:
	 * 0 = SCROLL_STATE_IDLE: 閒置狀態,就是手指松開
	 * 1 = SCROLL_STATE_TOUCH_SCROLL:   手指觸摸滑動,就是按著來滑動
	 * 2 = SCROLL_STATE_FLING:  快速滑動後松開
	 */
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		//Log.e("main", scrollState + "");
		//當手指松開 並且 此時是ListView中的item是最後一條的時候    顯示FooterView
		//getCount獲取的是ListView的總的條數
		if(scrollState == OnScrollListener.SCROLL_STATE_IDLE
				&& getLastVisiblePosition() == (getCount() -1 )
				&& !isLoadingMore ){
			isLoadingMore = true;
			
			footerView.setPadding(0, 0, 0, 0);
			//將列表移動到指定的Position處
			setSelection(getCount());
			
			//如果監聽不為空  則調用加載更多方法
			if(listener!=null){
				listener.onLoadingMore();
			}
			
		}
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
	}
}


 

 

 

MainActivity

 

 

public class MainActivity extends Activity {

	private RefreshListView refLv;
	private ArrayList list = new ArrayList();
	private MyAdapter myAdapter;

	private Handler handler = new Handler(){
		 public void handleMessage(android.os.Message msg) {
			 //更新UI
			 myAdapter.notifyDataSetChanged();

			//重置狀態
			refLv.completeRefresh();
		 };
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		initView();

		initData();

	}

	/**
	 * 初始化View
	 */
	private void initView() {
		setContentView(R.layout.activity_main);
		refLv = (RefreshListView) findViewById(R.id.refLv);
	}

	/**
	 * 初始化數據
	 */
	private void initData() {
		for (int i = 0; i < 15; i++) {
			list.add("ListView原來數據 :" + i);
		}

		//獲取頭部的布局
//		final View headerView = View.inflate(MainActivity.this,
//				R.layout.layout_header, null);
		//1、第一種   獲取自動加載View的高度的方式  使用監聽的方式 
//		//使用inflate是異步的  要想獲取到加載組件的高度 需要使用 getViewTreeObserver 進行監聽
//		headerView.getViewTreeObserver().addOnGlobalLayoutListener(
//				new OnGlobalLayoutListener() {
//			
//			@Override
//			public void onGlobalLayout() {
//				
//				//要先remove掉一下
//				headerView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
//				
//				//獲取頭部布局的高度
//				int headerViewHeight = headerView.getHeight();
//				//將頭部進行隱藏
//				headerView.setPadding(0, -headerViewHeight, 0, 0);
//				refLv.addHeaderView(headerView);
//			}
//		});
		
		//  第 一種   獲取動態 自定義組件的寬 高 
//		headerView.measure(0, 0); //自動的通知系統獲取高度和寬度
//		int headerViewHeight = headerView.getMeasuredHeight();
//		//將頭部進行隱藏
//		headerView.setPadding(0, -headerViewHeight, 0, 0);
//		refLv.addHeaderView(headerView);
		
		myAdapter = new MyAdapter();
		refLv.setAdapter(myAdapter);

		refLv.setOnRefreshListener(new OnRefreshListener() {
			
			public void onPullRefresh() {
				//Log.e("MainActivity", "進入正在刷新狀態,此時應請求服務器數據");
				//需要聯網請求服務器數據,然後更新UI
				requestDataFromServer(false);
			}

			@Override
			public void onLoadingMore() {
				requestDataFromServer(true);
			}
		});
	}

	/**
	 * 模擬向服務器請求數據
	 * @param isLoadingMore  用於區分 是加載更多數據  還是下拉刷新
	 */
	private void requestDataFromServer(final boolean isLoadingMore){
		new Thread(){
			public void run() {
				//模擬請求服務的一個時間長度
				SystemClock.sleep(3000);
				
				//將數據添加到頭部
				if(isLoadingMore){
					list.add("加載更多的數據-1");
					list.add("加載更多的數據-2");
					list.add("加載更多的數據-3");
				}else {
					list.add(0, "下拉刷新的數據");
				}
				
				//更新UI
				handler.sendEmptyMessage(0);
			};
		}.start();
	}
	
	
	class MyAdapter extends BaseAdapter {

		@Override
		public int getCount() {
			return list.size();
		}

		@Override
		public Object getItem(int position) {
			return null;
		}

		@Override
		public long getItemId(int position) {
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			TextView tv = new TextView(MainActivity.this);
			tv.setPadding(20, 20, 20, 20);
			tv.setTextSize(18);

			tv.setText(list.get(position));

			return tv;
		}

	}

}

 

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