SwipeBackLayout的用法屏幕移动退出

SwipeBackLayou的简单使用

下载arr包

https://download.csdn.net/download/qq_35427437/10414355

如果想要可以评论或关注

这是5.0以后的新特性(此功能好像在低版本有问题,5.0以上没有黑屏)

使用步骤如下:

1、导入SwipeBackActivity库

2、让当前activity继承于SwipeBackActivity

3、//测拉关闭的控件

private SwipeBackLayout mSwipeBackLayout;
mSwipeBackLayout = getSwipeBackLayout();

4、//设置activity的关闭模式

int edgeFlag = SwipeBackLayout.EDGE_RIGHT;          
int edgeFlag = SwipeBackLayout.EDGE_BOTTOM;
int edgeFlag = SwipeBackLayout.EDGE_ALL;

int edgeFlag = SwipeBackLayout.EDGE_LEFT;

滑动关闭当前页面的方向有四种形式 
* 1.SwipeBackLayout.EDGE_RIGHT 右边关闭页面 
* 2.SwipeBackLayout.EDGE_LEFT 左边关闭页面 
* 3.SwipeBackLayout.EDGE_BOTTOM 底部关闭页面 
* 4.SwipeBackLayout.EDGE_ALL 以上三种形式关闭页面 

//以上有四种模式可供选择

5、mSwipeBackLayout.setEdgeTrackingEnabled(edgeFlag);//设置选择使用什么模式

6、//如何避免低版本的滑动黑屏现象??
//把应用的theme设置为透明<!--设置窗口透明,避免滑动时是黑的-->
<item name="android:windowIsTranslucent">true</item>

//主activity设置为不透明<!--设置主界面不透明,避免主界面上的界面在滑动时可以看到桌面-->
 <item name="android:windowIsTranslucent">false</item>

 

Style设置

 

<style name="AppBackTheme"  parent="@style/AppTheme">
        <item name="android:windowIsTranslucent">true</item>
    </style>

在AndroidManifest.xml里面调用

  <activity android:name=".news.activity.DetailActivity" android:theme="@style/AppBackTheme"></activity>

 

 

SwipeBackLayout源码分析

public class SwipeBackLayout extends FrameLayout {
     /**
      * SwipeBackLayout的主布局
      */
     private View mContentView;
     /**
      * 是一个距离,表示滑动的时候手的移动要大于这个距离才开始移动    控件。如果小于这个距离就不触发移动控件,
      * 如 viewpager就是用这个距离来判断用户是否翻页,这个距离打印出来是16px
      */
     private int mTouchSlop;
     /**
      * 手指点击屏幕时的Y坐标
      */
     private int downY;
     /**
      * 手指点击屏幕时的X坐标
      */
     private int downX;
     /**
      * 手指点击屏幕时,临时的X坐标
      */
     private int tempX;
     /**
      * Android里 Scroller类是为了实现View平滑滚动的一个Helper类
      */
     private Scroller mScroller;
     /**
      * 手机屏幕的宽度
      */
     private int viewWidth;
     /**
      * 表示屏幕是否正在滑动的标记
      */
     private boolean isSilding;
     /**
      * 表示是否finish掉当前的activity
      */
     private boolean isFinish;
     /**
      * 获取系统资源的 drawable文件,带有阴影的
      */
     private Drawable mShadowDrawable;
     /**
      * SwipeBackLayout依附的activity
      */
     private Activity mActivity;
     /**
      * 当前activity里所存在的 viewpager的集合
      */
     private List<viewpager> mViewPagers = new LinkedList<viewpager>();// 创建一个空的 viewpager的集合
     /**
      * 是否对手势进行拦截的设置,默认为true。若为false,则SwipeBackLayout这个 viewgroup对手势不拦截不消费
      */
     private boolean mEnable = true;
 
     public SwipeBackLayout(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
     }
 
