亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

android 有阻尼下拉刷新列表的實(shí)現(xiàn)方法

 更新時間:2018年01月20日 12:45:11   作者:GuityCrown  
下面小編就為大家分享一篇android 有阻尼下拉刷新列表的實(shí)現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助,一起跟隨小編過來看看吧

本文將會介紹有阻尼下拉刷新列表的實(shí)現(xiàn),先來看看效果預(yù)覽:

這是下拉狀態(tài):

這是下拉松開手指后listView回滾到刷新狀態(tài)時的樣子:

1. 如何調(diào)用

雖然效果圖看起來樣子不太好看,主要是因?yàn)槟莻€藍(lán)色的背景對不對,沒關(guān)系,這只是一個背景而已,在了解了我們這個下拉刷新列表的實(shí)現(xiàn)之后,你就可以很輕松地修改這個背景,從而實(shí)現(xiàn)你想要的UI效果!話不多說,下面我們先來講講這個下拉刷新列表是如何使用的,這也是我們編寫代碼所要實(shí)現(xiàn)的目標(biāo)。

    final PullToRefreshListView eListView = (PullToRefreshListView) rootView.findViewById(R.id.profile_listView);
    eListView.setOnLoadCallBack(new PullToRefreshListView.OnLoadCallBack() {
      @Override
      public int whereToLoad() {
        return PullToRefreshListView.DEFAULT_WHERE_TO_LOAD;
      }
      @Override
      public void onLoad() {
        eListView.postDelayed(new Runnable() {
          @Override
          public void run() {
            eListView.setLoadingFinish();
          }
        }, 5000);
      }
      @Override
      public void cancelLoad() {
      }
      @Override
      public Drawable refreshDrawable() {
        return new ColorDrawable(Color.CYAN);
      }
    });
    eListView.setAdapter(new BaseAdapter() {
      @Override
      public int getCount() {
        return 30;
      }
      @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;
        if (convertView == null) {
          tv = new TextView(getActivity());
          tv.setGravity(Gravity.CENTER_VERTICAL);
          tv.setHeight(200);
          tv.setBackgroundColor(Color.WHITE);
        } else {
          tv = (TextView) convertView;
        }
        tv.setText(position+"");
        return tv;
      }
    });

在上述代碼中,我們可以看到PullToRefreshListView的使用在adapter上跟ListView是一樣的,這個當(dāng)然,因?yàn)槲覀儗?shí)現(xiàn)下拉刷新功能并不需要修改數(shù)據(jù)適配器。我們也看到,PullToRefreshListView的實(shí)例需要設(shè)置一個OnLoadCallBack回調(diào),該回調(diào)需要實(shí)現(xiàn)4個方法,包括:

  /**
   * 下拉刷新的回調(diào)
   */
  public interface OnLoadCallBack {
    /**
     * 下拉結(jié)束后將listView定位到哪個位置等待刷新完成
     * @return listView的定位y坐標(biāo)值,in dp
     */
    int whereToLoad();
    /**
     * 下拉結(jié)束后進(jìn)行刷新的回調(diào)
     */
    void onLoad();
    /**
     * 取消刷新
     */
    void cancelLoad();
    /**
     * 下拉刷新的背景
     * @return 背景drawable
     */
    Drawable refreshDrawable();
  }

whereToLoad方法告知PullToRefreshListView對象下拉刷新時停留在哪個位置,具體點(diǎn)說,也就是上述第二章效果圖中藍(lán)色背景的高度。onLoad方法是下拉刷新的回調(diào),調(diào)用者可以在這里實(shí)現(xiàn)刷新動作。cancelLoad方法是取消刷新動作的回調(diào),調(diào)用者需要在這里將刷新動作取消。

根據(jù)上述方法,我們可以猜測,在onLoad方法中執(zhí)行的應(yīng)該是一個線程或者AsyncTask,而在cancelLoad方法中要做的就是將這個線程或者AsyncTask取消掉。最后還有一個refreshDrawable方法,這個方法是為修改listView的背景而提供給調(diào)用者的,調(diào)用者可以返回任意一個喜歡的背景Drawable。

