国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

親自動手編寫Android通用刷新控件

2019-10-23 18:27:23
字體:
供稿:網(wǎng)友

項目中我們經(jīng)常有上拉、下拉刷新的需求,幾乎所有的listView、RecyclerView都會伴隨著上拉、下拉刷新的需求,如果我們使用一些開源控件,換了控件我們就要更新,現(xiàn)在我們自己擼起袖子寫一個通用的刷新控件

項目地址:https://git.oschina.net/qiangshen/commentview.git

思路:

  • 寫一個繼承RelativeLayout的RefreshLayout
  • 添加頭尾控件作為刷新控件
  • 通過事件分發(fā)來進行刷新操作
  • 通過動畫來控制控件移動

目的:讓他的所有子控件都可以使用,哪怕是一個TextView

public class RefreshLayout extends RelativeLayout {  /**   * 滑動控件時拉去的速度比例   */  private final int V_REFRESH = 2;  /**   * 是否是刷新過程   * true 是   * false 不是   * 為false的時候才可以進行刷新   */  private boolean mIsRefreshDuring;  /**   * 可以進下拉刷新   */  private boolean mCanDownPull;  /**   * 可以進行上拉刷新   */  private boolean mCanUpPull;  /**   * 判斷觸摸后是否是初次移動   */  private boolean mIsFirstMove;  /**   * y軸呢平移的距離   */  private int mDistanceY;  /**   * 刷新接口對象   */  private OnRefresh mOnRefresh;  /**   * 用于控制事件攔截的變量   */  private boolean mCanIntercept;  private int mTouchSlop;  private int mDistance;  private LayoutParams mHeaderParams;  private View mHeaderView;  private View mFootView;  private int mHeaderMaxHeight;  private int mStartY;  private LayoutParams mFootParams;  private int mFootMaxHeight;  private PullCallBack mCallBack;  private View mChildView;  private ObjectAnimator mAnimator;  public RefreshLayout(Context context) {    super(context);    initData();  }  public RefreshLayout(Context context, AttributeSet attrs) {    super(context, attrs);    initData();  }  public RefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    initData();  }  /**   * 必須讓頭尾控件實現(xiàn)的接口   */  public interface HeadAndFootCallBack {    //設(shè)置屬性    void setAttribute();    //開始刷新    void startPull();    //停止刷新    void stopPull();  }  /**   * 必須讓被拖動的控件子類實現(xiàn)   */  public interface PullCallBack {    boolean canDownPull();    boolean canUpPull();  }  private void initData() {    //不調(diào)用該方法不能進行繪制    setWillNotDraw(false);  }  /**   * 下拉刷新完成后必須使用該方法   */  public void downPullFinish() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();    ((HeadAndFootCallBack) mHeaderView).stopPull();  }  /**   * 上拉完成后必須調(diào)用該方法   */  public void upPullFinish() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();    ((HeadAndFootCallBack) mFootView).stopPull();  }  /**   * 自動下拉刷新   */  public void autoDownPullForHead() {    postDelayed(new Runnable() {      @Override      public void run() {        mCanDownPull = true;        mCanUpPull = false;        mAnimator.setFloatValues(10, mHeaderMaxHeight);        mAnimator.start();        ((HeadAndFootCallBack) mHeaderView).startPull();        mOnRefresh.onDownPullRefresh();      }    }, 500);  }  /**   * 自動下拉刷新   */  public void autoUpPullForHead() {    postDelayed(new Runnable() {      @Override      public void run() {        mCanDownPull = false;        mCanUpPull = true;        mAnimator.setFloatValues(0, mFootMaxHeight);        mAnimator.start();        ((HeadAndFootCallBack) mFootView).startPull();        mOnRefresh.onUpPullRefresh();      }    }, 500);  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {    return mCanIntercept;  }  @Override  public boolean onTouchEvent(MotionEvent event) {    return true;  }  @Override  public boolean dispatchTouchEvent(MotionEvent event) {    Log.e("shen", "mIsRefreshDuring=" + mIsRefreshDuring);    if (mIsRefreshDuring) /**如果正在進行刷新將不會獲取MotionEvent*/  {      return super.dispatchTouchEvent(event);    }    switch (event.getAction()) {      case MotionEvent.ACTION_DOWN:        mStartY = (int) event.getY();        initPull();        break;      case MotionEvent.ACTION_MOVE:        if (event.getPointerCount() == 1) {          int moveY = (int) event.getY();          mDistanceY = (moveY - mStartY) / V_REFRESH;          if (!mIsFirstMove && mDistanceY != 0 && mDistanceY < mTouchSlop) {            mCanDownPull = mDistanceY > 0;            mCanUpPull = !mCanDownPull;            mIsFirstMove = true;          }          if (mCanDownPull && mCallBack.canDownPull()) {            upDataForDownPull();//下拉刷新            mChildView.setEnabled(false);            mCanIntercept = true;          }          if (mCanUpPull && mCallBack.canUpPull()) {            upDataForUpPull();//上拉加載            mChildView.setEnabled(false);            mCanIntercept = true;          }          mStartY = moveY;        }        break;      case MotionEvent.ACTION_UP:        mIsRefreshDuring = true;        mIsFirstMove = false;        if (mHeaderParams.height >= mHeaderMaxHeight) /**可以下拉刷新**/  {          ((HeadAndFootCallBack) mHeaderView).startPull();          mOnRefresh.onDownPullRefresh();        } else if (mFootParams.height >= mFootMaxHeight) /**可以上拉刷新**/  {          ((HeadAndFootCallBack) mFootView).startPull();          mOnRefresh.onUpPullRefresh();        } else if (mHeaderParams.height > 0 && mHeaderParams.height < mHeaderMaxHeight) /**不能進行下拉刷新,收回**/  {          releaseForDownFinished();        } else if (mFootParams.height > 0 && mFootParams.height < mFootMaxHeight) /**不能進行下拉刷新,收回**/  {          releaseForUpFinished();        } else {          mIsRefreshDuring = false;          mCanIntercept = false;        }        break;    }    super.dispatchTouchEvent(event);    return true;  }  /**   * 每次進行觸摸都需要進行初始化   */  private void initPull() {    mCanDownPull = false;    mCanUpPull = false;  }  /**   * 不需要進行上拉刷新   */  private void releaseForUpFinished() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();  }  /**   * 不需要進行下拉刷新   */  private void releaseForDownFinished() {    mAnimator.setFloatValues(mChildView.getTranslationY(), 0);    mAnimator.start();  }  /**   * 上拉時處理手勢   */  private void upDataForUpPull() {    if (mDistanceY != 0) {      mFootParams.height -= mDistanceY;      if (mFootParams.height <= 0) {        mFootParams.height = 0;      }      if (mFootParams.height >= mFootMaxHeight) {        mFootParams.height = mFootMaxHeight;      }      mChildView.setTranslationY(-mFootParams.height);      mFootView.requestLayout();    }  }  /**   * 下拉時處理手勢   */  private void upDataForDownPull() {    if (mDistanceY != 0) {      mHeaderParams.height += mDistanceY;      if (mHeaderParams.height >= mHeaderMaxHeight) { //最大        mHeaderParams.height = mHeaderMaxHeight;      }      if (mHeaderParams.height <= 0) { //最小        mHeaderParams.height = 0;      }      mChildView.setTranslationY(mHeaderParams.height);      mHeaderView.requestLayout();    }  }  @Override  protected void onAttachedToWindow() {    super.onAttachedToWindow();  }  @Override  protected void onFinishInflate() {    super.onFinishInflate();    //加載頭    mHeaderView = getChildAt(0);    if (!(mHeaderView instanceof HeadAndFootCallBack)) {      new IllegalStateException("HeaderView必須實現(xiàn)HeadAndFootCallBack接口");    }    ((HeadAndFootCallBack) mHeaderView).setAttribute();    mHeaderParams = (LayoutParams) mHeaderView.getLayoutParams();    mHeaderParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);    //加載尾    mFootView = getChildAt(2);    if (!(mFootView instanceof HeadAndFootCallBack)) {      new IllegalStateException("FootView必須實現(xiàn)HeadAndFootCallBack接口");    }    ((HeadAndFootCallBack) mFootView).setAttribute();    mFootParams = (LayoutParams) mFootView.getLayoutParams();    mFootParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);    mChildView = getChildAt(1);    if (!(mChildView instanceof HeadAndFootCallBack)) {      new IllegalStateException("ChildView必須實現(xiàn)PullCallBack接口");    }    mCallBack = (PullCallBack) getChildAt(1);    //設(shè)置動畫    mAnimator = ObjectAnimator.ofFloat(mChildView, "translationY", 0);    mAnimator.setInterpolator(new DecelerateInterpolator());    mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {      @Override      public void onAnimationUpdate(ValueAnimator animation) {        int translationY = (int) mChildView.getTranslationY();        if (mCanUpPull) { //從移動到的位置往下滑          mFootParams.height = Math.abs(translationY);          mFootView.requestLayout();        } else if (mCanDownPull) {          mHeaderParams.height = Math.abs(translationY);          mHeaderView.requestLayout();        }        Log.e("shen", "translationY=" + translationY);        Log.e("shen", "mHeaderParams.height=" + mHeaderParams.height);        if (translationY == 0) {          mChildView.setEnabled(true);          mDistanceY = 0; //重置          mIsRefreshDuring = false; //重置          mCanIntercept = false;        } else {          mIsRefreshDuring = true;        }      }    });  }  @Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();    mDistance = mTouchSlop * 5;    //設(shè)置下拉頭初始屬性    mHeaderMaxHeight = mHeaderParams.height;    mHeaderParams.height = 0;    mHeaderView.requestLayout();    //設(shè)置上拉尾初始屬性    mFootMaxHeight = mFootParams.height;    mFootParams.height = 0;    mFootView.requestLayout();  }  /**   * 下拉/上拉事件監(jiān)聽   */  public interface OnRefresh {    /**     * 下拉刷新     */    void onDownPullRefresh();    /**     * 上拉加載     */    void onUpPullRefresh();  }  public void setOnRefresh(OnRefresh onRefresh) {    mOnRefresh = onRefresh;  }}

給他添加三個控件,頭尾就是刷新頭、尾,第二個就是正常顯示的控件。必須讓頭尾實現(xiàn)HeadAndFootCallBack接口,來設(shè)置屬性,通知開始刷新、結(jié)束刷新

難點: 現(xiàn)在來說下開發(fā)時遇到的難點