     public SwipeBackLayout(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); // 是一个距离,表示滑动的时候手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件,如 viewpager就是用这个距离来判断用户是否翻页
           Log. d("xiao" , "mTouchSlop:" + mTouchSlop );
            mScroller = new Scroller(context); // Android里Scroller 类是为了实现View平滑滚动的一个Helper类
            mShadowDrawable = getResources().getDrawable(R.drawable.shadow_left );// 获取系统资源的 drawable文件
     }
 
     /**
      * 把swipeBackLayout附加到指定的activity中,放到 decor顶层窗口下,decorChild上
      * 这样做的作用就是,让SwipeBackLayout附加到任何activity时,就立于此activity主视图之上
      *
      * @param activity
      */
     public void attachToActivity(Activity activity) {
            mActivity = activity; // 传进来的activity
            int[] attrs = new int[] { android.R.attr.windowBackground };
            // 返回一个与主题Theme定义的 attrs数组对应的typedArray类型数组
           TypedArray a = activity.getTheme().obtainStyledAttributes(attrs);
            // 获取typedArray数组中指定位置的资源id值
            int background = a.getResourceId(0, 0);
            // 回收TypedArray类型数组
           a.recycle();
            // 返回顶层窗口装饰视图
           ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
            // 返回装饰视图的指定位置的view,就是 decor的child,很形象
           ViewGroup decorChild = (ViewGroup) decor.getChildAt(0);
            // 给顶层窗口装饰视图的第一个子视图设置背景资源,
            // background就是上面获得的android.R.attr.windowBackground
           decorChild.setBackgroundResource(background);
            // decor顶层窗口装饰视图移除decorChild,杀了他的儿子
           decor.removeView(decorChild);
            // 这个应该是给SwipeBackLayout添加子view,因为SwipeBackLayout继承自FrameLayout
            // 这时,SwipeBackLayout就是decorChild的父布局了
            this.addView(decorChild);
            // 把decorChild当成SwipeBackLayout的contentView进行设置
            this.setContentView(decorChild);
            // 然后给decor添加一个子view,这个this就是SwipeBackLayout
           decor.addView( this);
     }
 
     /**
      * 设置主布局视图
      *
      * @param decorChild
      */
     private void setContentView(View decorChild) {
            mContentView = (View) decorChild.getParent(); // 返回decorChild的父布局,这个时候父布局就是SwipeBackLayout
     }
 
     /**
      * 设置手势
      *
      * @param enable
      */
     public void setEnableGesture( boolean enable) {
            mEnable = enable;
     }
 
     /**
      * 事件拦截操作
      */
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
            if (! mEnable) {
                 // false表示不拦截
                 return false;
           }
 
            // 处理ViewPager冲突问题
           ViewPager mViewPager = getTouchViewPager( mViewPagers, ev);// 获取到触摸地方的 viewpager
 
            if (mViewPager != null && mViewPager.getCurrentItem() != 0) {
                 // 当viewpager 不为空且viewpager不处在第一个item时,swipeBackLayout就不拦截
                 return super.onInterceptTouchEvent(ev); // 默认返回false,表示不拦截
           }
 
            switch (ev.getAction()) {
            case MotionEvent. ACTION_DOWN:
                 downX = tempX = ( int) ev.getRawX(); // 当点击时候的X坐标
                 downY = ( int) ev.getRawY(); // 当点击时候的Y坐标
                 break;
            case MotionEvent. ACTION_MOVE:
                 int moveX = ( int) ev.getRawX();
                 // 满足此条件屏蔽SildingFinishLayout里面子类的touch事件
                 if (moveX - downX > mTouchSlop
                           && Math. abs((int) ev.getRawY() - downY) < mTouchSlop) {
                      // 当水平移动的距离大于16px,且竖直方向的移动距离小于16px时,SwipeBackLayout拦截此次触摸事件
                      // 就是说当手指move的时候,满足上述条件时,触摸事件就会被SwipeBackLayout的onInterceptTouchEvent方法拦截
                      // 继而传递给SwipeBackLayout的onTouchEvent方法
                      return true;
                }
                 break;
           }
 
            return super.onInterceptTouchEvent(ev);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
            if (! mEnable) {
                 return false;
           }
 
            switch (event.getAction()) {
            case MotionEvent. ACTION_MOVE:
                 int moveX = ( int) event.getRawX(); // 移动后的X坐标
                 int deltaX = tempX - moveX; // 这个是点击时和移动后,X坐标差值
                Log. d("xiao" , "deltaX:" + deltaX);// 右滑为负值
                 tempX = moveX; // 给tempX重新赋值
                 if (moveX - downX > mTouchSlop
                           && Math. abs((int) event.getRawY() - downY) < mTouchSlop) {
                      // 满足上述条件时,触摸事件由onInterceptTouchEvent传递至onTouchEvent方法中
                      isSilding = true; // 标记为正在滑动
                }
 
                 if (moveX - downX >= 0 && isSilding) {
                      // 当右滑且处于正在滑动的时候,主布局通过scrollBy整体移动,且通过打印deltaX为负值
                      mContentView.scrollBy(deltaX, 0);
                }
                 break;
            case MotionEvent. ACTION_UP:
                 isSilding = false; // 讲滑动标记设置为false
                Log. d("xiaok" , "mContentView:" + mContentView.getScrollX());
                Log. d("xiaok" , "viewWidth:" + viewWidth );
                 if ( mContentView.getScrollX() <= - viewWidth / 2) {
                      // 当右滑距离超过屏幕宽度的一半时,标记isFinish为true表示滚动出界面,然后滚动出界面
                      isFinish = true;
                     scrollRight();
                } else {
                      // 否则界面回滚至原点,标记isFinish为false
                     scrollOrigin();
                      isFinish = false;
                }
                 break;
           }
            return true;
     }
 
     /**
      * 获取SwipeBackLayout里面的ViewPager的集合,这里用到的好像是递归思想
      *
      * @param mViewPagers
      * @param parent
      */
     private void getAlLViewPager(List<viewpager> mViewPagers, ViewGroup parent) {
            int childCount = parent.getChildCount();
            for ( int i = 0; i < childCount; i++) {
                View child = parent.getChildAt(i);
                 if (child instanceof ViewPager) {
                     mViewPagers.add((ViewPager) child);
                } else if (child instanceof ViewGroup) {
                     getAlLViewPager(mViewPagers, (ViewGroup) child);
                }
           }
     }
 
     /**
      * 返回我们touch的ViewPager
      *
      * @param mViewPagers
      * @param ev
      * @return
      */
     private ViewPager getTouchViewPager(List<viewpager> mViewPagers,
                MotionEvent ev) {
            if (mViewPagers == null || mViewPagers.size() == 0) {
                 // 如果mViewPagers集合为空,或者mViewPagers的size=0,那么直接返回空
                 return null;
           }
           Rect mRect = new Rect(); // 创建一个新的空矩形。所有坐标被初始化为0。
            for (ViewPager v : mViewPagers) { // 遍历mViewPagers集合,判断我现在触摸的地方是不是在某一个 viewpager范围里
                                                            // 如果在,那么就返回这个 viewpager
                v.getHitRect(mRect); // 获取每一个viewpager的矩形的坐标值,并赋值给mRect矩形
 
                 if (mRect.contains(( int) ev.getX(), ( int) ev.getY())) {
                      // 返回true,如果(x,y)坐标在mRect矩形的范围内
                      return v; // 返回viewpager
                }
           }
            return null; // 否则返回空
     }
 
     @Override
     protected void onLayout( boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
            // 不明白为什么onLayout方法执行了两次
           Log. d("xiao" , "changed:" + changed);
            if (changed) {
                 viewWidth = this.getWidth();
                Log. d("xiao" , "viewWidth:" + viewWidth );
                getAlLViewPager( mViewPagers, this); // 获得SwipeBackLayout中的ViewPager的集合
           }
     }
 
     @Override
     protected void dispatchDraw(Canvas canvas) { // 当需要绘制子view的时候,才会调用此方法
            super.dispatchDraw(canvas);
            /**
            * 这个方法是用来绘制右滑退出时,SwipeBackLayout左侧的那个阴影效果
            */
            if ( mShadowDrawable != null && mContentView != null) {
 
                 int left = mContentView.getLeft()
                           - mShadowDrawable.getIntrinsicWidth();
                 int right = left + mShadowDrawable.getIntrinsicWidth();
                 int top = mContentView.getTop();
                 int bottom = mContentView.getBottom();
 
                 mShadowDrawable.setBounds(left, top, right, bottom);
                 mShadowDrawable.draw(canvas);
           }
 
     }
 
     /**
      * 滚动出界面
      */
     private void scrollRight() {
            /**
            * 这里解释下getScrollX的意思:返回视图左边缘的X坐标,但是是反向的X轴,就是值是相反的
            */
            final int delta = ( viewWidth + mContentView.getScrollX());
            /**
            * 调用startScroll方法来设置一些滚动的参数,我们在computeScroll()方法中调用scrollTo来滚动item
            * 当 dx的值为正数时view向左滑动
            */
           Log. d("xiao" , "delta:" + delta);
            mScroller.startScroll( mContentView.getScrollX(), 0, -delta + 1, 0,
                     Math. abs(delta));
           postInvalidate();
     }
 
     /**
      * 滚动到起始位置
      */
     private void scrollOrigin() {
 
            int delta = mContentView.getScrollX();
           Log. d("xiao" , "1delta:" + delta);
            mScroller.startScroll( mContentView.getScrollX(), 0, -delta, 0,
                     Math. abs(delta));
           postInvalidate();
     }
 
     @Override
     public void computeScroll() {
            /**
            * 当我们执行 ontouch或invalidate()或postInvalidate()都会导致这个copmuteScroll方法的执行
            * 所以底下加一个判断,computeSrcollOffset是在startScroll方法启动时就会返回true
            */
 
            // 调用startScroll的时候scroller.computeScrollOffset()返回true,从文字上理解是计算偏移量
            if ( mScroller.computeScrollOffset()) {
                 mContentView.scrollTo( mScroller.getCurrX(), mScroller.getCurrY());
                 postInvalidate();
 
                 if ( mScroller.isFinished() && isFinish) { //
                      // 当滑动结束,且当前view滑动出界面时,执行activity,finish的命令
                      mActivity.finish();
                }
           }
     }
}
</viewpager></viewpager></viewpager></viewpager>

 

