Android中SwipeBack實現右滑返回效果_Android

來源:互聯網
上載者:User

現在有很多App支援右滑返回,比如知乎,效果比較贊。

於是自己對Activity和Fragment進行了繼承,派生出SwipeBackActivity和SwipeBackFragment,用於對這種效果的實現,也就是只要繼承這兩個類就可以了。

效果如下

  • Activity

Fragment

Frgament的效果實現比Activity稍微簡單,因為Activity要考慮到dectorView。

支援滑動的控制項SwipeLayout,核心思路就是把原有的控制項添加到支援滑動的控制項中,SwipeLayout要注意計算手勢速度,源碼如下:

package com.ui.jerry.swipebackdemo;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.widget.LinearLayout;import android.widget.Scroller;import android.widget.Toast;public class SwipeLayout extends LinearLayout {  public static final String TAG = "SwipeLayout";  private View mEmptyView;  private View mContentView;  private int mLeftEdge;  private int mWidth;  private int mMaxScrollX;  private Scroller mScroller;  private VelocityTracker mVelocityTracker = null;  private int mMaxFlingVelocity;  private int mLastX;  ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);  private Context mContext;  public static final int DURATION = 1500;  //滿屏滑動時間  public static final int OPEN_ANIM_DURATION = 1000;  public static int SNAP_VELOCITY = 600; //最小的滑動速率  private OnFinishListener mOnFinishListener;  public SwipeLayout(Context context) {    this(context, null);  }  public SwipeLayout(Context context, AttributeSet attrs) {    super(context, attrs);    mContext = context;    init();  }  public void setOnFinishListener(OnFinishListener mOnFinishListener) {    this.mOnFinishListener = mOnFinishListener;  }  void init() {    mScroller = new Scroller(mContext);    mMaxFlingVelocity = ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity();    mWidth = DisplayUtils.getScreenWidth(mContext) * 2;    mMaxScrollX = mWidth / 2;    mLeftEdge = mMaxScrollX - mMaxScrollX / 3;    setOrientation(LinearLayout.HORIZONTAL);    childParams.width = DisplayUtils.getScreenWidth(mContext);    mEmptyView = LayoutInflater.from(mContext).inflate(R.layout.view_translate, null);    addView(mEmptyView, childParams);  }  public void setContentView(View contentView) {    if (mContentView != null) {      removeView(mContentView);    }    mContentView = contentView;    addView(contentView, childParams);    postDelayed(new Runnable() {      @Override      public void run() {        openActivityAnimation();      }    }, 200);  }  /**   * 擷取速度追蹤器   *   * @return   */  private VelocityTracker getVelocityTracker() {    if (mVelocityTracker == null) {      mVelocityTracker = VelocityTracker.obtain();    }    return mVelocityTracker;  }  /**   * 回收速度追蹤器   */  private void recycleVelocityTracker() {    if (mVelocityTracker != null) {      mVelocityTracker.clear();      mVelocityTracker.recycle();      mVelocityTracker = null;    }  }  @Override  public boolean onTouchEvent(MotionEvent ev) {    //1.擷取速度追蹤器    getVelocityTracker();    //2.將當前事件納入到追蹤器中    mVelocityTracker.addMovement(ev);    int pointId = -1;    switch (ev.getAction()) {      case MotionEvent.ACTION_DOWN:        //如果螢幕的動畫還沒結束,你就按下了,我們就結束上一次動畫,即開始這次新ACTION_DOWN的動畫//        clearScrollHis();        mLastX = (int) ev.getX();        pointId = ev.getPointerId(0);        break;      case MotionEvent.ACTION_MOVE:        int nextScrollX = (int) (mLastX - ev.getX() + getScrollX());        if (scrollTo(nextScrollX)) {          mLastX = (int) ev.getX();        }        break;      case MotionEvent.ACTION_CANCEL:      case MotionEvent.ACTION_UP:        //3.計算當前速度        mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity);        //擷取x y方向上的速度        float vX = mVelocityTracker.getXVelocity(pointId);        Log.i(TAG, "mVelocityX:" + vX);        //大於某個速率 直接滑動        if (vX > SNAP_VELOCITY) {          scrollToLeft();        } else if (vX < -SNAP_VELOCITY) {          scrollToRight();        } else {          snapToDestation();        }        //4.回收速度追蹤器        recycleVelocityTracker();        break;    }    return true;  }  private void openActivityAnimation() {    clearScrollHis();    mScroller.startScroll(getScrollX(), 0, mMaxScrollX - getScrollX(), 0, OPEN_ANIM_DURATION);    invalidate();//這裡必須調用invalidate()才能保證computeScroll()會被調用,否則不一定會重新整理介面,看不到滾動效果  }  public void closeActivityAnimation() {    clearScrollHis();    mScroller.startScroll(getScrollX(), 0, -getScrollX(), 0, OPEN_ANIM_DURATION);    invalidate();//這裡必須調用invalidate()才能保證computeScroll()會被調用,否則不一定會重新整理介面,看不到滾動效果  }  private void clearScrollHis() {    if (mScroller != null) {      if (!mScroller.isFinished()) {        mScroller.abortAnimation();      }    }  }  /**   * 根據現在的滾動位置判斷   */  private void snapToDestation() {    int scrollX = getScrollX();    if (scrollX > 0 && scrollX <= mLeftEdge) {      smoothScrollTo(0);    } else if (scrollX > mLeftEdge) {      smoothScrollTo(mMaxScrollX);    }  }  /**   * 直接滾動   *   * @param x   * @return   */  public boolean scrollTo(int x) {    if (x < 0) {      scrollTo(0, 0);    } else if (x > mMaxScrollX) {      scrollTo(mMaxScrollX, 0);    } else {      scrollTo(x, 0);    }    return true;  }  public void scrollToRight() {    smoothScrollTo(mMaxScrollX);  }  public void scrollToLeft() {    smoothScrollTo(0);  }  @Override  protected void onScrollChanged(int l, int t, int oldl, int oldt) {    super.onScrollChanged(l, t, oldl, oldt);    Log.d(TAG, "left:" + l);    if (l == 0) {      Log.d(TAG, "OnFinish");      Toast.makeText(mContext, "Finished", Toast.LENGTH_SHORT).show();      if(mOnFinishListener!=null){        mOnFinishListener.onFinish();      }    }  }  public void smoothScrollTo(int fx) {    if (fx < 0) {      smoothScrollTo(0, 0);    } else if (fx > mMaxScrollX) {      smoothScrollTo(mMaxScrollX, 0);    } else {      smoothScrollTo(fx, 0);    }  }  //  //調用此方法滾動到目標位置  public void smoothScrollTo(int fx, int fy) {    int dx = fx - getScrollX();    int dy = fy - getScrollY();    smoothScrollBy(dx, dy);  }  //調用此方法設定滾動的相對位移  public void smoothScrollBy(int dx, int dy) {    //設定mScroller的滾動位移量    mScroller.startScroll(getScrollX(), 0, dx, dy, Math.abs(dx * DURATION / mMaxScrollX));    invalidate();//這裡必須調用invalidate()才能保證computeScroll()會被調用,否則不一定會重新整理介面,看不到滾動效果  }  @Override  public void computeScroll() {    //先判斷mScroller滾動是否完成    if (mScroller.computeScrollOffset()) {      //這裡調用View的scrollTo()完成實際的滾動      scrollTo(mScroller.getCurrX(), mScroller.getCurrY());      //必須調用該方法,否則不一定能看到滾動效果      postInvalidate();    }    super.computeScroll();  }  /**   * fragment或者activity 結束的介面   */  public interface OnFinishListener{    void onFinish();  }}

以上就是本文的全部內容,希望對大家的學習有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.