知道如何調(diào)用以后,我們就要一步一步地實(shí)現(xiàn)這個PullToRefreshListView了。

2. 在dispatchDraw中重畫子View實(shí)現(xiàn)下拉視覺

PullToRefreshListView實(shí)現(xiàn)的關(guān)鍵在于重畫該listVIew的子View。重畫ViewGroup的子View一般是在dispatchDraw方法中實(shí)現(xiàn)的。因此,我們的PullToRefreshListView繼承自ListView類,重載其dispatchDraw方法。

  @Override
  protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    if (distanceY > 0) {
      if (refreshDrawable == null) {
        refreshDrawable = onLoadCallBack.refreshDrawable();
      }
      if (refreshDrawable == null) {
        canvas.drawColor(Color.GRAY);
      } else {
        int left = getPaddingLeft();
        int top = getPaddingTop();
        refreshDrawable.setBounds(left, top, getWidth()+left, getHeight()+top);
        refreshDrawable.draw(canvas);
      }
      canvas.save();
      canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);
      for (int i=0;i<getChildCount();i++) {
        View child = getChildAt(i);
        drawChild(canvas, child, getDrawingTime());
      }
      canvas.restore();
    }
  }

重畫子View的關(guān)鍵在于這一句代碼:

canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY); 

在重畫子View之前,我們需要先將canvas向上移動distanceY距離。這是為什么呢?我們先來看看在canvas畫子View的方法

drawChild方法的文檔是怎么說的。

protected boolean drawChild (Canvas canvas, View child, long drawingTime)

Added in API level 1 Draw one child of this View Group. This method is responsible for getting the canvas in the right state. This includes clipping, translating so that the child's scrolled origin is at 0, 0, and applying any animation transformations.

Parameters canvas The canvas on which to draw the child child Who to draw drawingTime The time at which draw is occurring Returns True if an invalidate() was issued

我來翻譯一下,drawChild方法可以畫出這個View Group的一個子View。該方法需要使canvas處于一個正確的狀態(tài),該狀態(tài)就

是通過對canvas進(jìn)行clip裁剪,translate評議操作等以使得該子View位于canvas的(0,0)位置。

什么意思呢?簡單來說就是,drawChild方法會將child view畫在canvas的(0,0)位置,因此為了使得該child view位于

canvas的正確位置,我們需要在重畫之前對canvas進(jìn)行裁剪平移等操作。舉個例子,有一個canvas和一個child view,本來

child view要畫在(0,0)位置上,于是呈現(xiàn)在我們眼前的child view就是位于canvas的頂部,但是如果在畫之前我們將

canvas向上移動100個像素單位,然后再將child view畫在(0,0)位置上,那么呈現(xiàn)在我們眼前的child view的位置將會是

位于canvas的(0,100)位置上。

根據(jù)以上分析,我們可以知道,重畫子View的原理就是:

當(dāng)PullToRefreshListView已經(jīng)滾動到頂部的時候,通過監(jiān)控滑動手勢來計算distanceY,從而確定要將canvas向上移動多少再重畫子View,就可以實(shí)現(xiàn)PullToRefreshListView跟隨滑動手勢進(jìn)行下拉的功能了。

3. 計算下拉距離

實(shí)現(xiàn)了重畫以后,我們需要做的就是如何計算distanceY。我們的初步想法是,根據(jù)滑動的距離來計算,考慮到我們要實(shí)現(xiàn)阻尼效果,即隨著滑動距離的變長,PullToRefreshListView的下拉距離會越來越短。在PullToRefreshListView實(shí)現(xiàn)中,我使用指數(shù)函數(shù)來實(shí)現(xiàn)這一阻尼效果,具體計算如下:

distanceY = ev.getY() - pullStartY; 
distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY); 

我們知道負(fù)指數(shù)是加速度隨距離變小的單調(diào)遞增函數(shù),我使用手指滑動距離計算負(fù)指數(shù)作為PullToRefreshListView的滑動距離的參考標(biāo)準(zhǔn),便可以實(shí)現(xiàn)有阻尼下拉效果。

