Android右滑关闭当前Activity

时间:2021-10-20 23:40:59

转载请注明出处:meijian531161724


常常可以看到,很多Android应用都有这么一个功能,就是滑动关闭Activity,比如微信,CSDN移动端,百度贴吧移动端等。我自己也想写个滑动关闭Activity,最近事情没有那么多,我就google了一下,查看了一下实现滑动关闭Activity的实现方法,其中,有个思路,我觉得很不错,因此,在这里,我通过别人的思路,自己实现了一下滑动关闭Activity的方法,在此记录一下。

首先我们先看下实现效果:

Android右滑关闭当前Activity

      要写滑动关闭Activity,有几个问题要解决:

1.透明的显示底层的Activity。

2.边界检测,滑动视图,以及自动滚动。

3.阴影绘制。

一、透明的显示底层Activity,可以使用透明主题,也可以使用其他主题,但是必须修改主题的几个属性,来达到透明的效果,如:

[html] view plain copy
  1. <style name="AppTheme" parent="@style/Theme.AppCompat.Light">  
  2.     <item name="android:windowBackground">@android:color/transparent</item>  
  3. </style>  

二、谷歌在V4包中,增加ViewDragHelper类,这个类能够对滑动,边界检测,自动滚动等功能,提供了很好的实现。因此在这里我们选择ViewDragHelper来实现滑动功能。

三、阴影绘制,Paint画笔来绘制。我们选择在dispatchDraw()方法中绘制,为什么不用onDraw(),因为onDraw有时候在ViewGroup中不会执行。我们使用画笔的setShader(),通过写一个LinearGradient(),再绘制一个矩形,得到阴影效果。

最核心的原理就是在于,替换Window的DecorView下的LinearLayout。下面从代码直观的说明:

