Coder Social home page Coder Social logo

and_swipeback's Introduction

SwipeBack

利用滑动手势退出当前Activity

License maven--central

Features

  • 不需要设置透明theme或windowIsTranslucent = true
  • 不影响activity的生命周期
  • 只需继承SwipeBackActivity
  • 支持Dialog的滑动返回

Getting started

Firstly,add the following lines to your app/build.gradle.

dependencies {  
    compile 'com.aitangba:swipeback:1.0.3'
}

Secondly, add the following lines to your application.

public class CustomApplication extends Application{

    @Override
    public void onCreate() {
        super.onCreate();
        registerActivityLifecycleCallbacks(ActivityLifecycleHelper.build());
    }

}

Finally, set the activity which need to swipe extends the SwipeBackActivity.

public class BaseActivity extends SwipeBackActivity {

}

Usage

API

Application在Api14之后添加了新的Callback方法

    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {

    }

这样就可以根据activity的生命周期缓存所有Activity,通过list获取上一个activity的实例,从而获取id为content的ContentView的子View(即setContentView中的View),并进行滑动展示。

默认SwipeBackActivity是支持滑动返回的,不需要滑动返回时则需要复写SwipeBackActivity的方法supportSlideBack,其中方法canBeSlideBack意思是能否返回至本Activity;两个方法相互配合使用,以应对各种需求。

 
   public class SwipeBackActivity extends AppCompatActivity implements SwipeBackHelper.SlideBackManager {

    private SwipeBackHelper mSwipeBackHelper;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!supportSlideBack()) {
            return super.dispatchTouchEvent(ev);
        }
        if (mSwipeBackHelper == null) {
            mSwipeBackHelper = new SwipeBackHelper(this, new SlideActivityAdapter());
			// 滑动返回触发finish
            mSwipeBackHelper.setOnSlideFinishListener(new SwipeBackHelper.OnSlideFinishListener() {
                @Override
                public void onFinish() {
                    SwipeBackActivity.this.finish();
                    overridePendingTransition(android.R.anim.fade_in, R.anim.hold_on);
                }
            });
        }
        return mSwipeBackHelper.processTouchEvent(ev) || super.dispatchTouchEvent(ev);
    }

    @Override
    public void finish() {
        if (mSwipeBackHelper != null) {
            mSwipeBackHelper.finishSwipeImmediately();
        }
        super.finish();
    }

    @Override
    public boolean supportSlideBack() {
        return true;
    }

    @Override
    public boolean canBeSlideBack() {
        return true;
    }
		
	// 独立获取上一个Activity
    private static class SlideActivityAdapter implements SlideActivityCallback {

        @Override
        public Activity getPreviousActivity() {
            return ActivityLifecycleHelper.getPreviousActivity();
        }
    }
}

6种事件状态

    private static final int STATE_ACTION_DOWN = 1; //点击事件
    private static final int STATE_ACTION_UP = 2;  //点击结束
    private static final int STATE_BACK_START = 3; //开始滑动,不返回前一个页面
    private static final int STATE_BACK_FINISH = 4;  //结束滑动,不返回前一个页面
    private static final int STATE_FORWARD_START = 5; //开始滑动,返回前一个页面
    private static final int STATE_FORWARD_FINISH = 6;//结束滑动,返回前一个页面
  1. 在Down手势发生时,只要将上一个Activity的ContentView从parentView中剥离,并加入到当前View的ContentView中;
  2. 在滑动手势发生时,加上阴影View,并进行滑动;同时滑动的有当前Activity的ContentView、上一个Activity的ContentView和自定义的阴影View;
  3. 在Up手势发生时,判断滑动是否超过屏幕1/4,触发返回操作,并展示滑动动画;
  4. 滑动取消或滑动返回发生时,需要将上个Activity的ContentView从新加入到上一个Acitivity的布局中。