4. 監(jiān)控手勢判斷ListView是否進(jìn)入下拉狀態(tài)并更新distanceY

更進(jìn)一步,我們要實(shí)現(xiàn)的就是對手勢的監(jiān)控,在PullToRefreshListView中,我們在onTouchEvent方法中進(jìn)行處理。

@Override 
public boolean onTouchEvent(MotionEvent ev) { 
  if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 
    // 按下的時候 
    lastAction = MotionEvent.ACTION_DOWN; 
    cancelAnimating(); 
    L.d(TAG, "touch down"); 
  } else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) { 
    // 放開手指,開始回滾 
    isPulling = false; 
    lastAction = -1; 
    startAnimating(); 
    L.d(TAG, "touch up"); 
  } else if (lastAction == MotionEvent.ACTION_DOWN) { 
    if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { 
      // 在按下手指的基礎(chǔ)上,開始滑動 
      if (isTop && !isPulling) { 
        // listView在頂部而且不處于下拉刷新狀態(tài),開始下拉 
        pullStartY = ev.getY(); 
        lastAction = MotionEvent.ACTION_MOVE; 
        isPulling = true; 
      } 
    } 
  } else if (lastAction == MotionEvent.ACTION_MOVE) { 
    if (isTop) { 
      // 下拉 
      distanceY = ev.getY() - pullStartY; 
      L.d(TAG, distanceY + ""); 
      if (distanceY > 0) { 
        distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY); 
        // 在下拉狀態(tài)時取消系統(tǒng)對move動作的響應(yīng),完全由本類響應(yīng) 
        ev.setAction(MotionEvent.ACTION_DOWN); 
      } else { 
        distanceY = 0; 
        // 在下拉過程中往上拉動該listView使得其回到頂部位置,則將該move動作交由系統(tǒng)進(jìn)行響應(yīng) 
        ev.setAction(MotionEvent.ACTION_MOVE); 
      } 
    } else { 
      // 在下拉過程中往上拉動listView使listView往下滾動到其沒有滾動到頂部,則取消其下拉狀態(tài),回到手指按下的初始狀態(tài) 
      lastAction = MotionEvent.ACTION_DOWN; 
      isPulling = false; 
      distanceY = 0; 
    } 
  } 
  return super.onTouchEvent(ev); 
} 

這一段代碼相對有一點(diǎn)復(fù)雜,我們慢慢解析。首先,我們有一個lastAction變量來記錄上一個手勢是什么,有一個isPulling變量來記錄當(dāng)前PullToRefreshListView是否處于下拉狀態(tài),有一個isTop變量記錄當(dāng)前PullToRefreshListView是否已經(jīng)滾動到頂部。

在onTouchEvent方法的重載實(shí)現(xiàn)中,一開始PullToRefreshListView沒有接受任何手勢,然后當(dāng)用戶按下手指出發(fā)ACTION_DOWN事件時,我記錄下這個動作,然后當(dāng)用戶進(jìn)行滑動時,如果此時PullToRefreshListView沒有“滾動到頂部”,則不做任何處理,反之則將lastAction更新為ACTION_MOVE狀態(tài),更新isPulling變量,記錄當(dāng)前手指的位置作為計算下拉距離的起始位置,開始下拉刷新,然后在下拉的過程中計算PullToRefreshListView下拉的距離以重畫子View。

在這個手勢處理的實(shí)現(xiàn)中,當(dāng)用戶在下拉過程中突然將PullToRefreshListView往上拉,如果將PullToRefreshListView 拉到不處于“滾動到頂部的狀態(tài)”時,則重置下拉狀態(tài),使得:

lastAction = MotionEvent.ACTION_DOWN; 

于是PullToRefreshListView接下來的下滑手勢響應(yīng)權(quán)被交還給系統(tǒng),知道用戶又將PullToRefreshListView下拉到“滾動到頂部”狀態(tài),則又重新執(zhí)行上述操作,使PullToRefreshListView進(jìn)入下拉狀態(tài)。

5. 如何判斷ListView是否已經(jīng)滾動到頂部

