Android仿iOS实现侧滑返回功能(类似微信)

我们都知道侧滑返回操作是 iOS 里面比较常见的功能,一般是手指在靠近手机屏幕左边缘向右滑动就可以关闭当前的界面,iOS 系统提供了这样的 API,但是 Android 怎么实现呢?网上找了许多方法,比较了一下,个人觉得还是这个比较方便也容易理解,

先上个效果再说:

原理

Activity 本身是不可以滑动的,但是我们可以制造一个正在滑动 Activity 的假象,使得看起来这个 Activity 正在被手指滑动。其原理其实很简单,我们滑动的其实是 Activity 里面的可见View元素,而我们将 Activity 设置为透明的,这样当 View 滑过的时候,由于 Activity 的底部是透明的,我们就可以在滑动过程中看到下面的Activity,这样看起来就是在滑动 Activity。所以 Activity 滑动效果分两步:

设置 Activity 透明
滑动 View

实现

1、设置透明:

资源文件 values -> styles.xml 添加如下代码,搞一个透明的主题。

<style name="Transparent" parent="Theme.AppCompat.Light.NoActionBar">
  <item name="android:windowBackground">@android:color/transparent</item>
  <item name="android:windowIsTranslucent">true</item>
</style>

然后在 AndroidManifest.xml 文件里面给相应的 Activity 设置透明的主题。比如 MainActivity :

<activity
  android:name="com.example.test.MainActivity"
  android:theme="@style/Transparent" >
</activity>

2、滑动View:

先看看 Activity 的层次结构:我们用的 Activity 的 xml 的根 View 并不是 Activity 的根 View ,在它上面还有一个父 View, id 是 android.R.id.content,再向上一层,还有一个view,它是一个 LinearLayout,它除了放置我们创建的 View 之外,还放置我们的 xml 之外的一些东西比如放 ActionBar 或者标题栏什么的。而再往上一级,就到了 Activity 的根 View —— DecorView,结构

如下图所示:

要做到像 iOS 那样可以滑动整个 Activity ,只滑动我们在xml里面创建的 View 显然是不对的,因为我们还有标题栏、ActionBar 什么的,所以我们要滑动的应该是 DecorView 或者倒数第二层的那个 View。

而要滑动 View的话,我们要重写其父窗口的 onInterceptTouchEvent 以及 onTouchEvent(当然使用 setOnTouchListener 不是不可能,但是如果子 View 里面有一个消费了 onTouch 事件,那么也就接收不到了),但是窗口的创建过程不是我们能控制的,DecorView 的创建都不是我们能干预的。

解决办法就是,我们自己创建一个 SwipeLayout,然后人为地插入顶层 View 中,放置在 DecorView 和其下面的 LinearLayout 中间,随着手指的滑动,不断改变 SwipeLayout 的子 View ——曾经是 DecorView 的子 View——的位置,这样我们就可以控制 Activity 的滑动啦。我们在 Activity 的 onPostCreate 方法中调用swipeLayout.replaceLayer 替换我们的 SwipeLayout,代码如下:

public void replaceLayer(Activity activity) {

  mActivity = activity;
  screenWidth = getScreenWidth(activity);
  setClickable(true);
  //获取 Activity 的 根 View
  ViewGroup root = (ViewGroup) activity.getWindow().getDecorView();
  //获取 根 View 下面的第一个 View,并保存到 content
  content = root.getChildAt(0);
  ViewGroup.LayoutParams params = content.getLayoutParams();
  ViewGroup.LayoutParams params2 = new ViewGroup.LayoutParams(-1, -1);
  //把根 View 下面原来的第一个 View 删除
  root.removeView(content);
  //把 content 添加到 SwipeLayout
  this.addView(content, params2);
  //再把 SwipeLayout 添加到根 View 里面
  root.addView(this, params);
  sideWidth = (int) (sideWidthInDP * activity.getResources().getDisplayMetrics().density);
}


然后把这些写成一个 SwipeActivity 要求实现侧滑返回的 Activity 继承 SwipeActivity , SwipeActivity 继承 FragmentActivity 或者 Activity 。比如 MainActivity:

public class SwipeActivity extends FragmentActivity {
  ...
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  }
  ...
}

public class MainActivity extends SwipeActivity {
  ...
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  }
  ...
}

总结

其实在工作中,开发一个项目基本都会封装一个 BaseActivity,只要 BaseActivity 继承 SwipeActivity ,然后所有继承 BaseActivity 的 Activity 就都可以实现侧滑返回了, 如果有不需要实现这个功能的只需要调用 SwipeActivity 里面的一个方法:
public void setSwipeEnabled(boolean swipeEnabled) 参数传一个 false 就好了。是不是很方便!

其实另外还暴露出来一个方法:
public void setSwipeAnyWhere(boolean swipeAnyWhere) 设置是否屏幕任意位置右滑关闭,因为默认是只能左边缘右滑返回。

最后

附上原github: https://github.com/NashLegend/SwipetoFinishActivity

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

声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#nhooo.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。