全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

android 右滑返回的示例代码

类似于微信的右滑返回,在BaseActivity里利用dispatchTouchEvent()拦截右滑动作,利用setTranslationX()实现动画,在DecorView里添加View作为滑动时的左侧阴影。

渐进步骤:

  • 设置activity背景透明
  • 重写finish()等方法设置activity的跳转动画
  • 重写dispatchTouchEvent()拦截 所需要 右滑动作
  • 重写onTouchEvent()给根布局设置偏移量
  • 添加滑动时上层activity的左侧阴影
  • 滑动时关联下层activity滑动

注意:步骤中的代码为了不关联到后面的步骤,会与最终的有点不同

背景透明

  <item name="android:windowBackground">@android:color/transparent</item>
  <item name="android:windowIsTranslucent">true</item>

activity的跳转动画

根据项目需要,重写用到的startActivity(Intent intent),startActivityForResult(Intent intent, int requestCode),finish()等activity跳转和销毁方法

@Override
public void startActivity(Intent intent) {
  super.startActivity(intent);
  overridePendingTransition(R.anim.slide_right_in, 0);
}

@Override
public void startActivityForResult(Intent intent, int requestCode) {
  super.startActivityForResult(intent, requestCode);
  overridePendingTransition(R.anim.slide_right_in, 0);
}

@Override
public void finish() {
  super.finish();
  overridePendingTransition(0, R.anim.slide_right_out);
}

//R.anim.slide_right_in
<set xmlns:android="http://schemas.android.com/apk/res/android">
 <translate
   android:duration="300"
   android:fromXDelta="100%"
   android:toXDelta="0"
   android:fromYDelta="0"
   android:toYDelta="0"/>
</set>

//R.anim.slide_right_out
<set xmlns:android="http://schemas.android.com/apk/res/android">
 <translate
   android:duration="300"
   android:fromXDelta="0"
   android:toXDelta="100%"
   android:fromYDelta="0"
   android:toYDelta="0" />
</set>

拦截右滑动作

所有的触摸事件通过activity.dispatchTouchEvent(MotionEvent ev)向view分发。
手指在X轴方向右滑动50~100px时,判断是否为(产品经理要)右滑动作

  • 手指落点为全屏幕,X方向滑动距离要比Y方向的大一些;
  • 手指落点为左侧边,X方向滑动距离有一些就行
private float downX = 0;
private float downY = 0;
private boolean shouldIntercept = false;
private boolean hadJudge = false;

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
  if (shouldIntercept) {
    return onTouchEvent(ev);
  }
  switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN: {
      downX = ev.getRawX();
      downY = ev.getRawY();
      hadJudge = false;
      break;
    }
    case MotionEvent.ACTION_MOVE: {
      if (hadJudge) break;
      if (ev.getRawX() == downX) break;
      if (ev.getRawX() < downX) {
        //左滑
        hadJudge = true;
        break;
      }
      if (ev.getRawX() - downX >=100){
        //超出判断距离
        hadJudge = true;
        break;
      }
      if (ev.getRawX() - downX > 50) {
        //x轴右滑50~100px
        float rate = (ev.getRawX() - downX) / (Math.abs(ev.getRawY() - downY));
        if ((downX < 50 && rate > 0.5f) || rate > 2) {
          shouldIntercept = true;
        }
      }
      break;
    }
    case MotionEvent.ACTION_UP: {
      downX =0;
      downY = 0;
      shouldIntercept = false;
      hadJudge=false;
      break;
    }
  }
  //Activity的默认分发
  if (ev.getAction() == MotionEvent.ACTION_DOWN) {
    onUserInteraction();
  }
  if (getWindow().superDispatchTouchEvent(ev)) {
    return true;
  }
  return true;
}

根布局位移动画

根据手指滑动距离设置根布局偏移距离,用滑动距离和手指抬起时的速度判断是否返回

private View rootView = null;
private float lastX = -1;  
private VelocityTracker velocityTracker = null;
private int maxFlingVelocity;