SwipeBackLayout 是一个支持屏幕上下左右滑动返回上层 Activity, 关闭当前 Activity, 类似简书 App。效果图:示例代码:public class DemoActivity extends SwipeBackActivity implements View.OnClickListener {     private int[] mBgColors;     private static int mBgIndex = 0;     private String mKeyTrackingMode;     private RadioGroup mTrackingModeGroup;     private SwipeBackLayout mSwipeBackLayout;     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_demo);         changeActionBarColor();         findViews();         mKeyTrackingMode = getString(R.string.key_tracking_mode);         mSwipeBackLayout = getSwipeBackLayout();         mTrackingModeGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {             @Override             public void onCheckedChanged(RadioGroup group, int checkedId) {                 int edgeFlag;                 switch (checkedId) {                     case R.id.mode_left:                         edgeFlag = SwipeBackLayout.EDGE_LEFT;                         break;                     case R.id.mode_right:                         edgeFlag = SwipeBackLayout.EDGE_RIGHT;                         break;                     case R.id.mode_bottom:                         edgeFlag = SwipeBackLayout.EDGE_BOTTOM;                         break;                     default:                         edgeFlag = SwipeBackLayout.EDGE_ALL;                 }                 mSwipeBackLayout.setEdgeTrackingEnabled(edgeFlag);                 saveTrackingMode(edgeFlag);             }         });     }
### 回答1: 如果 Android 侧滑返回无效,可以尝试以下解决方案: 1. 确保当前所在的界面已经设置了 `android:windowIsTranslucent=false` 和 `android:fitsSystemWindows=true`。这两个属性会让系统留出空间来显示返回按钮。 2. 在当前界面的布局文件中,确保当前界面的根布局使用了 `DrawerLayout` 或者 `androidx.drawerlayout.widget.DrawerLayout`,并且已经为这个 `DrawerLayout` 设置了 `android:id="@+id/drawer_layout"`。 3. 在当前界面的 `Activity` 中,重写 `onOptionsItemSelected()` 方法,并且在方法中处理返回按钮的点击事件。 ```java @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { // 在这里处理返回按钮的点击事件 finish(); return true; } return super.onOptionsItemSelected(item); } ``` 4. 在当前界面的 `Activity` 中,调用 `setSupportActionBar()` 方法,并设置 `ActionBar` 的一个返回按钮。 ```java ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } ``` 5. 在当前界面的布局文件中,确保当前界面的根布局使用了 `SwipeBackLayout` 或者 `com.github.ikew0ng.SwipeBackLayout`。 6. 在当前界面的 `Activity` 中,调用 `SwipeBackLayout` 的 `setEdgeTrackingEnabled()` 方法,并设置参数为 `SwipeBackLayout.EDGE_LEFT`。 ```java SwipeBackLayout swipeBackLayout = find ### 回答2: Android侧滑返回无效可能有以下几个原因: 1. 手机系统不支持侧滑返回:某些早期版本的Android系统可能没有内置侧滑返回功能。如果你的手机系统较旧,可能无法使用这个功能。 2. 手机设置问题:侧滑返回功能可能在手机设置中被禁用。你可以在手机设置中找到"手势"或"导航栏"选项,并确保侧滑返回功能已开启。 3. 第三方应用冲突:如果你安装了某些修改了系统导航栏的应用或定制了界面的应用,可能会影响到侧滑返回功能的正常使用。尝试卸载或禁用这些应用,然后查看侧滑返回是否恢复正常。 4. 应用本身不支持侧滑返回:并不是所有的应用都支持侧滑返回功能。尤其是在使用一些老旧的应用或者某些自定义界面的应用时,侧滑返回可能无效。试试在其他应用中进行侧滑返回操作,看是否只是在特定应用中无效。 如果出现以上问题,你可以尝试以下方法解决侧滑返回无效的问题: 1. 更新手机系统:如果你的手机系统较老,尝试更新到最新版本的Android系统。 2. 检查手机设置:确保侧滑返回功能在手机设置中已开启。 3. 检查第三方应用冲突:禁用或卸载可能与侧滑返回功能冲突的第三方应用,然后重新尝试侧滑返回。 4. 尝试其他应用:如果只有特定应用中无效,尝试在其他应用中进行侧滑返回操作,看是否只是在该应用中无效。 如果以上方法都无效,可能需要考虑重置手机设置或者联系手机厂商客服进行进一步的帮助和支持。 ### 回答3: Android侧滑返回无效可能是由多种原因造成的。以下是可能导致侧滑返回无效的常见问题及解决方法: 1. 设置问题:首先,确保在系统设置中已启用了侧滑返回功能。有些Android设备在出厂时可能默认关闭了此功能,需要手动打开。进入"设置"菜单,在"系统"或"手势"选项中找到"侧滑返回",确保此选项已开启。 2. 应用限制:某些应用程序可能会限制侧滑返回功能,特别是游戏或多媒体应用。在这种情况下,无法在该应用中使用侧滑返回功能。尝试在其他应用或主屏幕上进行侧滑操作,看是否正常工作。 3. 第三方应用冲突:有时,已安装的第三方应用可能会干扰侧滑返回功能。尝试在安全模式下启动设备,这将禁用所有第三方应用。如果在安全模式下可以正常使用侧滑返回功能,则证明某个应用程序引起了冲突。您可以尝试卸载最近安装的应用程序或使用逐一排除法确定冲突的应用程序。 4. 触摸屏幕问题:如果设备的触摸屏幕出现故障或损坏,可能会导致侧滑返回无效。请尝试在其他部分屏幕上进行滑动操作,看是否也无效。如果其他滑动操作正常,请联系厂家或维修中心进行设备维修或更换触摸屏幕。 通过检查以上可能的问题和解决方法,您应该能够解决Android侧滑返回无效的问题。如果问题仍然存在,建议尝试更新系统或联系设备制造商获取进一步支持和帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达帮主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值