ListView下拉刷新一般要注意以下幾點:
1. listview的頭布局
2. 注意標志的應用,即刷新的幾個狀態,分別是下拉刷新,松開刷新和正在刷新
3. 注意幾個動畫效果,即箭頭旋轉,刷新圖標旋轉等
先上效果圖:
下面,我們來分別介紹。
先來說說這個demo里用到的幾個方法。
(1)public boolean onTouchEvent(MotionEvent ev):這個方法是手勢觸摸事件。這里主要用到了MotionEvent.ACTION_DOWN(手勢按下)、MotionEvent.ACTION_MOVE(手勢滑動)和MotionEvent.ACTION_UP(手指抬起手勢)。
下拉刷新,是先將listview的頭部隱藏,然后用手勢拖動屏幕刷新。那么,listview的頭部如何隱藏呢?這里用的是header.setPadding(0,-headerViewHeight,0,0)來隱藏頭部,這里不細說,等下介紹。如圖1所示,要讓listview的頭部跟着手勢一起向下滑動,則需要記錄手指移動的距離。所以,當MotionEvent.ACTION_DOWN(手勢按下)觸發時,需要一個downY記錄手勢按下時y的偏移值,然后隨着手勢的滑動即MotionEvent.ACTION_MOVE(手勢滑動)觸發時,又需要一個moveY記錄移動的偏移值,然后paddingTop=moveY-downY得到的就是手指滑動的距離。然后用paddingTop-headerViewHeight(相減的值設為x)得到頭部的頂部到屏幕的頂部距離。如果想x>0則說明頭部完全顯示,如果x<0則頭部沒有完全顯示。
這里要設置幾個標志位
PULL_DOWN_REFRESH(下拉刷新):當頭部未完全顯示時為下拉刷新狀態。
RELEASE_REFRESH(釋放刷新):當頭部完全顯示時為釋放刷新狀態。
REFRESHING(正在刷新):當手勢抬起,並頭部完全顯示時為正在刷新。
其他的都比較簡單,在程序里都有注釋,這里就不再贅述了。上代碼:
RefreshListView.java
package com.example.yds.pulldowntest; 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.animation.Animation; import android.view.animation.RotateAnimation; import android.widget.ImageView; import android.widget.ListView; import android.widget.AbsListView; import android.widget.TextView; import org.w3c.dom.Text; /** * Created by yds on 2017/1/10. */ public class RefreshListView extends ListView implements AbsListView.OnScrollListener { //頭布局視圖 private View header; //頭布局高度 private int headerViewHeight; //按下時y的偏移量 private int downY; //移動時y的偏移量 private int moveY; //距離頂部的距離 private int paddingTop; //listview第一個可見的item項 private int firstVisibleItemPosition; //下拉刷新 private final int PULL_DOWN_REFRESH = 0; //釋放刷新 private final int RELEASE_REFRESH = 1; //正在刷新 private final int REFRESHING = 2; //當前狀態,默認為下拉刷新 private int currentState = PULL_DOWN_REFRESH; //刷新列表構造函數 private Context context; //刷新監聽 private OnRefreshListener mOnRefreshListener; private ImageView refresh; private RotateAnimation animation; //圖片向上旋轉 private Animation upAnimation; //圖片向下旋轉 private Animation downAnimation; //箭頭 private ImageView row; //提示文本 private TextView header_tv; public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); //初始化頭布局 initHeaderView(); //滑動監聽 this.setOnScrollListener(this); this.context = context; } /**滾動狀態改變時調用,一般用於列表視圖和網格視圖 * * @param view * @param scrollState 有三種值,分別是SCROLL_STATE_IDLE,SCROLL_STATE_TOUCH_SCROLL,SCROLL_STATE_FLING * SCROLL_STATE_IDLE:當屏幕停止滾動時 * SCROLL_STATE_TOUCH_SCROLL:當屏幕以觸屏方式滾動並且手指還在屏幕上時 * SCROLL_STATE_FLING:當用戶之前滑動屏幕並抬起手指,屏幕以慣性滾動 */ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (scrollState==SCROLL_STATE_IDLE||scrollState == SCROLL_STATE_FLING){ } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { firstVisibleItemPosition = firstVisibleItem; } // public void setOnRefreshListener(OnRefreshListener listener){ // // } public void setOnRefreshListener(OnRefreshListener listener){ mOnRefreshListener = listener; } private void initHeaderView(){ //頭布局文件 header = LayoutInflater.from(getContext()).inflate(R.layout.header,null); //測量頭布局,繪制一個視圖一般經過measure,layout,draw header.measure(0,0); //頭布局高度 headerViewHeight = header.getMeasuredHeight(); //設置間隔 header.setPadding(0,-headerViewHeight,0,0); //加載頭布局 this.addHeaderView(header); refresh = (ImageView) header.findViewById(R.id.refresh); row = (ImageView) header.findViewById(R.id.row); header_tv = (TextView) header.findViewById(R.id.header_tv); initAnimation(); } private void initAnimation(){ animation = new RotateAnimation(0f,360f, Animation.RELATIVE_TO_SELF,0.48f,Animation.RELATIVE_TO_SELF,0.47f); animation.setDuration(500); animation.setRepeatCount(5); upAnimation = new RotateAnimation(0f,180f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f); upAnimation.setDuration(300); upAnimation.setFillAfter(true); downAnimation = new RotateAnimation(180f,360f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f); downAnimation.setDuration(300); downAnimation.setFillAfter(true); // refresh.setAnimation(animation); } /** * 觸摸事件 * @param ev * @return */ @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()){ //手指按下 case MotionEvent.ACTION_DOWN: //記錄按下時y的偏移量 downY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE://手指滑動 //記錄移動時的y值偏移 moveY = (int) ev.getY(); //可以看成頭布局距離屏幕頂部的距離,這里除以2是控制手指滑動 paddingTop = (moveY - downY)/2-headerViewHeight; if(firstVisibleItemPosition==0&&-headerViewHeight<paddingTop){//必須的條件 //如果paddingTop>0就說明完全顯示了,但還要判斷當前狀態是否是下拉刷新狀態,因為正在刷新狀態也是完全顯示 if(paddingTop>0&¤tState == PULL_DOWN_REFRESH){//完全顯示 header_tv.setText("松開刷新"); //將當前狀態置為釋放刷新 currentState = RELEASE_REFRESH; changeHeaderByViewState(); }else if(paddingTop<0&¤tState == RELEASE_REFRESH){//沒有完全顯示,currentState=RELEASE_REFRESH原因是可以先滑到完全顯示后再往上滑到不完全顯示 currentState = PULL_DOWN_REFRESH; header_tv.setText("下拉刷新"); changeHeaderByViewState(); } header.setPadding(0,paddingTop,0,0); } break; case MotionEvent.ACTION_UP: if(currentState == RELEASE_REFRESH){//完全顯示 header.setPadding(0,0,0,0); currentState = REFRESHING; changeHeaderByViewState(); if (mOnRefreshListener!=null){ mOnRefreshListener.downPullRefresh(); } }else if(currentState == PULL_DOWN_REFRESH){//未完全顯示 //當手指松開時,若頭部未完全顯示則隱藏頭部 header.setPadding(0,-headerViewHeight,0,0); } break; } return super.onTouchEvent(ev); } private void changeHeaderByViewState(){ switch (currentState){ case PULL_DOWN_REFRESH: row.startAnimation(downAnimation); break; case RELEASE_REFRESH: row.startAnimation(upAnimation); break; case REFRESHING: row.clearAnimation(); row.setVisibility(View.GONE); header_tv.setText("正在刷新"); refresh.clearAnimation(); refresh.setVisibility(View.VISIBLE); refresh.startAnimation(animation); break; } } public void hideHeaderView(){ header.setPadding(0,-headerViewHeight,0,0); refresh.setVisibility(View.GONE); currentState = PULL_DOWN_REFRESH; header_tv.setText("下拉刷新"); row.setVisibility(View.VISIBLE); } }
MainActivity.java
package com.example.yds.pulldowntest; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.widget.TextView; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MainActivity extends Activity implements OnRefreshListener{ private TextView log_tv; private RefreshListView listView; private PullDownAdapter adapter; private Map<String,Object>map; List<Map<String,Object>>list = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); log_tv = (TextView) findViewById(R.id.log_tv); listView = (RefreshListView) findViewById(R.id.listview); for (int i = 0 ;i < 5 ; i++){ map = new HashMap<>(); map.put("name","this "+i); list.add(map); } adapter = new PullDownAdapter(this,list); listView.setOnRefreshListener(this); listView.setAdapter(adapter); log_tv.setText(list.get(0).get("name").toString()+"this is null?"+list.get(1).get("name").toString()); } @Override public void downPullRefresh() { new AsyncTask<Void,Void,Void>(){ @Override protected Void doInBackground(Void... params) { SystemClock.sleep(2800); map = list.get(0); map.put("name","這是刷新后的數據"); list.add(map); return null; } @Override protected void onPostExecute(Void result) { super.onPostExecute(result); adapter.notifyDataSetChanged(); listView.hideHeaderView(); } }.execute(new Void[]{}); } }
源碼下載地址:
http://download.csdn.net/detail/u013293125/9734831