@Override
public boolean onTouchEvent(MotionEvent event) {
  if (rootView == null) {
    ViewGroup rootGroup = (ViewGroup) (getWindow().getDecorView());
    rootView = rootGroup.getChildAt(0);
  }
  //测量手指抬起时的速度
  if (velocityTracker == null) {
    velocityTracker = VelocityTracker.obtain();
    maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity();
  }
  velocityTracker.addMovement(event);


  switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN: {
      lastX = event.getRawX();
      break;
    }
    case MotionEvent.ACTION_MOVE: {
      if (lastX == -1) {
        lastX = event.getRawX();
        break;
      }
      //根据手指滑动距离设置根布局偏移距离
      rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX);
      if (rootView.getTranslationX() < 0) rootView.setTranslationX(0);
      lastX = event.getRawX();
      break;
    }
    case MotionEvent.ACTION_UP: {
      //测量手指抬起时的速度
      velocityTracker.computeCurrentVelocity(1000, maxFlingVelocity);
      float velocityX = velocityTracker.getXVelocity();
      if (velocityTracker != null) {
        velocityTracker.recycle();
        velocityTracker = null;
      }

      //判断是否返回
      if (downX < 50 && velocityX > 1000) {
        //手指在左侧边落下,返回
        onBack();
      } else if (velocityX > 3600) {
        //手指快速滑动,返回
        onBack();
      } else if (rootView.getTranslationX() > ConvertUtil.getWidthInPx() * 0.3) {
        //滑动距离超过30%屏幕宽度,返回
        onBack();
      } else {
        //不返回,根布局偏移归零
        rootView.animate().translationX(0).setDuration(200).start();
      }
      
      lastX = -1;
      shouldIntercept = false;
      hadJudge=false;
      downX = 0;
      downY = 0;
      break;
    }
  }
  return super.onTouchEvent(event);
}

添加左侧阴影

Activity的最顶层View为DecorView,DecorView是一个FrameLayout,里面只有一个Linearlayout,Linearlayout包含着标题栏和自定义布局(setContentView)。
上一步跟随手指滑动进行偏移的就是Linearlayout,现在要在DecorView里添加一个View,设置背景作为阴影,并跟随Linearlayout进行移动

private View shadowView = null;
@Override
public boolean onTouchEvent(MotionEvent event) {
  if (rootView == null) {
    //添加阴影
    
    ViewGroup rootGroup = (ViewGroup) (getWindow().getDecorView());

    shadowView = new View(this);
    rootGroup.addView(shadowView, 0);
    ViewGroup.LayoutParams params = shadowView.getLayoutParams();
    //阴影宽度
    params.width = (int) ((float) ConvertUtil.getWidthInPx() * 0.05f);
    params.height = ConvertUtil.getHeightInPx();
    shadowView.setLayoutParams(params);
    shadowView.setBackgroundResource(R.drawable.shadow_grey_h);
    shadowView.setTranslationX(params.width);

    rootView = rootGroup.getChildAt(1);
  }

  ...

  switch (event.getAction()) {
    ...
    case MotionEvent.ACTION_MOVE: {
      if (lastX == -1) {
        lastX = event.getRawX();
        break;
      }
      //根据手指滑动距离设置根布局偏移距离
      rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX);
      if (rootView.getTranslationX() < 0) rootView.setTranslationX(0);
      //阴影跟随根布局移动
      shadowView.setTranslationX(-shadowView.getWidth()+rootView.getTranslationX());
      lastX = event.getRawX();
      break;
    }
    case MotionEvent.ACTION_UP: {
      ...
      } else {
        //不返回,根布局偏移归零
        rootView.animate().translationX(0).setDuration(200).start();
        //阴影偏移归零
        shadowView.animate().translationX(-shadowView.getWidth()).setDuration(200).start();
      }
      ...
    }
  }
  ...
}

关联下层activity滑动

  • 保存所有的activity以获取下层activity
  • 给下层activity添加退出和进入的动画
  • 在上层activity滑动时调用下层滑动

获取下层activity

private static ArrayList<Activity> Activity_Stack = new ArrayList<>();
private BaseSwipeBackActivity lastActivity = null;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity();

  if (!Activity_Stack.contains(this)) Activity_Stack.add(this);
  if (Activity_Stack.size() >= 2) {
    Activity last = Activity_Stack.get(Activity_Stack.size() - 2);
    if (last instanceof BaseSwipeBackActivity) {
      lastActivity = (BaseSwipeBackActivity) last;
    }
  }
}

