返回顶部
首页 > 资讯 > 移动开发 >Android中SwipeBack实现右滑返回效果
  • 899
分享到

Android中SwipeBack实现右滑返回效果

Android 2022-06-06 09:06:06 899人浏览 安东尼
摘要

现在有很多App支持右滑返回,比如知乎,效果比较赞。 于是自己对Activity和Fragment进行了继承,派生出SwipeBackActivity和SwipeBackFr

现在有很多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);
  }
  
  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);
    }
  }
  
  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();
  }
  
  public interface OnFinishListener{
    void onFinish();
  }
}
您可能感兴趣的文章:Android右滑返回上一个界面的实现方法Android仿微信右滑返回功能的实例代码android 右滑返回的示例代码Android实现类似iOS右滑返回的效果(原因分析及解决办法)Android 实现右滑返回功能


--结束END--

本文标题: Android中SwipeBack实现右滑返回效果

本文链接: https://lsjlt.com/news/25767.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作