关于Android实现ionic2 禁止滑动返回回的几种方法总结

Android左滑返回功能的实现示例代码
转载 &更新时间:日 09:02:50 & 作者:shawn_yy
本篇文章主要介绍了Android左滑返回的实现示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
前几天用了个app发现左滑可以返回首页,发现这个功能很炫酷,就想着自己能不能做出来,于是研究了一下
将activity的背景设置为透明同时设置切换动画
手指滑动的时候,根View跟着滑动,滑倒一定的距离就finish掉。
原理很简单,但实现起来可能有些坑。这里记录一下。
处理onInterceptTouchEvent
事件拦截要处理一件事情:确定这次触摸事件是不是应该交给SlideFinishLayout的onTouchEvent处理。
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
val action = ev.action
when (action){
MotionEvent.ACTION_DOWN -& {
mLastX = ev.x.toInt()
mIsDrag = false
MotionEvent.ACTION_MOVE -& {
mScroller.computeScrollOffset()
mIsDrag = !mScroller.isFinished
val deltaY:Int = ev.x.toInt() - mLastX
if (deltaY &= mTouchSlop){
mIsDrag = true
return mIsDrag
onTouchEvent
这个是核心的实现方法.
这里会用到OverScroller的startScroll()方法来处理手指离开后的动画。OverScroller使用起来非常的简单,如果想让View滚动就调用startScroll()传入相应参数,会把计算的结果回调给View的computeScroll()方法,下面是主要的实现思路:
override fun onTouchEvent(event: MotionEvent): Boolean {
val action = event.action
//1.初始化轨迹
initVelocityTrackerIfNotExists(event)
when(action){
MotionEvent.ACTION_DOWN -& {
//2.down 事件 mScroller放弃动画 记录触摸的位置
if (!mScroller.isFinished){
mScroller.abortAnimation()
mLastX = event.rawX.toInt()
mIsDrag = true
dispatchScroll(0 , 0 , slideState)
MotionEvent.ACTION_MOVE -& {
//3.move事件调用performDrag()方法 会调用offsetLeftAndRight() 从而移动View
val currentX = event.rawX.toInt()
val deltaX = currentX - mLastX
log("x = ${event.rawX} y = ${event.rawX}")
performDrag(deltaX)
log("deltaX = $deltaX")
mLastX = currentX
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -&{
//4.up事件 主要处理手指离开后的View的滚动,以及是否要达到销毁的条件
//endDrag()方法会处理手指离开后的动画以及是否达到销毁条件
if (mIsDrag){
mLastX = 0
mIsDrag = false
velocityTracker?.computeCurrentVelocity(1000 , mMaximumVelocity)
val velocity = velocityTracker?.xVelocity?.toInt()!!
isReachFinish = endDrag(velocity)
postInvalidateOnAnimation()
recycleVelocityTracker()
return true
//开始拖动
private fun performDrag(x:Int){
var canOffset = false
isDragLeft = x & 0
slideState = SlideState.DRAGGING
//计算 滚动的 距离
if (slideModel == DirectionModel.ONLY_LEFT ){
if (x & 0){
offsetLeftAndRight(x)
canOffset = true
}else if (slideModel == DirectionModel.ONLY_RIGHT){
offsetLeftAndRight(x)
canOffset = true
offsetLeftAndRight(x)
canOffset = true
if (canOffset){
dispatchScroll(x , left , slideState)
//手指离开后的动作
fun endDrag(xVelocity:Int):Boolean{
slideState = SlideState.SETTLING
val left = this.left
log( "left = $left screenWidth * FACTOR= ${screenWidth * FACTOR}")
log( "xVelocity = $xVelocity mMinimumVelocity= $mMinimumVelocity")
if (Math.abs(left) & screenWidth * FACTOR
|| xVelocity & mMinimumVelocity){
if (left&0){
mScroller.startScroll(left , 0 , screenWidth - left , 0)
mScroller.startScroll(left , 0 , left - screenWidth , 0)
return true
mScroller.startScroll(left , 0 , -left , 0)
return false
activity背景要透明的
&style name="AppTheme.Transparent" parent="Theme.AppCompat.Light.NoActionBar"&
&item name="android:windowBackground"&@color/transparent&/item&
&item name="android:windowIsTranslucent"&true&/item&
设置activity进场和出场动画
R.anim.enter
&?xml version="1.0" encoding="utf-8"?&
&set xmlns:android="http://schemas.android.com/apk/res/android"&
&translate
android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="200"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"/&
R.anim.exit
&?xml version="1.0" encoding="utf-8"?&
&set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="true"
&translate
android:fromXDelta="0"
android:toXDelta="100%p"
android:duration="200"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"/&
activity代码如下
class TwoActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_two)
val index = intent?.getStringExtra("index")
nextBtn.setOnClickListener {
startActivity(Intent(this@TwoActivity , TwoActivity::class.java))
overridePendingTransition(R.anim.enter, 0)
//滑动达到finish的监听事件,slideFinishLayout没有做任何处理 如果这里不掉用finish也不会退出activity
slideFinishLayout.finishListener = {
overridePendingTransition(0, 0)
override fun finish() {
super.finish()
overridePendingTransition(0, R.anim.exit)
存在的问题
堆栈之前的activity被意外销毁了,此时的当前的activity虽然为透明的,但是背景是黑色的,可能是因为被意外销毁还没有来的及调用onCreate,但是打开不保留活动来测试是没有问题的。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具你的位置: >
> 一步一步教你150行代码实现简书滑动返回效果
今天带大家实现简书的滑动返回效果.
先看看效果图:
因为没有具体内容,也没有简书的图片资源,所以稍微简陋了点.
但是依然不妨碍我们的效果展示~
OK,接下来惯例,通过阅读本文你能学习到:
ViewDragHelper的使用(如果你想学习自定义View,那么ViewDragHelper你绝对不能错过)
好像也没有什么了….
这个效果,难度不大,会ViewDragHelper的同学应该10分钟就能写出来了吧~
如果不会也没关系~
1. 我们自定义一个SwipeBackFrameLayout继承自FrameLayout
1.1 因为看到左边黄色的View是被遮住的,而另外一个View的宽度是MatchParent的,所以FrameLayout是不错的选择.
顺便增加一个回调,通知activity去finish
public void setCallback(Callback mCallback){
this.mCallback = mC
private Callback mC
public interface Callback{
void onShouldFinish();
1.2 Xml布局,非常简单:
&yifeiyuan.practice.practicedemos.drager.SwipeBackFrameLayout
xmlns:android=&http://schemas.android.com/apk/res/android&
xmlns:tools=&http://schemas.android.com/tools&
android:id=&@+id/swipe_back&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
tools:context=&yifeiyuan.practice.practicedemos.drager.SwipeBackActivity&&
android:layout_width=&40dp&
android:layout_height=&match_parent&
android:text=&@string/hello_world&
android:gravity=&center&
android:background=&#ffff00& /&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:background=&#ff00ff& /&
&/yifeiyuan.practice.practicedemos.drager.SwipeBackFrameLayout&
1.3 实例化一个ViewDragHelper
//1f代表灵敏度
mDragHelper = ViewDragHelper.create(this, 1f,new ViewDragHelper.Callback() {
public boolean tryCaptureView(View child, int pointerId) {
//因为我们是从左向右滑动 所以设置EDGE_LEFT
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
1.4 在SwipeBackFrameLayout里实例化xml里的子View
private View mDividerV
private View mContentV
protected void onFinishInflate() {
super.onFinishInflate();
mDividerView = getChildAt(0);
mDividerView.setAlpha(0f);
mContentView = getChildAt(1);
1.5 让ViewDragHelper处理touch事件
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mDragHelper.shouldInterceptTouchEvent(ev);
public boolean onTouchEvent(MotionEvent event) {
mDragHelper.processTouchEvent(event);
1.6重写ViewDragHelper的一些处理方法
已附上详细注释
public void onEdgeTouched(int edgeFlags, int pointerId) {
super.onEdgeTouched(edgeFlags, pointerId);
//触摸到左边界的时候 我们capture住mContentView
mDragHelper.captureChildView(mContentView, pointerId);
public int getViewHorizontalDragRange(View child) {
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
Log.d(TAG, &onViewPositionChanged() called with left = [& + left + &], top = [& + top + &], dx = [& + dx + &], dy = [& + dy + &]&);
//0.0 - 1.0
//Notice 这边可以给个接口回调出去,就可以做各种炫酷的效果了
float alpha = (float) (left*1.0/mDividerWidth);
mDividerView.setAlpha(alpha);
public int clampViewPositionHorizontal(View child, int left, int dx) {
// Log.d(TAG, &clampViewPositionHorizontal() called with dx = [& + dx + &]&);
// 计算left 我们的目标范围是0-dividerwidth的宽度
int newLeft = Math.min(mDividerWidth, Math.max(left,0));
return newL
public void onViewReleased(View releasedChild, float xvel, float yvel) {
//&0代表用户想关闭
if (mLastdx&0){
// 还不到关闭条件,我们让view滑动过去,再关闭
if (mDividerWidth != releasedChild.getLeft()) {
mDragHelper.settleCapturedViewAt(mDividerWidth,releasedChild.getTop();
invalidate();
if (mCallback != null) {
mCallback.onShouldFinish();
//用户不想关闭 ,则滑动到最左边
if (mDividerWidth != 0) {
mDragHelper.settleCapturedViewAt(0, releasedChild.getTop());
invalidate();
public void onViewDragStateChanged(int state) {
super.onViewDragStateChanged(state);
//滑动停止,并且到达了滑动的判断条件 则回调关闭
if(mDragHelper.getViewDragState()==ViewDragHelper.STATE_IDLE&&mCallback != null&&mDividerWidth==mContentView.getLeft()&&mLastdx&0) {
mCallback.onShouldFinish();
1.7 增加对view滑动事件处理,对于以上mDividerWidth我们在onLayout里获取
private int mDividerW
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mDividerWidth = mDividerView.getWidth();
//Notice view 刚初始化的时候就会被调用一次
public void computeScroll() {
super.computeScroll();
// Log.d(TAG, &computeScroll() called with & + &&);
if (mDragHelper.continueSettling(true)) {
invalidate();
我们写完自定义view后还需要自定义一下activity的退出动画~
2.定义activity的finish动画
2.1 在anim目录下,创建两个动画xml:
android:duration=&300&
xmlns:android=&http://schemas.android.com/apk/res/android&
android:fromAlpha=&1.0&
android:toAlpha=&1.0& &
//out_to_right
&translate
xmlns:android=&http://schemas.android.com/apk/res/android&
android:duration=&300&
android:fromXDelta=&0%&
android:toXDelta=&100%& &
&/translate&
2.2 在activity里设置callback监听,并运用动画
mSwipeBack.setCallback(new SwipeBackFrameLayout.Callback() {
public void onShouldFinish() {
overridePendingTransition(R.anim.no_anim, R.anim.out_to_right);
好了!!~代码量非常少!~就是这么简单~
吐槽一下,简书对代码块的支持太差了,代码复制过来全是乱的!!
同学们还是去看源码吧:
源码在我的上
转载请注明: &
与本文相关的文章&nbsp&#8250&nbsp&nbsp&#8250&nbsp
一步一步教你150行代码实现简书滑动返回效果
原文:&今天带大家实现简书的滑动返回效果.先看看效果图:因为没有具体内容,也没有简书的图片资源,所以稍微简陋了点.但是依然不妨碍我们的效果展示~OK,接下来惯例,通过阅读本文你能学习到:ViewDragHelper的使用(如果你想学习自定义View,那么ViewDragHelper你绝对不能错过)好像也没有什么了....这个效果,难度不大,会ViewDragHelper的同学应该10分钟就能写出来了吧~如果不会也没关系~1. 我们自定义一个SwipeBackFrameLayout继承自FrameLayout1.1 因为看到左边黄色的View是被遮住的,而另外一个View的宽度是MatchParent的,所以FrameLayout是不错的选择.顺便增加一个回调,通知activity去finishpublic&void&setCallback(Callback&mCallback){
&&&&this.mCallback&=&mC
private&Callback&mC
public&interface&Callback{
&&&&void&onShouldFinish();
}1.2 Xml布局,非常简单:&yifeiyuan.practice.practicedemos.drager.SwipeBackFrameLayout&
xmlns:android=&http://schemas.android.com/apk/res/android&&&&&
xmlns:tools=&http://schemas.android.com/tools&&&&&
android:id=&@+id/swipe_back&
android:layout_width=&match_parent&&&&&
android:layout_height=&match_parent&&&&&
tools:context=&yifeiyuan.practice.practicedemos.drager.SwipeBackActivity&&
&&&&&TextView
&&&&&&&&android:layout_width=&40dp&&&&&&&&&
&&&&&&&&android:layout_height=&match_parent&&&&&&&&&
&&&&&&&&android:text=&@string/hello_world&
&&&&&&&&android:gravity=&center&
&&&&&&&&android:background=&#ffff00&
&&&&&&&&/&
&&&&&&&&android:layout_width=&match_parent&&&&&&&&&
&&&&&&&&android:layout_height=&match_parent&
&&&&&&&&android:background=&#ff00ff&
&&&&&&&&/&
&/yifeiyuan.practice.practicedemos.drager.SwipeBackFrameLayout&1.3 实例化一个ViewDragHelper//1f代表灵敏度&
mDragHelper&=&ViewDragHelper.create(this,&1f,new&ViewDragHelper.Callback()&{
&&&&@Override
&&&&public&boolean&tryCaptureView(View&child,&int&pointerId)&{
&&&&&&&&return&
//因为我们是从左向右滑动&所以设置EDGE_LEFT
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);1.4 在SwipeBackFrameLayout里实例化xml里的子Viewprivate&View&mDividerV
private&View&mContentV
protected&void&onFinishInflate()&{
&&&&super.onFinishInflate();&
&&&mDividerView&=&getChildAt(0);
&&&&mDividerView.setAlpha(0f);
&&&&mContentView&=&getChildAt(1);
}1.5 让ViewDragHelper处理touch事件@Override
public&boolean&onInterceptTouchEvent(MotionEvent&ev)&{
&&&&return&mDragHelper.shouldInterceptTouchEvent(ev);
public&boolean&onTouchEvent(MotionEvent&event)&{&&&&
&&&&mDragHelper.processTouchEvent(event);
&&&&return&
}1.6重写ViewDragHelper的一些处理方法已附上详细注释@Override
public&void&onEdgeTouched(int&edgeFlags,&int&pointerId)&{&&&&
&&&&super.onEdgeTouched(edgeFlags,&pointerId);&
&&&//触摸到左边界的时候&我们capture住mContentView&&&&&&&&&&&
&&&&mDragHelper.captureChildView(mContentView,&pointerId);&
}&&&&&&&&&&&&
@Override&&&&&&&&&&&&
public&int&getViewHorizontalDragRange(View&child)&{
&&&&&&return&1;&&&&&&
@Override&
public&void&onViewPositionChanged(View&changedView,&int&left,&int&top,&int&dx,&int&dy)&{
&&&&&super.onViewPositionChanged(changedView,&left,&top,&dx,&dy);
&&&&&Log.d(TAG,&&onViewPositionChanged()&called&with&left&=&[&&+&left&+&&],&top&=&[&&+&top&+&&],&dx&=&[&&+&dx&+&&],&dy&=&[&&+&dy&+&&]&);&
&&&&&//0.0&-&1.0
&&&&&//Notice&这边可以给个接口回调出去,就可以做各种炫酷的效果了&&&&&&&&&&&&&&&&&&&&&
&&&&&float&alpha&=&(float)&(left*1.0/mDividerWidth);&&
&&&&&mDividerView.setAlpha(alpha);&&&&&&&&&&&&
&&&&&@Override
&&&&&public&int&clampViewPositionHorizontal(View&child,&int&left,&int&dx)&{
//&&&&&&&&&&&&&&&&Log.d(TAG,&&clampViewPositionHorizontal()&called&with&&dx&=&[&&+&dx&+&&]&);
&&&&&//&计算left&我们的目标范围是0-dividerwidth的宽度
&&&&&mLastdx&=&&
&&&&&int&newLeft&=&Math.min(mDividerWidth,&Math.max(left,0));&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&return&newL&
}&&&&&&&&&&&&
&&&&&@Override&&&&&&&&&&&&
&&&&&public&void&onViewReleased(View&releasedChild,&float&xvel,&float&yvel)&{&&&&&&&&&&&&&&&&
&&&&&//&0代表用户想关闭&&&&&&&&&&&&&&&&
&&&&&if&(mLastdx&0){
&&&&&//&还不到关闭条件,我们让view滑动过去,再关闭&&&&&&&&&&&&&&&&&&&&
&&&&&if&(mDividerWidth&!=&releasedChild.getLeft())&{&&&&
&&&&&&&mDragHelper.settleCapturedViewAt(mDividerWidth,releasedChild.getTop();
&&&&&&&invalidate();&
}&else&{&&&&
&&&&&if&(mCallback&!=&null)&{&&
&&&&&&&&&&mCallback.onShouldFinish();&&
&&&&&&}&&&&&
}else{&&&&&&&&&&&&
&&&&&&&&//用户不想关闭&,则滑动到最左边
&&&&&if&(mDividerWidth&!=&0)&{&&&
&&&&&&&&&&mDragHelper.settleCapturedViewAt(0,&releasedChild.getTop());&&
&&&&&&&&&&invalidate();&&
}&&&&&&&&&&&&
}&&&&&&&&&&&&
&&&&&@Override&&&&&&&&&&&&
&&&&&public&void&onViewDragStateChanged(int&state)&{&&
&&&&&&&&&&&&&&super.onViewDragStateChanged(state);&
//滑动停止,并且到达了滑动的判断条件&则回调关闭
if(mDragHelper.getViewDragState()==ViewDragHelper.STATE_IDLE&&mCallback&!=&null&&mDividerWidth==mContentView.getLeft()&&mLastdx&0)&{&&&&&&&&&&&&&&&&&&&&
mCallback.onShouldFinish();&
&&&&&&&&&&&&&&&}
&&&&&&&&&&&&}
&&&&&&&&});1.7 增加对view滑动事件处理,对于以上mDividerWidth我们在onLayout里获取private&int&mDividerW
protected&void&onLayout(boolean&changed,&int&left,&int&top,&int&right,&int&bottom)&{
&&&&super.onLayout(changed,&left,&top,&right,&bottom);
&&&&mDividerWidth&=&mDividerView.getWidth();
//Notice&view&刚初始化的时候就会被调用一次
&&&&@Override
&&&&public&void&computeScroll()&{
&&&&&&&&super.computeScroll();
&&&&&&//&&&&&&&&Log.d(TAG,&&computeScroll()&called&with&&&+&&&);&
&&&&if&(mDragHelper.continueSettling(true))&{
&&&&&&&&invalidate();
}我们写完自定义view后还需要自定义一下activity的退出动画~2.定义activity的finish动画2.1 在anim目录下,创建两个动画xml://no_anim
android:duration=&300&&&&&
xmlns:android=&http://schemas.android.com/apk/res/android&&&&&
android:fromAlpha=&1.0&
android:toAlpha=&1.0&
//out_to_right
&translate&&&&
xmlns:android=&http://schemas.android.com/apk/res/android&&&&&
android:duration=&300&&&&&
android:fromXDelta=&0%&&&&&
android:toXDelta=&100%&&&&&
&&/translate&2.2 在activity里设置callback监听,并运用动画mSwipeBack.setCallback(new&SwipeBackFrameLayout.Callback()&{&&&&
&&&&@Override
&&&&public&void&onShouldFinish()&{
&&&&&&&&finish();
&&&&&&&&overridePendingTransition(R.anim.no_anim,&R.anim.out_to_right);
});好了!!~代码量非常少!~就是这么简单~吐槽一下,简书对代码块的支持太差了,代码复制过来全是乱的!!同学们还是去看源码吧:源码在我的上如果你觉得喜欢,举手之劳,给我点个赞吧!~如果有什么不好的,不对的欢迎指出!~如果有什么更好的方式,也欢迎指导!!!!下次见!~关注我,联系我,交个朋友
上一篇: 原文: http://minxiaoming.com//NiceApp2/ GitHub: https://github.com/minxiaoming/NiceAppDemo 一、可以侧拉刷新加载的ViewPager 首先需要添加ViewPager,这个是一个可以侧拉加载刷新的ViewPager,这里最美使用的是GitHub上的一个开源项目: And
下一篇: 动态图: 设置 build.gradle中添加依赖 dependencies{...compilede.codecrafters.tableview:tableview:0.9.3...} 特性 Layouting 列数 所提供的TableView非常容易满足你的要求,只需在xml布局中设置属性就能设置列数。 de.codecrafters.tableview.TableViewaandroid 右滑返回的示例代码
转载 &更新时间:日 08:18:04 & 作者:沉寂chenji
本篇文章主要介绍了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跳转和销毁方法
public void startActivity(Intent intent) {
super.startActivity(intent);
overridePendingTransition(R.anim.slide_right_in, 0);
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
overridePendingTransition(R.anim.slide_right_in, 0);
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"/&
//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" /&
拦截右滑动作
所有的触摸事件通过activity.dispatchTouchEvent(MotionEvent ev)向view分发。
手指在X轴方向右滑动50~100px时,判断是否为(产品经理要)右滑动作
手指落点为全屏幕,X方向滑动距离要比Y方向的大一些;
手指落点为左侧边,X方向滑动距离有一些就行
private float downX = 0;
private float downY = 0;
private boolean shouldIntercept =
private boolean hadJudge =
public boolean dispatchTouchEvent(MotionEvent ev) {
if (shouldIntercept) {
return onTouchEvent(ev);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
downX = ev.getRawX();
downY = ev.getRawY();
hadJudge =
case MotionEvent.ACTION_MOVE: {
if (hadJudge)
if (ev.getRawX() == downX)
if (ev.getRawX() & downX) {
hadJudge =
if (ev.getRawX() - downX &=100){
//超出判断距离
hadJudge =
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 =
case MotionEvent.ACTION_UP: {
downY = 0;
shouldIntercept =
//Activity的默认分发
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
if (getWindow().superDispatchTouchEvent(ev)) {
根布局位移动画
根据手指滑动距离设置根布局偏移距离,用滑动距离和手指抬起时的速度判断是否返回
private View rootView =
private float lastX = -1;
private VelocityTracker velocityTracker =
private int maxFlingV
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();
case MotionEvent.ACTION_MOVE: {
if (lastX == -1) {
lastX = event.getRawX();
//根据手指滑动距离设置根布局偏移距离
rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX);
if (rootView.getTranslationX() & 0) rootView.setTranslationX(0);
lastX = event.getRawX();
case MotionEvent.ACTION_UP: {
//测量手指抬起时的速度
velocityTracker.computeCurrentVelocity(1000, maxFlingVelocity);
float velocityX = velocityTracker.getXVelocity();
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker =
//判断是否返回
if (downX & 50 && velocityX & 1000) {
//手指在左侧边落下,返回
} else if (velocityX & 3600) {
//手指快速滑动,返回
} else if (rootView.getTranslationX() & ConvertUtil.getWidthInPx() * 0.3) {
//滑动距离超过30%屏幕宽度,返回
//不返回,根布局偏移归零
rootView.animate().translationX(0).setDuration(200).start();
lastX = -1;
shouldIntercept =
downX = 0;
downY = 0;
return super.onTouchEvent(event);
添加左侧阴影
Activity的最顶层View为DecorView,DecorView是一个FrameLayout,里面只有一个Linearlayout,Linearlayout包含着标题栏和自定义布局(setContentView)。
上一步跟随手指滑动进行偏移的就是Linearlayout,现在要在DecorView里添加一个View,设置背景作为阴影,并跟随Linearlayout进行移动
private View shadowView =
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();
//根据手指滑动距离设置根布局偏移距离
rootView.setTranslationX(rootView.getTranslationX() + event.getRawX() - lastX);
if (rootView.getTranslationX() & 0) rootView.setTranslationX(0);
//阴影跟随根布局移动
shadowView.setTranslationX(-shadowView.getWidth()+rootView.getTranslationX());
lastX = event.getRawX();
case MotionEvent.ACTION_UP: {
//不返回,根布局偏移归零
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 =
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)
protected void onDestroy() {
super.onDestroy();
Activity_Stack.remove(this);
下层activity的退出、进入动画
private void lowerActivityExitAnim() {
if (rootView == null)
//只移动30%
rootView.animate().translationX(-ConvertUtil.getWidthInPx() * 0.3f).setDuration(300).start();
private void lowerActivityEnterAnim(float upperTranslationX) {
if (rootView == null)
//保证滑动退出时,上下层时间同步
float r = 1-upperTranslationX/ (float) ConvertUtil.getWidthInPx();
rootView.animate().translationX(0).setDuration((long) (300f * r)).start();
在跳转时,调用下层activity的退出、进入动画
public void startActivity(Intent intent) {
super.startActivity(intent);
overridePendingTransition(R.anim.slide_right_in, 0);
lowerActivityExitAnim();
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
overridePendingTransition(R.anim.slide_right_in, 0);
lowerActivityExitAnim();
public void finish() {
super.finish();
overridePendingTransition(0, R.anim.slide_right_out);
if (lastActivity != null) lastActivity.lowerActivityEnterAnim(rootView.getTranslationX());
Activity_Stack.remove(this);
上层activity滑动时关联下层滑动
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: {
//不返回,根布局偏移归零
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 =
private View rootView =
private View shadowView =
private float downX = 0;
private float downY = 0;
private boolean shouldIntercept =
private boolean hadJudge =
private float lastX = -1;
private VelocityTracker velocityTracker =
private int maxFlingV
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)
protected void onResume() {
initShadow();
super.onResume();
protected void onDestroy() {
super.onDestroy();
Activity_Stack.remove(this);
public void startActivity(Intent intent) {
super.startActivity(intent);
overridePendingTransition(R.anim.slide_right_in, 0);
lowerActivityExitAnim();
public void startActivityForResult(Intent intent, int requestCode) {
super.startActivityForResult(intent, requestCode);
overridePendingTransition(R.anim.slide_right_in, 0);
lowerActivityExitAnim();
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);
public boolean dispatchTouchEvent(MotionEvent ev) {
if (shouldIntercept) {
return onTouchEvent(ev);
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
downX = ev.getRawX();
downY = ev.getRawY();
hadJudge =
case MotionEvent.ACTION_MOVE: {
if (hadJudge)
if (ev.getRawX() == downX)
if (ev.getRawX() & downX) {
hadJudge =
if (ev.getRawX() - downX &= 100) {
//超出判断距离
hadJudge =
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 =
case MotionEvent.ACTION_UP: {
downX = 0;
downY = 0;
shouldIntercept =
hadJudge =
//Activity的默认分发
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
if (getWindow().superDispatchTouchEvent(ev)) {
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();
case MotionEvent.ACTION_MOVE: {
if (lastX == -1) {
lastX = event.getRawX();
//根据手指滑动距离设置根布局偏移距离
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();
case MotionEvent.ACTION_UP: {
//测量手指抬起时的速度
velocityTracker.computeCurrentVelocity(1000, maxFlingVelocity);
float velocityX = velocityTracker.getXVelocity();
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker =
//判断是否返回
if (downX & 50 && velocityX & 1000) {
//手指在左侧边落下,返回
} else if (velocityX & 3600) {
//手指快速滑动,返回
} else if (rootView.getTranslationX() & ConvertUtil.getWidthInPx() * 0.3) {
//滑动距离超过30%屏幕宽度,返回
//不返回,根布局偏移归零
rootView.animate().translationX(0).setDuration(200).start();
//阴影偏移归零
shadowView.animate().translationX(-shadowView.getWidth()).setDuration(200).start();
//下层activity偏移复原
if (lastActivity != null) lastActivity.lowerActivityExitAnim();
lastX = -1;
shouldIntercept =
hadJudge =
downX = 0;
downY = 0;
return super.onTouchEvent(event);
private void lowerActivityExitAnim() {
if (rootView == null)
rootView.animate().translationX(-ConvertUtil.getWidthInPx() * 0.3f).setDuration(300).start();
private void lowerActivityEnterAnim(float upperTranslationX) {
if (rootView == null)
float r = 1-upperTranslationX/ (float) ConvertUtil.getWidthInPx();
rootView.animate().translationX(0).setDuration(r == 0.0f ? 10 : (long) (300f * r)).start();
abstract public void onBack();
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 ios 关闭滑动返回 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信