下一步,我們?nèi)绾闻袛郘istView是否處于“滾動到頂部”狀態(tài)呢?這一問題我PullToRefreshListView的onScroll中解決。

    setOnScrollListener(new OnScrollListener() {
      @Override
      public void onScrollStateChanged(AbsListView view, int scrollState) {
      }
      @Override
      public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        // 沒有子view的時候(沒有數(shù)據(jù),或者被拉到看不到子view),意味著該listView滾動到頂部
        if (getChildCount() == 0) {
          isTop = true;
          return;
        }
        if (firstVisibleItem == 0) {
          View firstView = getChildAt(0);
          if (firstView.getTop() + distanceY >= 0) {
            // 第一個view可見且其相對parent(該listView)的頂部距離大于等于0,意味著該listView也是滾動到頂部
            isTop = true;
            return;
          }
        }
        isTop = false;
      }
    });

為PullToRefreshListView設(shè)置一個OnScrollListener回調(diào),并在其onScroll方法中監(jiān)控其滾動位置,具體看注釋也已經(jīng)一目了然,我就不多解釋了。

6. 下拉后的回滾動畫

最后,當(dāng)下拉結(jié)束松開手指時,我們需要為PullToRefreshListView執(zhí)行一個回滾的動畫,我們在onTouchEvent方法中看到:

    // ......
    else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {
      // 放開手指,開始回滾
      isPulling = false;
      lastAction = -1;
      startAnimating();
      L.d(TAG, "touch up");
    }
    // ...... 

startAnimating方法的實(shí)現(xiàn)如下:

  /**
   * 下拉結(jié)束時進(jìn)行回滾動畫并執(zhí)行刷新動作
   */
  private void startAnimating() {
    int whereToLoad = dp2px(onLoadCallBack.whereToLoad());
    final boolean toLoad;
    if (distanceY <= whereToLoad) {
      pullCancelAnimator = ValueAnimator.ofFloat(distanceY, 0);
      toLoad = false;
    } else {
      pullCancelAnimator = ValueAnimator.ofFloat(distanceY, whereToLoad);
      toLoad = true;
    }
    pullCancelAnimator.setDuration((long) (DEFAULT_BASE_ANIMATING_TIME_PER_100DP*px2dp(distanceY)/100));
    pullCancelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
    pullCancelAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        distanceY = (float) animation.getAnimatedValue();
        ViewCompat.postInvalidateOnAnimation(PullToRefreshListView.this);
      }
    });
    pullCancelAnimator.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animation) {
      }
      @Override
      public void onAnimationEnd(Animator animation) {
        post(new Runnable() {
          @Override
          public void run() {
            pullCancelAnimator = null;
            if (toLoad) {
              onLoadCallBack.onLoad();
            }
          }
        });
      }
      @Override
      public void onAnimationCancel(Animator animation) {
        post(new Runnable() {
          @Override
          public void run() {
            pullCancelAnimator = null;
            if (toLoad) {
              onLoadCallBack.cancelLoad();
            }
          }
        });
      }
      @Override
      public void onAnimationRepeat(Animator animation) {
      }
    });
    pullCancelAnimator.start();
  }

我使用ValueAnimator來實(shí)現(xiàn)這一回滾動畫,其中為ValueAnimator設(shè)置的回調(diào)中,在動畫更新和動畫結(jié)束以及動畫取消中分別調(diào)用了OnLoadCallBack的3歌回調(diào)方法,從而實(shí)現(xiàn)PullToRefreshListView的下拉刷新動作。我們可以看到,onLoad方法是在UI線程執(zhí)行的,因此如果在onLoad方法中執(zhí)行耗時操作的話,需要在后臺線程中操作,這與我們前面的解析是對應(yīng)的。

7. 改進(jìn)和問題

(1) 我們可以將onLoad回調(diào)修改成一個返回一個異步任務(wù)對象的方法,然后PullToRefreshListView在下拉結(jié)束后執(zhí)行這個異步任務(wù),因此我們就可以不需要cancelLoading回調(diào)了,直接就可以在PullToRefreshListView內(nèi)部進(jìn)行取消操作,這樣做可以增強(qiáng)封裝性,但相對目前的做法自由度就沒有那么高了。