  • 由于判斷在dispatchTouchEvent中,導(dǎo)致如果該控件以及子控件都不消費該事件的話,就會造成事件不會發(fā)送到它,因為如果不消費DOWN事件的話,之后所有的事件都不會在進行接收。解決方式,讓該控件onTouchEvent方法消返回true,當(dāng)子控件不進行事件消費的話,就會返回由該控件消費,不會造成因DOWN事件不消費而無法接收到事件,導(dǎo)致dispatchTouchEvent也不消費事件
  • 動畫,動畫就是我的傷痛,最近在學(xué)習(xí)估值器

這個控件自認(rèn)為寫的不錯,通過他可以幫我們學(xué)習(xí)事件分發(fā)、動畫、接口回調(diào),也是有一定的學(xué)習(xí)意義

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 友谊县| 文成县| 寻乌县| 炉霍县| 鄂州市| 泾源县| 农安县| 日照市| 公安县| 平度市| 成安县| 桃园县| 武邑县| 顺义区| 称多县| 应城市| 永登县| 清苑县| 湖州市| 宁乡县| 五峰| 开化县| 平潭县| 德格县| 中西区| 锡林浩特市| 曲周县| 普兰店市| 庆安县| 滕州市| 黑河市| 东宁县| 古浪县| 富宁县| 宜宾县| 呼玛县| 西峡县| 白沙| 洪泽县| 奉节县| 陵水|