[java] view plain copy
  1.  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Context;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.BitmapShader;  
  8. import android.graphics.Canvas;  
  9. import android.graphics.Color;  
  10. import android.graphics.LinearGradient;  
  11. import android.graphics.Paint;  
  12. import android.graphics.RectF;  
  13. import android.graphics.Shader;  
  14. import android.support.v4.widget.ViewDragHelper;  
  15. import android.util.DisplayMetrics;  
  16. import android.view.MotionEvent;  
  17. import android.view.View;  
  18. import android.view.ViewGroup;  
  19. import android.widget.FrameLayout;  
  20.   
  21. import java.util.Map;  
  22.   
  23. /** 
  24.  * Created by FengJun on 2016/12/21. 
  25.  * 功能:当activity布局中嵌入当前布局,该activity可以从边缘滑动关闭 
  26.  * 实现原理: 
  27.  * 1.获取DecorView的RootView,删除RootView,把RootView添加到当前View 
  28.  * 再把当前View添加到DecorView 
  29.  */  
  30. public class SlideBackLayout extends FrameLayout {  
  31.     /**当前Activity的DecorView*/  
  32.     private ViewGroup mDecorView;  
  33.     /**DecorView下的LinearLayout*/  
  34.     private View mRootView;  
  35.     /**需要边缘滑动删除的Activity*/  
  36.     private Activity mActivity;  
  37.     /**Drag助手类*/  
  38.     private ViewDragHelper mViewDragHelper;  
  39.     /**触发退出当前Activity的宽度*/  
  40.     private float mSlideWidth;  
  41.     /**屏幕的宽和高*/  
  42.     private int mScreenWidth;  
  43.     private int mScreenHeight;  
  44.     /**画笔,用来绘制阴影效果*/  
  45.     private Paint mPaint;  
  46.     /**用于记录当前滑动距离*/  
  47.     private int curSlideX;  
  48.   
  49.   
  50.     public SlideBackLayout(Context context) {  
  51.         super(context);  
  52.         init(context);  
  53.     }  
  54.   
  55.     private void init(Context context) {  
  56.         //必须是传入Activity  
  57.         mActivity = (Activity) context;  
  58.         //构造ViewDragHelper  
  59.         mViewDragHelper = ViewDragHelper.create(thisnew DragCallback());  
  60.         //设置从左边缘捕捉View  
  61.         mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);  
  62.         //初始化画笔  
  63.         mPaint = new Paint();  
  64.         mPaint.setStrokeWidth(2);  
  65.         mPaint.setAntiAlias(true);  
  66.         mPaint.setColor(Color.GRAY);  
  67.     }  
  68.   
  69.     //绑定方法,在Activity的DecorView下插入当前ViewGroup,原来的RootView放于当前ViewGroup下  
  70.     public void bind() {  
  71.         mDecorView = (ViewGroup) mActivity.getWindow().getDecorView();  
  72.         mRootView = mDecorView.getChildAt(0);  
  73.         mDecorView.removeView(mRootView);  
  74.         this.addView(mRootView);  
  75.         mDecorView.addView(this);  
  76.   
  77.         //计算屏幕宽度  
  78.         DisplayMetrics dm = new DisplayMetrics();  
  79.         mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);  
  80.         mScreenWidth = dm.widthPixels;  
  81.         mScreenHeight = dm.heightPixels;  
  82.         mSlideWidth = dm.widthPixels *0.28f;  
  83.     }  
  84.   
  85.     @Override  
  86.     public boolean onInterceptHoverEvent(MotionEvent event) {  
  87.         return mViewDragHelper.shouldInterceptTouchEvent(event);  
  88.     }  
  89.   
  90.     @Override  
  91.     public boolean onTouchEvent(MotionEvent event) {  
  92.         mViewDragHelper.processTouchEvent(event);  
  93.         return true;  
  94.     }  
  95.   
  96.     class DragCallback extends ViewDragHelper.Callback {  
  97.   
  98.         @Override  
  99.         public boolean tryCaptureView(View child, int pointerId) {  
  100.             return false;  
  101.         }  
  102.   
  103.         @Override  
  104.         public void onViewReleased(View releasedChild, float xvel, float yvel) {  
  105.             //当前回调,松开手时触发,比较触发条件和当前的滑动距离  
  106.             int left = releasedChild.getLeft();  
  107.             if (left <= mSlideWidth) {  
  108.                 //缓慢滑动的方法,小于触发条件,滚回去  
  109.                 mViewDragHelper.settleCapturedViewAt(00);  
  110.             } else {  
  111.                 //大于触发条件,滚出去...  
  112.                 mViewDragHelper.settleCapturedViewAt(mScreenWidth, 0);  
  113.             }  
  114.             //需要手动调用更新界面的方法  
  115.             invalidate();  
  116.   
  117.         }  
  118.   
  119.         @Override  
  120.         public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {  
  121.             curSlideX = left;  
  122.             //当滑动位置改变时,刷新View,绘制新的阴影位置  
  123.             invalidate();  
  124.             //当滚动位置到达屏幕最右边,则关掉Activity  
  125.             if (changedView == mRootView && left >= mScreenWidth) {  
  126.                 mActivity.finish();  
  127.             }  
  128.         }  
  129.   
  130.         @Override  
  131.         public int clampViewPositionHorizontal(View child, int left, int dx) {  
  132.             //限制左右拖拽的位移  
  133.             left = left >= 0 ? left : 0;  
  134.             return left;  
  135.         }  
  136.   
  137.         @Override  
  138.         public int clampViewPositionVertical(View child, int top, int dy) {  
  139.             //上下不能移动,返回0  
  140.             return 0;  
  141.         }  
  142.   
  143.         @Override  
  144.         public void onEdgeDragStarted(int edgeFlags, int pointerId) {  
  145.             //触发边缘时,主动捕捉mRootView  
  146.             mViewDragHelper.captureChildView(mRootView, pointerId);  
  147.         }  
  148.     }  
  149.   
  150.   
  151.     @Override  
  152.     public void computeScroll() {  
  153.         //使用settleCapturedViewAt方法是,必须重写computeScroll方法,传入true  
  154.         //持续滚动期间,不断刷新ViewGroup  
  155.         if (mViewDragHelper.continueSettling(true))  
  156.             invalidate();  
  157.   
  158.     }  
  159.   
  160.     @Override  
  161.     protected void dispatchDraw(Canvas canvas) {  
  162.         //进行阴影绘制,onDraw()方法在ViewGroup中不一定会执行  
  163.         drawShadow(canvas);  
  164.         super.dispatchDraw(canvas);  
  165.   
  166.     }  
  167.   
  168.   
  169.     private void drawShadow(Canvas canvas) {  
  170.         canvas.save();  
  171.         //构造一个渐变  
  172.         Shader mShader = new LinearGradient(curSlideX - 400, curSlideX, 0new int[]{Color.parseColor("#1edddddd"), Color.parseColor("#6e666666"), Color.parseColor("#9e666666")}, null, Shader.TileMode.REPEAT);  
  173.         //设置着色器  
  174.         mPaint.setShader(mShader);  
  175.         //绘制时,注意向左边偏移  
  176.         RectF rectF = new RectF(curSlideX - 400, curSlideX, mScreenHeight);  
  177.         canvas.drawRect(rectF, mPaint);  
  178.         canvas.restore();  
  179.     }  
  180.   
  181.   
  182. }  

我在代码中,进行详细的注释。总体来说,不难理解。我们在使用的时候,在布局文件中,一定要在根布局设置背景颜色,否则整个布局将会是透明的。下面是使用方法:

[java] view plain copy
  1.  
  2.   
  3. import android.support.v7.app.AppCompatActivity;  
  4. import android.os.Bundle;  
  5. import android.widget.TextView;  
  6.   
  7. import com.mjc.slidebackdemo.view.SlideBackLayout;  
  8.   
  9. /** 
  10.  * 从左侧边缘向右滑动可以关闭当前页面 
  11.  */  
  12. public class SecondActivity extends AppCompatActivity {  
  13.   
  14.     private TextView tv;  
  15.     private SlideBackLayout mSlideBackLayout;  
  16.   
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.activity_main);  
  21.         mSlideBackLayout = new SlideBackLayout(this);  
  22.         mSlideBackLayout.bind();  
  23.         tv = (TextView) findViewById(R.id.tv);  
  24.     }  
  25. }  

哪个Activity需要滑动关闭的功能,只需要实例化一个SlideBackLayout对象,并调用bind()方法。这样,我们就实现了滑动关闭的效果了。

项目地址:https://github.com/AndStuFeng/SlideBackDemo

建议API 22以上