Tips:
在设计过程中遇到也有过其他思路:
1)设置Activity的透明theme,可是发现只要activity的层级变多就会变得非常卡顿;
2)动态设置Activity的theme,这需要通过反射,而且还需要判断api,部分手机还不兼容;
3)在滑动展示上个Activity的View时,直接将上个Activity的contentView截图保存在内存卡上,然后显示在当前Activity的view上,但是有明显的卡顿感;
以上都是在设计过程中想到的方案,也逐个实践了一下,发现问题还是比较多的,想想还不如另辟蹊径,就有了现在的方案,目前看来还是能兼容大部分手机的。

ScreenShot

image

Update

  • 1.0.1
    添加接口SlideBackManager;
    修正手势判断,仅在可滑动区域进行滑动手势判断,不干扰点击或长按事件;
    修复由于其他多线程在滑动页面进行中时,调用finish方法导致异常发生的问题

  • 1.0.2
    优化库中类的结构;
    为兼容高德地图的滑动事件,在触发滑动事件时,通知底层View的取消当前的点击或滑动事件;

  • 1.0.3
    SwipeBackHelper去除继承hanhler;
    优化SwipeBackHelper代码结构,将涉及View的操作和动画、手势​代码分离;
    兼容当前Activity和上一个Activity Theme 不同的情况(由于StatusBar的高度产生的高度差)

License

Copyright 2016-2019 XBeats

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

and_swipeback's People

Contributors

xbeats avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

and_swipeback's Issues

[Bug fix] Fix bug case flickering on Oreo

Google has confirmed it's a bug in Android 8.0, presumably fixed in 8.1. So the "empty animation" fix is for years, until minSdkVersion == 27.

  1. create empty anim xml under /anim folder:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

</set>
  1. replace 0 to animation_activity_none:
activity.overridePendingTransition(R.anim.animation_activity_none, R.anim.animation_activity_none);

Bug fix!

NestedScrollView自动上滑

A界面是NestedScrollView布局,
1.引入的是com.aitangba:swipeback:1.0.2这个版本,返回A界面的时候会自动上滑一部分
2.引入的是com.aitangba:swipeback:1.0.1这个版本,A界面返回前一个界面的的时候A界面也会上滑一部分

作者可以写两个NestedScrollView布局的Activity来回切换测试。

StatusBar Color Issue

状态栏是个问题.如果两个activity状态栏不一样的话...效果并不好,另外如果当前页面设置了fifSystemWindow..也不是很好,不过这样的方式是个很棒的思路!

ShadowView的构造函数报空指针

在360崩溃日志系统看到的
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference at android.view.ViewConfiguration.get(ViewConfiguration.java:359) at android.view.View.(View.java:3646) at com.aitangba.swipeback.ShadowView.(ShadowView.java:18) at com.aitangba.swipeback.SwipeBackHelper$ViewManager.addShadowView(SwipeBackHelper.java:443) at com.aitangba.swipeback.SwipeBackHelper$ViewManager.access$300(SwipeBackHelper.java:375) at com.aitangba.swipeback.SwipeBackHelper.handleMessage(SwipeBackHelper.java:205) at android.os.Handler.dispatchMessage(Handler.java:111) at android.os.Looper.loop(Looper.java:224) at android.app.ActivityThread.main(ActivityThread.java:5911) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1113) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:879)

多进程栈底的ativity无效

谢谢你的开源代码 我发现些问题 多进程栈底的activity无效 ,还有设置了intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);也会导致无效 有没有好 的解决思路或方法