@Override
protected void onDestroy() {
  super.onDestroy();
  Activity_Stack.remove(this);
}

下层activity的退出、进入动画

private void lowerActivityExitAnim() {
  if (rootView == null) return;
  //只移动30%
  rootView.animate().translationX(-ConvertUtil.getWidthInPx() * 0.3f).setDuration(300).start();
}

private void lowerActivityEnterAnim(float upperTranslationX) {
  if (rootView == null) return;
  //保证滑动退出时,上下层时间同步
  float r = 1-upperTranslationX/ (float) ConvertUtil.getWidthInPx();
  rootView.animate().translationX(0).setDuration((long) (300f * r)).start();
}

在跳转时,调用下层activity的退出、进入动画

@Override
public void startActivity(Intent intent) {
  super.startActivity(intent);
  overridePendingTransition(R.anim.slide_right_in, 0);
  lowerActivityExitAnim();
}

@Override
public void startActivityForResult(Intent intent, int requestCode) {
  super.startActivityForResult(intent, requestCode);
  overridePendingTransition(R.anim.slide_right_in, 0);
  lowerActivityExitAnim();
}

@Override
public void finish() {
  super.finish();
  overridePendingTransition(0, R.anim.slide_right_out);
  if (lastActivity != null) lastActivity.lowerActivityEnterAnim(rootView.getTranslationX());
  Activity_Stack.remove(this);
}

上层activity滑动时关联下层滑动

@Override
public boolean onTouchEvent(MotionEvent event) {
  ...
  switch (event.getAction()) {
    ...
    case MotionEvent.ACTION_MOVE: {
      ...
      //根据手指滑动距离设置根布局偏移距离
      rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX);
      if (rootView.getTranslationX() < 0) rootView.setTranslationX(0);
      //阴影跟随根布局移动
      shadowView.setTranslationX(-shadowView.getWidth() + rootView.getTranslationX());
      //下层activity跟随移动
      if (lastActivity != null && lastActivity.rootView != null)
        //-ConvertUtil.getWidthInPx() * 0.3f初始的偏移
        lastActivity.rootView.setTranslationX(-ConvertUtil.getWidthInPx() * 0.3f + rootView.getTranslationX() * 0.3f);
      ...
    }
    case MotionEvent.ACTION_UP: {
      ...
      } else {
        //不返回,根布局偏移归零
        rootView.animate().translationX(0).setDuration(200).start();
        //阴影偏移归零
        shadowView.animate().translationX(-shadowView.getWidth()).setDuration(200).start();
        //下层activity偏移复原
        if (lastActivity != null)
          lastActivity.lowerActivityExitAnim();
      }
      ...
    }
  }

  return super.onTouchEvent(event);
}

完整的

public abstract class BaseSwipeBackActivity extends AppCompatActivity {

  private static ArrayList<Activity> Activity_Stack = new ArrayList<>();
  private BaseSwipeBackActivity lastActivity = null;

  private View rootView = null;
  private View shadowView = null;

  private float downX = 0;
  private float downY = 0;
  private boolean shouldIntercept = false;
  private boolean hadJudge = false;

  private float lastX = -1;
  private VelocityTracker velocityTracker = null;
  private int maxFlingVelocity;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity();