(2) 回滾動畫應(yīng)該也可以進(jìn)行優(yōu)化,具體怎么優(yōu)化我也不清楚。。。各位朋友有好的想法可以在評論區(qū)提議一下,謝謝~

(3) 下拉的時候?qū)Χ帱c(diǎn)觸碰的響應(yīng)并不完美,雖然也可以接受,但是做不到像qq客戶端的聊天列表那樣。

8. 源碼

至此,我已經(jīng)解析了如何實(shí)現(xiàn)一個下拉刷新列表,PullToRefreshListView的源碼如下。

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListView;
import com.ivan.healthcare.healthcare_android.log.L;
/**
 * 支持下拉刷新的的listView
 * Created by Ivan on 16/2/14.
 */
public class PullToRefreshListView extends ListView {
  private final String TAG = "PullToRefreshListView";
  private final int DEFAULT_BASE_ANIMATING_TIME_PER_100DP = 150;
  public static final int DEFAULT_WHERE_TO_LOAD = 80;
  private int lastAction = -1;
  private float pullStartY = -1;
  private boolean isTop = true;
  private float distanceY = 0;
  private boolean isPulling = false;
  private ValueAnimator pullCancelAnimator;
  private Context context;
  private Drawable refreshDrawable;
  private OnLoadCallBack onLoadCallBack = new OnLoadCallBack() {
    @Override
    public int whereToLoad() {
      return DEFAULT_WHERE_TO_LOAD;
    }
    @Override
    public void onLoad() {
    }
    @Override
    public void cancelLoad() {
    }
    @Override
    public Drawable refreshDrawable() {
      return null;
    }
  };
  public PullToRefreshListView(Context context) {
    super(context);
    initView(context);
  }
  public PullToRefreshListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView(context);
  }
  private void initView(Context context) {
    this.context = context;
    setOnScrollListener(new OnScrollListener() {
      @Override
      public void onScrollStateChanged(AbsListView view, int scrollState) {
      }
      @Override
      public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        // 沒有子view的時候(沒有數(shù)據(jù),或者被拉到看不到子view),意味著該listView滾動到頂部
        if (getChildCount() == 0) {
          isTop = true;
          return;
        }
        if (firstVisibleItem == 0) {
          View firstView = getChildAt(0);
          if (firstView.getTop() + distanceY >= 0) {
            // 第一個view可見且其相對parent(該listView)的頂部距離大于等于0,意味著該listView也是滾動到頂部
            isTop = true;
            return;
          }
        }
        isTop = false;
      }
    });
  }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
      // 按下的時候
      lastAction = MotionEvent.ACTION_DOWN;
      cancelAnimating();
      L.d(TAG, "touch down");
    } else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {
      // 放開手指,開始回滾
      isPulling = false;
      lastAction = -1;
      startAnimating();
      L.d(TAG, "touch up");
    } else if (lastAction == MotionEvent.ACTION_DOWN) {
      if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
        // 在按下手指的基礎(chǔ)上,開始滑動
        if (isTop && !isPulling) {
          // listView在頂部而且不處于下拉刷新狀態(tài),開始下拉
          pullStartY = ev.getY();
          lastAction = MotionEvent.ACTION_MOVE;
          isPulling = true;
        }
      }
    } else if (lastAction == MotionEvent.ACTION_MOVE) {
      if (isTop) {
        // 下拉
        distanceY = ev.getY() - pullStartY;
        L.d(TAG, distanceY + "");
        if (distanceY > 0) {
          distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);
          // 在下拉狀態(tài)時取消系統(tǒng)對move動作的響應(yīng),完全由本類響應(yīng)
          ev.setAction(MotionEvent.ACTION_DOWN);
        } else {
          distanceY = 0;
          // 在下拉過程中往上拉動該listView使得其回到頂部位置,則將該move動作交由系統(tǒng)進(jìn)行響應(yīng)
          ev.setAction(MotionEvent.ACTION_MOVE);
        }
      } else {
        // 在下拉過程中往上拉動listView使listView往下滾動到其沒有滾動到頂部,則取消其下拉狀態(tài),回到手指按下的初始狀態(tài)
        lastAction = MotionEvent.ACTION_DOWN;
        isPulling = false;
        distanceY = 0;
      }
    }
    return super.onTouchEvent(ev);
  }
  @Override
  protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    if (distanceY > 0) {
      if (refreshDrawable == null) {
        refreshDrawable = onLoadCallBack.refreshDrawable();
      }
      if (refreshDrawable == null) {
        canvas.drawColor(Color.GRAY);
      } else {
        int left = getPaddingLeft();
        int top = getPaddingTop();
        refreshDrawable.setBounds(left, top, getWidth()+left, getHeight()+top);
        refreshDrawable.draw(canvas);
      }
      canvas.save();
      canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);
      for (int i=0;i<getChildCount();i++) {
        View child = getChildAt(i);
        drawChild(canvas, child, getDrawingTime());
      }
      canvas.restore();
    }
  }
  /**
   * 下拉結(jié)束時進(jìn)行回滾動畫并執(zhí)行刷新動作
   */
  private void startAnimating() {
    int whereToLoad = dp2px(onLoadCallBack.whereToLoad());
    final boolean toLoad;
    if (distanceY <= whereToLoad) {
      pullCancelAnimator = ValueAnimator.ofFloat(distanceY, 0);
      toLoad = false;
    } else {
      pullCancelAnimator = ValueAnimator.ofFloat(distanceY, whereToLoad);
      toLoad = true;
    }
    pullCancelAnimator.setDuration((long) (DEFAULT_BASE_ANIMATING_TIME_PER_100DP*px2dp(distanceY)/100));
    pullCancelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
    pullCancelAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override
      public void onAnimationUpdate(ValueAnimator animation) {
        distanceY = (float) animation.getAnimatedValue();
        ViewCompat.postInvalidateOnAnimation(PullToRefreshListView.this);
      }
    });
    pullCancelAnimator.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animation) {
      }
      @Override
      public void onAnimationEnd(Animator animation) {
        post(new Runnable() {
          @Override
          public void run() {
            pullCancelAnimator = null;
            if (toLoad) {
              onLoadCallBack.onLoad();
            }
          }
        });
      }
      @Override
      public void onAnimationCancel(Animator animation) {
        post(new Runnable() {
          @Override
          public void run() {
            pullCancelAnimator = null;
            if (toLoad) {
              onLoadCallBack.cancelLoad();
            }
          }
        });
      }
      @Override
      public void onAnimationRepeat(Animator animation) {
      }
    });
    pullCancelAnimator.start();
  }
  private void cancelAnimating() {
    if (pullCancelAnimator != null) {
      pullCancelAnimator.cancel();
    }
  }
  private float px2dp(float pxvalue) {
    return (pxvalue - 0.5f) /context.getResources().getDisplayMetrics().density;
  }
  private int dp2px(float dpvalue) {
    return (int) (dpvalue * context.getResources().getDisplayMetrics().density + 0.5f);
  }
  /**
   * 下拉刷新的回調(diào)
   */
  public interface OnLoadCallBack {
    /**
     * 下拉結(jié)束后將listView定位到哪個位置等待刷新完成
     * @return listView的定位y坐標(biāo)值,in dp
     */
    int whereToLoad();
    /**
     * 下拉結(jié)束后進(jìn)行刷新的回調(diào)
     */
    void onLoad();
    /**
     * 取消刷新
     */
    void cancelLoad();
    /**
     * 下拉刷新的背景
     * @return 背景drawable
     */
    Drawable refreshDrawable();
  }
  /**
   * 設(shè)置下拉刷新回調(diào)
   * @param cb 回調(diào)
   */
  public void setOnLoadCallBack(OnLoadCallBack cb) {
    this.onLoadCallBack = cb;
  }
  /**
   * 刷新動作結(jié)束后調(diào)用該方法結(jié)束刷新,使得listView回滾到頂部
   */
  public void setLoadingFinish() {
    startAnimating();
  }
}

以上這篇android 有阻尼下拉刷新列表的實(shí)現(xiàn)方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論