两三个页面的情况下,快速连续滑动返回会崩溃

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setX(float)' on a null object reference
at com.aitangba.swipeback.SwipeBackHelper$ViewManager.translateViews(SwipeBackHelper.java:388)
at com.aitangba.swipeback.SwipeBackHelper$ViewManager.access$300(SwipeBackHelper.java:268)
at com.aitangba.swipeback.SwipeBackHelper.setTranslationX(SwipeBackHelper.java:209)
at com.aitangba.swipeback.SwipeBackHelper.processTouchEvent(SwipeBackHelper.java:111)
at cn.kunming.common.activity.SwipeBackActivity.dispatchTouchEvent(SwipeBackActivity.java:33)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:69)
at com.android.internal.policy.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2405)
at android.view.View.dispatchPointerEvent(View.java:9548)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4515)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4313)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3823)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3883)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3842)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3990)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3850)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4047)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3823)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3883)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3842)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3850)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3823)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6239)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6213)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6174)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6346)
at android.view.ViewRootImpl$ColorWindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7598)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:176)
at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:6313)
at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:6369)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:862)
at android.view.Choreographer.doCallbacks(Choreographer.java:674)
at android.view.Choreographer.doFrame(Choreographer.java:604)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:848)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:179)
at android.app.ActivityThread.main(ActivityThread.java:5769)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674)

如果上个页面控件存在Toolbar,屏幕旋转后导致Toolbar高度不变

首先竖屏首页
截图
跳转至滑动页
截图
旋转屏幕至横屏
截图
回到横屏时的首页
截图

你可以发现在横屏做侧滑时Toolbar的高度还是竖屏时的Toolbar高度;当你真正返回到首页发现横屏的Toolbar其实变小了;然后我如果一开始首页是横屏的话,跳转到侧滑页然后旋转至竖屏后Toolbar高度还是一开始横屏的高度;所以就是说人为添加到侧滑页的页面的Toolbar在屏幕旋转时Activity重建后出现异常

性能问题

这个思路的话,每个Activity都要添加上一个的ContentView,性能方面会不会有影响?

几个问题

1:如果我在侧边栏中,点击View,进入新的Activity,此时滑动返回,下层的界面并不是侧边栏,而是Activity,可能这和你实现的方式有关,DecorView。。。
2:滑动冲突:侧边栏无法滑动展开了,,当然这个可以解决
3:还是因为使用了DecorView,导致首页的几个Tab点击时会时不时报null。。。
4:StatusBar问题,不能很好地兼容沉浸式,由于项目的需要,其中有两种沉浸式实现,但是侧滑库只能兼容其中一种,另一种没办法兼容,而且会导致低层Activity的状态栏高度X2。。

沉浸式状态栏

�如果两个节目的状态栏颜色不一样,滑动的效果并不友好,有解决思路吗

没有效果

我的华为荣耀4x和p9Plus都没有效果,直接下载运行的,是不是还要配置下

Fragment 支持

如果你打开 overDraw 的话,应该能看出来 微信 的UI部分使用了Fragment(比如会话界面),同样支持侧滑返回,并且背景界面也会在侧滑的时候跟随做视差滑动,如果使用 ActivityLifecycleCallback,则没法追踪 fragment 的界面。
不过微信的侧滑返回应该是混合了很多种方式,比如有些其他进程的界面的侧滑,应该就是普通的透明背景加 Swipebacklayout。
你的这种实现方式很有意思,感觉就算 activity 栈销毁重建也不会影响 侧滑返回,而且也没有 Swipebacklayout 的性能问题。
https://github.com/29995270/WechatSwipeBack
我也有做一个实现,但是没法处理 activity 栈被销毁的问题,也很难实际应用。

背景页显示问题

一个activity隐藏了actionbar,另一个activity没有隐藏actionbar,此时从没有隐藏actionbar的activity滑动返回过程中,actionbar不能跟着滑动,背景页面会显示在actionbar下边,根布局为CoordinatorLayout时背景页会显示在状态栏中

actionbar显示空白

当前Activity没有使用actionbar ,上一个Activity使用了actionbar,这时候右滑返回上一页时,actionbar 显示空白,只有当上一个 Activity 完全显示出来时,actionbar重绘了才有东西,重绘之前都是空白。

目前出现的滑动闪屏的一个解决方法

首先在AppTheme的Style里面加上这句话

<item name="android:windowIsTranslucent">true</item>

加上以解决闪屏问题,可能动画会失效,这个时候需要给窗口增加动画,也就是在style中加上

