編輯:關於Android編程
我們在使用ListView的時候,很多情況下需要用到下拉刷新的功能。為了了解下拉刷新的底層實現原理,我采用自定義ListView控件的方式來實現效果。
實現的基本原理是:自定義ListView,給ListView加載頭布局,然後動態的控制頭布局的現實與隱藏。ListView初始化的時候,頭布局是隱藏的,當手指往下拉的時候,根據手指移動的距離與頭布局的高度的關系來控制頭布局的顯示。具體的控制思路詳見後邊的代碼,代碼中的注釋很詳細。先來看一下效果圖:

頭布局的實現代碼如下:
接著定義一個RefreshListView,繼承自ListView,重寫它的三個構造方法,在RefreshlistView初始化的時候,加載一個頭布局,這個頭布局默認是隱藏的。
// 初始化頭布局
private void initHeaderView() {
// 給當前的ListView添加下拉刷新的頭布局
mHeaderView = View.inflate(getContext(), R.layout.list_refresh_header,
null);
tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
// 下拉箭頭
ivArror = (ImageView) mHeaderView.findViewById(R.id.iv_arror);
// 進度條
pb = (ProgressBar) mHeaderView.findViewById(R.id.pb_list);
this.addHeaderView(mHeaderView);
// 初始化這個下拉刷新的ListView的時候,縣隱藏掉下拉刷新的頭布局,然後通過代碼動態的控制頭布局的顯示與隱藏
// 隱藏頭布局
// 先測量一把頭布局
mHeaderView.measure(0, 0);
// 獲得測量得到的高度
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
// 設置paddingtop為負高度,隱藏頭布局
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
// 初始化完成布局,初始化兩個動畫效果
initAnimation();
// 設置當前時間
tvTime.setText("最後刷新時間:" + getCurrentTime());
}
當手指觸摸屏幕時,觸發OnTouchEvent事件,根據手指在Y軸方向上的移動偏移量來動態的控制頭布局的顯示與隱藏。並即時更新下拉框的顯示的狀態。具體的代碼如下:
/**
* 下拉屏幕的時候,將頭布局展示出來,重寫一下ListView的觸摸屏幕的事件
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 手指按下的時候獲得當前屏幕的Y坐標
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
// 手指移動的時候,獲得當前屏幕的Y坐標,與開始的Y坐標做比較
if (startY == -1) {
// 確保startY有效
startY = (int) ev.getRawY();
}
int endY = (int) ev.getRawY();
// 屏幕Y方向移動的距離
int dy = endY - startY;
// 只有屏幕向下滑,也就是dy>0,並且當前的ListView顯示的是第一個條目,那個隱藏的下拉刷新的頭布局才慢慢的隨手指滑出來
if (dy > 0 && this.getFirstVisiblePosition() == 0) {
// 允許下拉刷新框出來
// 下拉刷新框出來其實就是給頭布局設置padding,首先根據手指移動的距離計算一下padding
int padding = dy - mHeaderViewHeight;//
mHeaderView.setPadding(0, padding, 0, 0);
// 更新刷新框的狀態
// 一共有三種狀態,下拉刷新、正在刷新、松開刷新
// 定義這三種狀態
// 如果padding大於0說明下拉刷新的框已經全部拉出來了,將狀態改為松開刷新
if (padding > 0 && mCurrentState != STATE_RELEASE_REFRESH) {
// 狀態改為松開刷新,將下拉框顯示的狀態更新一下
mCurrentState = STATE_RELEASE_REFRESH;
// 更新當前下拉框顯示的狀態
updateState();
}
if (padding < 0 && mCurrentState != STATE_PULL_REFRESH) {
// 狀態改為下拉刷新
mCurrentState = STATE_PULL_REFRESH;
updateState();
}
}
break;
case MotionEvent.ACTION_UP:
// 手指抬起來的時候重置startY。將狀態改為正在刷新
startY = -1;
if (mCurrentState == STATE_RELEASE_REFRESH) {
// 如果當前為松開刷新,則手指一抬起來就將狀態改為正在
mCurrentState = STATE_REFRESHING;
// 頭布局的padding設置為0000
mHeaderView.setPadding(0, 0, 0, 0);
updateState();
} else {
// 沒有完全拉出來,就將頭布局隱藏
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
}
break;
}
return super.onTouchEvent(ev);
}
/**
* 更新當前下拉框顯示的狀態
*/
private void updateState() {
// 判斷當前狀態是什麼,根據當前狀態更新下拉框顯示
switch (mCurrentState) {
case STATE_PULL_REFRESH:
// 下拉刷新
tvTitle.setText("下拉刷新");
ivArror.setVisibility(View.VISIBLE);
pb.setVisibility(View.INVISIBLE);
// 給箭頭設置動畫
ivArror.startAnimation(animDown);
break;
case STATE_REFRESHING:
// 正在刷新
tvTitle.setText("正在刷新...");
ivArror.clearAnimation();// 必須先清除動畫,才能隱藏
ivArror.setVisibility(View.INVISIBLE);
pb.setVisibility(View.VISIBLE);
// 正在刷新的時候調用接口中的方法
if (mListener != null) {
// 正在刷新
mListener.onRefresh();
}
break;
case STATE_RELEASE_REFRESH:
// 松開刷新
tvTitle.setText("松開刷新");
ivArror.setVisibility(View.VISIBLE);
pb.setVisibility(View.INVISIBLE);
ivArror.startAnimation(animUp);
break;
}
}
為了監聽下拉刷新的動作,自定義一個監聽接口,當正在刷新的時候執行onRefresh方法。對外提供一個設置監聽的方法,監聽器由子類實現,具體的正在刷新執行的邏輯由子類在onRefresh中實現。
// 下拉刷新邏輯的實現方式:給當前的ListView設置下拉刷新的監聽器,監聽器的本質就是一個接口
/**
* 下拉刷新的監聽器
*
* @author ZHY
*
*/
public interface onRefreshListener {
// 刷新的時候執行的方法,誰實現這個接口。誰執行此方法
public void onRefresh();
}
onRefreshListener mListener;
// 有了監聽器之後,提供一個設置監聽的方法
public void setOnRefreshListener(onRefreshListener listener) {
// 這個Listneer是從子類中闖過來的,是子類定義的監聽
mListener = listener;
}
刷新完成之後,改變下拉刷新的狀態,並且隱藏下拉框
// 刷新完成的時候,將下拉框隱藏
/**
* 調用服務器的數據刷新,刷新完成之後調用的方法 加載完成之後的回調
*
* @param isSuccess
*/
public void onRefreshCompleted(boolean isSuccess) {
// 將狀態改成下拉刷新,然後隱藏下拉框
mCurrentState = STATE_PULL_REFRESH;
tvTitle.setText("下拉刷新");
ivArror.setVisibility(View.VISIBLE);
pb.setVisibility(View.INVISIBLE);
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隱藏
// 如果刷新成功,則更新最後一次刷新時間,否則不更新時間
if (isSuccess) {
tvTime.setText("最後刷新時間:" + getCurrentTime());
}
}
這一部分工作做完之後,一個可以實現下拉刷新功能的ListView就定義好了。在MainActivity中就可以直接使用了
Android中使用ListView實現漂亮的表格效果
在這裡我們要使用Android ListView來實現顯示股票行情,效果圖如下,紅色表示股票價格上漲,綠色表示股票價格下跌。第一步、定義color.xml如下:復制代碼
Android實踐--Android Http 客戶端編程之GET
Android Http 客戶端編程之GET 說起Http編程,不盡然想起GET和POST兩種請求方式,本文以簡潔明了的的步驟和說明,將Android中常用
.Net程序員玩轉Android開發---(17)Handler用法
在android開發中,如果在一個線程中想更新主界面中控件顯示的數據,直接給主界面控件賦值就會出現異常,android中為了安全起見,是不允許在線程中更新界面控件的數據,
Android中自定義MultipartEntity實現文件上傳以及使用Volley庫實現文件上傳
最近在參加CSDN博客之星,希望大家給投一票,謝謝啦~ 點這裡投我一票吧~前言 在開發當中,我們常常需要實現文件上傳,比較常