    if (!Activity_Stack.contains(this)) Activity_Stack.add(this);
    if (Activity_Stack.size() >= 2) {
      Activity last = Activity_Stack.get(Activity_Stack.size() - 2);
      if (last instanceof BaseSwipeBackActivity) {
        lastActivity = (BaseSwipeBackActivity) last;
      }
    }
  }

  @Override
  protected void onResume() {
    initShadow();
    super.onResume();
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    Activity_Stack.remove(this);
  }

  @Override
  public void startActivity(Intent intent) {
    super.startActivity(intent);
    overridePendingTransition(R.anim.slide_right_in, 0);
    lowerActivityExitAnim();
  }

  @Override
  public void startActivityForResult(Intent intent, int requestCode) {
    super.startActivityForResult(intent, requestCode);
    overridePendingTransition(R.anim.slide_right_in, 0);
    lowerActivityExitAnim();
  }

  @Override
  public void finish() {
    super.finish();
    overridePendingTransition(0, R.anim.slide_right_out);
    if (lastActivity != null) lastActivity.lowerActivityEnterAnim(rootView.getTranslationX());
    Activity_Stack.remove(this);
  }

  private void initShadow() {
    if (shadowView == null) {
      ViewGroup rootGroup = (ViewGroup) (getWindow().getDecorView());

      shadowView = new View(this);
      rootGroup.addView(shadowView, 0);
      ViewGroup.LayoutParams params = shadowView.getLayoutParams();
      //阴影宽度
      params.width = (int) ((float) ConvertUtil.getWidthInPx() * 0.05f);
      params.height = ConvertUtil.getHeightInPx();
      shadowView.setLayoutParams(params);
      //渐变背景作为阴影
      shadowView.setBackgroundResource(R.drawable.shadow_grey_h);
      shadowView.setTranslationX(-params.width);

      rootView = rootGroup.getChildAt(1);
    }
  }

  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    if (shouldIntercept) {
      return onTouchEvent(ev);
    }
    switch (ev.getAction()) {
      case MotionEvent.ACTION_DOWN: {
        downX = ev.getRawX();
        downY = ev.getRawY();
        hadJudge = false;
        break;
      }
      case MotionEvent.ACTION_MOVE: {
        if (hadJudge) break;
        if (ev.getRawX() == downX) break;
        if (ev.getRawX() < downX) {
          //左滑
          hadJudge = true;
          break;
        }
        if (ev.getRawX() - downX >= 100) {
          //超出判断距离
          hadJudge = true;
          break;
        }
        if (ev.getRawX() - downX > 50) {
          //x轴右滑50~100px
          float rate = (ev.getRawX() - downX) / (Math.abs(ev.getRawY() - downY));
          if ((downX < 50 && rate > 0.5f) || rate > 2) {
            shouldIntercept = true;
          }
        }
        break;
      }
      case MotionEvent.ACTION_UP: {
        downX = 0;
        downY = 0;
        shouldIntercept = false;
        hadJudge = false;
        break;
      }
    }
    //Activity的默认分发
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
      onUserInteraction();
    }
    if (getWindow().superDispatchTouchEvent(ev)) {
      return true;
    }
    return true;
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    initShadow();

    //测量手指抬起时的速度
    if (velocityTracker == null) {
      velocityTracker = VelocityTracker.obtain();
      maxFlingVelocity = ViewConfiguration.get(this).getScaledMaximumFlingVelocity();
    }
    velocityTracker.addMovement(event);


    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN: {
        lastX = event.getRawX();
        break;
      }
      case MotionEvent.ACTION_MOVE: {
        if (lastX == -1) {
          lastX = event.getRawX();
          break;
        }
        //根据手指滑动距离设置根布局偏移距离
        rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX);
        if (rootView.getTranslationX() < 0) rootView.setTranslationX(0);
        //阴影跟随根布局移动
        shadowView.setTranslationX(-shadowView.getWidth() + rootView.getTranslationX());
        //下层activity跟随移动
        if (lastActivity != null && lastActivity.rootView != null)
          lastActivity.rootView.setTranslationX(-ConvertUtil.getWidthInPx() * 0.3f + rootView.getTranslationX() * 0.3f);

        lastX = event.getRawX();
        break;
      }
      case MotionEvent.ACTION_UP: {
        //测量手指抬起时的速度
        velocityTracker.computeCurrentVelocity(1000, maxFlingVelocity);
        float velocityX = velocityTracker.getXVelocity();
        if (velocityTracker != null) {
          velocityTracker.recycle();
          velocityTracker = null;
        }

        //判断是否返回
        if (downX < 50 && velocityX > 1000) {
          //手指在左侧边落下,返回
          onBack();
        } else if (velocityX > 3600) {
          //手指快速滑动,返回
          onBack();
        } else if (rootView.getTranslationX() > ConvertUtil.getWidthInPx() * 0.3) {
          //滑动距离超过30%屏幕宽度,返回
          onBack();
        } else {
          //不返回,根布局偏移归零
          rootView.animate().translationX(0).setDuration(200).start();
          //阴影偏移归零
          shadowView.animate().translationX(-shadowView.getWidth()).setDuration(200).start();
          //下层activity偏移复原
          if (lastActivity != null) lastActivity.lowerActivityExitAnim();
        }

        lastX = -1;
        shouldIntercept = false;
        hadJudge = false;
        downX = 0;
        downY = 0;
        break;
      }
    }

    return super.onTouchEvent(event);
  }
  

  private void lowerActivityExitAnim() {
    if (rootView == null) return;
    rootView.animate().translationX(-ConvertUtil.getWidthInPx() * 0.3f).setDuration(300).start();
  }

  private void lowerActivityEnterAnim(float upperTranslationX) {
    if (rootView == null) return;
    float r = 1-upperTranslationX/ (float) ConvertUtil.getWidthInPx();
    rootView.animate().translationX(0).setDuration(r == 0.0f ? 10 : (long) (300f * r)).start();
  }

  //退出
  abstract public void onBack();
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# android  # 右滑返回  # Android右滑返回上一个界面的实现方法  # Android仿微信右滑返回功能的实例代码  # Android实现类似IOS右滑返回的效果(原因分析及解决办法)  # Android中SwipeBack实现右滑返回效果  # Android 实现右滑返回功能  # 重写  # 跳转  # 判断是否  # 是一个  # 要在  # 就行  # 自定义  # 只有一个  # 要比  # 所需要  # 类似于  # 含着  # 大家多多  # 大一些  # 标题栏  # 上一步  # 为左  # 偏移量  # duration  # toXDelta 