<item name="android:windowAnimationStyle">@style/Animation.Activity.Translucent.Style</item>

而这个的动画风格具体实现又是这个

<style name="Animation.Activity.Translucent.Style" parent="@android:style/Animation.Translucent">
<item name="android:windowEnterAnimation">@anim/slide_in_from_right</item>
<item name="android:windowExitAnimation">@anim/slide_out_to_right</item>
</style>

slide_in_from_right具体如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromXDelta="100%p"
android:toXDelta="0" />
</set>

slide_out_to_right具体如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="200"
android:fromXDelta="0"
android:toXDelta="100%p" />
</set>

style修改以后,如果不出意外,那么会在手势左滑返回时多一次返回窗口动画,这个动画具体内容页面就是上一层的Activity的视图,到这里之后要修改源码了,将SwipeBackHelper的handleMessage函数中的 case MSG_SLIDE_FINISHED:修改成以下代码

mViewManager.removeShadowView();
mViewManager.resetPreviousView();
mActivity.finish();

修改完毕之后,是不是左滑还有一个灰色背景或白色背景?这个就是属于窗口的背景了,所以最后只需要 在Style中加入一句

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

再试试,是不是效果完成?不保证百分百兼容,只是作为一个参考供大家使用。

使用Monkey测试时发现一个问题

App集成这个滑动返回库后,在Monkey测试时发现一个问题 。

// android.content.res.Resources$NotFoundException: File res/drawable-xxhdpi-v4/welcome.png from drawable resource ID #0x7f020191: .xml extension required

// 	at android.content.res.Resources.loadColorStateListForCookie(Resources.java:2808)

// 	at android.content.res.Resources.loadColorStateList(Resources.java:2749)

// 	at android.content.res.TypedArray.getColor(TypedArray.java:441)

// 	at com.aitangba.swipeback.SwipeBackHelper.getWindowBackgroundColor(SwipeBackHelper.java:269)

// 	at com.aitangba.swipeback.SwipeBackHelper.handleMessage(SwipeBackHelper.java:210)

// 	at android.os.Handler.dispatchMessage(Handler.java:102)

// 	at android.os.Looper.loop(Looper.java:148)

// 	at android.app.ActivityThread.main(ActivityThread.java:5438)

// 	at java.lang.reflect.Method.invoke(Native Method)

// 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)

// 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)

过快滑动出现闪屏的情况

我司测试发现的,迅速从左往右一扫,页面会先白屏一下,再加载上一个activity,这个如何解决下?

java.lang.NullPointerException Attempt to invoke interface method 'boolean java.util.List.contains(java.lang.Object)' on a null object reference hg.zp.ui.ui.activity.WelcomeActivity.onDestroy(WelcomeActivity.java:108)

 java.lang.NullPointerException
 Attempt to invoke interface method 'boolean java.util.List.contains(java.lang.Object)' on a null object reference
 hg.zp.ui.ui.activity.WelcomeActivity.onDestroy(WelcomeActivity.java:108)
 .......
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
 Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'boolean      java.util.List.contains(java.lang.Object)' on a null object reference
 	at com.aitangba.swipeback.ActivityLifecycleHelper.onActivityDestroyed(ActivityLifecycleHelper.java:64)
at android.app.Application.dispatchActivityDestroyed(Application.java:569)
at android.app.Activity.dispatchActivityDestroyed(Activity.java:1446)
at android.app.Activity.onDestroy(Activity.java:2660)

.............

ActionBar的问题。

如果存在ActionBar,ActionBar不会移动。

发现你这种实现方案挺新颖的,解决了设置Activity背景透明生命周期导致的性能问题。

为什么采用Handler的机制

基于该库做了一些修改,例如加入滑动触发的判断.目前的情况是左边的一些按钮无法触发.
改完后发现因为Handler和事件分发有时候会造成时序的混乱.直接把SwipeWindowHelper去除了继承Handler.
想问下当时是基于什么情况下考虑使用Handler.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.