相关文章: 行程制作网站有哪些,第三方机票电子行程单怎么开?  php能控制zigbee模块吗_php通过串口与cc2530 zigbee通信【介绍】  网站制作中优化长尾关键字挖掘的技巧,建一个视频网站需要多少钱?  沈阳制作网站公司排名,沈阳装饰协会官方网站?  网站插件制作软件免费下载,网页视频怎么下到本地插件?  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  头像制作网站在线制作软件,dw网页背景图像怎么设置?  简单实现Android文件上传  广州美橙建站如何快速搭建多端合一网站?  如何挑选优质建站一级代理提升网站排名?  常州企业网站制作公司,全国继续教育网怎么登录?  网站制作壁纸教程视频,电脑壁纸网站?  制作表格网站有哪些,线上表格怎么弄?  无锡营销型网站制作公司,无锡网选车牌流程?  如何通过远程VPS快速搭建个人网站?  如何制作一个表白网站视频,关于勇敢表白的小标题?  如何有效防御Web建站篡改攻击?  视频网站制作教程,怎么样制作优酷网的小视频?  宁波免费建站如何选择可靠模板与平台?  油猴 教程,油猴搜脚本为什么会网页无法显示?  早安海报制作网站推荐大全,企业早安海报怎么每天更换?  专业网站建设制作报价,网页设计制作要考什么证?  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  如何高效生成建站之星成品网站源码?  番禺网站制作公司哪家值得合作,番禺图书馆新馆开放了吗?  创业网站制作流程,创业网站可靠吗?  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?  c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】  ,网页ppt怎么弄成自己的ppt?  如何挑选高效建站主机与优质域名?  香港服务器部署网站为何提示未备案?  网站制作公司广州有几家,广州尚艺美发学校网站是多少?  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  深圳企业网站制作设计,在深圳如何网上全流程注册公司?  C#如何在一个XML文件中查找并替换文本内容  如何选择适合PHP云建站的开源框架?  C++如何编写函数模板?(泛型编程入门)  武汉网站制作费用多少,在武汉武昌,建面100平方左右的房子,想装暖气片,费用大概是多少啊?  建站之家VIP精选网站模板与SEO优化教程整合指南  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  网页制作模板网站推荐,网页设计海报之类的素材哪里好?  logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?  如何在IIS中新建站点并配置端口与IP地址?  如何通过免费商城建站系统源码自定义网站主题与功能?  建站之星安装提示数据库无法连接如何解决?  微课制作网站有哪些,微课网怎么进?  如何用PHP快速搭建CMS系统?  如何通过FTP空间快速搭建安全高效网站?  如何快速搭建支持数据库操作的智能建站平台? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。