[android]手把手通过一个类实现侧滑退出activity功能


1、概述#

*本文代码 非原创 来自于 一个 叫做NBAPlus的开源代码中.https://github.com/SilenceDut/NBAPlus 有兴趣的小伙伴们可以好好去了解下,推荐下,真™可以的~

2、简单描述下,所谓侧滑退出功能便是手指在界面左边或者右边滑动可以执行关闭界面的方法。换咱程序员的说话就是特么的:滑动 activity执行finish方法。


效果图:#

侧滑退出.gif

2、主要实现方法#

通过ViewDragHelper来检测到屏幕侧滑,然后通过内置接口传递给acitivity触发了侧滑事件,通知其关闭。

额,就是这么简单明了的一句概况了。

来来来代码代码看代码~喵了个巴拉的,具体细节看代码。因为感觉写太多细节的话,我自己都懒得去看。(咳咳……不是我懒不是我懒……嗯的,就是这样。)

3、代码#

1、实现侧滑删除,这里的方法是先要创建一个监听侧滑的自定义布局.####


public class SwipeBackLayout extends FrameLayout {  

     //自定义控件 必备俩个构造函数
     public SwipeBackLayout(Context context) {
        this(context, null);//引用俩个参数的构造方法,目的是将三个构造方法连接起来.
     }
     public SwipeBackLayout(Context context, AttributeSet attrs) {     
        this(context, attrs, 0); //引用三个参数的构造方法
     }  
      public SwipeBackLayout(Context context, AttributeSet attrs, int  defStyleAttr) {     
        super(context, attrs, defStyleAttr); 
        init();//写个初始化方法,等下在里面实现 viewDragHelper,已经一些初始化操作
     }
}

2、哎哎哎,憋打我,容我在墨迹下,咱分析下要用到的属性。。。####

  • 1、首先TAG属性,好吧,其实并没有什么ruan用。打印Log用的。
    private static final String TAG = "SwipeBackLayout" ;
  • 2、都说ViewDragHelper实现的了,所以ViewDraghelper要有吧?总要知道滑动哪个view吧?view的宽度也得测量出来吧?是不是关闭也得知道吧?竟然要通知Activity那回调函数得来一个吧?侧滑得有阴影吧?透明度得控制下吧?……
   //于是乎……就有了这么一丢丢的属性……
   private ViewDragHelper mViewDragHelper;
   private View mContentView;
   private int mContentWidth;
   private int mMoveLeft;
   private boolean isClose = false;
   private boolean isEdgeDrag=false;
   private CallBack mCallBack;//自定义内部的回调函数,下面写
   private Drawable mShadowLeft;
   private static final int FULL_ALPHA = 255;
   private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
   private int mScrimColor = DEFAULT_SCRIM_COLOR;
   private float mScrimOpacity;
   private float mScrollPercent;
   private Rect mTmpRect = new Rect();
  • 3、上面的属性中有个回调接口,我们这个接口主要就是通知acitivity什么时候关闭咯,那一个关闭的方法就ok了好的就不偷懒了,万一有和我一样的萌新看呢,贴上个代码
//界面移出屏幕时接口回调
public interface CallBack { 
   void onFinish();//这个就可以直接用了咯,然后在acitiviy中实例化接口
}
//设置回调接口,提供给activity实现接口
public void setCallBack(CallBack callBack) {
    mCallBack = callBack;
}

3、属性既然定义好了,咱就把刚init()中的方法内容贴出来吧。就是在这货里面实现的viewGragHelper的!####

//初始化方法private  void init(){ 

   //ViewDragHelper 需要用到的回调函数有点多哈,这里不介绍了。哈。那个啥大家可以多研究下,百度上资料也是千篇一律的。
   mViewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {   
         //返回true表示可以拖动     
         @Override     
         public boolean tryCaptureView(View child, int pointerId) {   
             return child == mContentView;//如果child==mContentView,返回true,也就是说mContentView可以移动    
         }        

          //记录值的变化      
          @Override       
          public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {          
              //记录左边的值的变化,因为我们实现的是往右滑动,所以只记录左边的值就可以了         
              mScrollPercent = Math.abs((float) left/ (mContentView.getWidth() + mShadowLeft.getIntrinsicWidth()));
              mMoveLeft = left; 
              if (isClose && (left == mContentWidth)) {
              //如果当前状态是关闭状态且左边的值等于滑动的View的宽度,                
              //也就是说当前的界面已经滑出屏幕,就回调finish方法,通知activity可以finish了             
              mCallBack.onFinish();      
              }
          }

          //手指松开会触发这个方法,做复位操作就在此方法中实现      
          @Override   
          public void onViewReleased(View releasedChild, float xvel, float yvel) {           
                   //一定得重写computeScroll()方法,不然没有效果          
                   //如果移动的距离大于或等于当前界面的1/10,则触发关闭     
                   if (mMoveLeft >= (mContentWidth / 10)) {       
                             isClose = true;  //设置滑动的View移动位置,即然当前的界面滑出屏幕                
                             mViewDragHelper.settleCapturedViewAt(mContentWidth, releasedChild.getTop());
                    } else {   
                            //设置滑动的View移动位置,即恢复原来的位置       
                            mViewDragHelper.settleCapturedViewAt(0, releasedChild.getTop());
                    }            
                  //通知重绘界面       
                   invalidate();  
      }     
  
           //重新定位水平移动的位置     
           @Override      
           public int clampViewPositionHorizontal(View child, int left, int dx) {            
            //水平移动距离的范围是0~当前界面的宽度,如果left小于0直接返回0,            
            // 如果大于当前界面的宽度直接返回当前界面宽度  
            //也就是控制当前界面只能往右移动         
               return Math.min(mContentWidth, Math.max(left, 0));       
           }      
  
            //设置水平拖动的距离   
            @Override   
            public int getViewHorizontalDragRange(View child) {  
                  //因为我们移动的是整个界面,所以直接返回整个界面的宽度就可以了          
                  return mContentWidth;      
           }      
 
            @Override  
             public void onEdgeTouched(int edgeFlags, int pointerId) {            super.onEdgeTouched(edgeFlags, pointerId);  
                       isEdgeDrag = true;   
              } 
            });    
             mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);      
             setShadow();//设置侧滑的边框,这个方法的代码下面写哈

}

4、init()方法已经写好了,里面有几个init要用到的方法贴出来吧####

  • 1、第一个重写的computeScroll方法,要不然onViewReleased会没效果。
@Override
public void computeScroll() {  
  super.computeScroll();    
  mScrimOpacity=1-mScrollPercent;
    //一定要做这个操作,否则onViewReleased不起作用   
  if (mViewDragHelper!=null&&mViewDragHelper.continueSettling(true)) {      
   invalidate();  
  }
}

  • 2、然后就是setShadow()设置阴影的方法,侧滑时哪条灰不溜秋的线。为啥要?美呀! --图片资源我放在res目录下的mipmap中了

图片:

shadow_left.png
public void setShadow() { 
      mShadowLeft=getResources().getDrawable(R.mipmap.shadow_left);    
      invalidate();
}
  • 3、写了这么多,总要获取咱要滑动的那个布局吧。也就是上面咱定义的那个mContentView这个属性.
@Override
protected void onFinishInflate() {  
  super.onFinishInflate();   
  //SwipeBackFrameLayout的子View有且只有一个,否则抛异常    
  if (getChildCount() != 1) {    
    throw new IllegalStateException("SwipeBackFrameLayout must host one child.");
    }
    //取得当前布局的第一个子View,也是唯一一个子View
    //也就是activity的主要布局
    mContentView = getChildAt(0);
}

  • 4、我们在到onLayout()中测量下mContentView宽度.
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {    
   super.onLayout(changed, left, top, right, bottom);    //获取当前界面宽度 
   mContentWidth = mContentView.getWidth();
}
  • 5、啊哟我去,还有一个很重要的步骤!脑抽的我没把触摸事件给viewDragHelper,如果没触摸事件还监听侧滑个……P呀.
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { 
   //把事件传递给
   ViewDragHelper 
   return mViewDragHelper.shouldInterceptTouchEvent(ev);
 }
  @Override
  public boolean onTouchEvent(MotionEvent event) {  
     //把事件传递给ViewDragHelper    
      mViewDragHelper.processTouchEvent(event);  
      invalidate();   
    return true;
  }
  • 6、最后设置了半天,还没画效果呀。画一下画一下,啥阴影呀,透明度呀……
//画一个子项 ,到时候把acitivity的主题设置下就可以看到下面的activity了
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {    
      final boolean drawContent = child == mContentView;   
      boolean ret = super.drawChild(canvas, child, drawingTime);  
      if (drawContent && mViewDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {      
            drawShadow(canvas, child);  
            drawScrim(canvas, child); 
       }  
       return ret;
 }
   //这个是那个阴影线
   private void drawShadow(Canvas canvas, View child) {   
             final Rect childRect = mTmpRect;    
             child.getHitRect(childRect);    
             mShadowLeft.setBounds(childRect.left - mShadowLeft.getIntrinsicWidth(), childRect.top,childRect.left, childRect.bottom);
             mShadowLeft.setAlpha((int) (mScrimOpacity * FULL_ALPHA));    mShadowLeft.draw(canvas);
 }
    //这个就是画那个透明渐变出来的帷幕,还真™不知道怎么形容
    private void drawScrim(Canvas canvas, View child) {  
             final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;    final int alpha = (int) (baseAlpha * mScrimOpacity);
             final int color = alpha << 24 | (mScrimColor & 0xffffff);    
             canvas.clipRect(0, 0, child.getLeft(), getHeight());    
             canvas.drawColor(color);
 }
  • 7、没7了。。。到了这里 自定义的SwipeDragLayout就写完了~~~可以用了哦!

4、 使用:三步走

  • 1、先把activity变成主题模式变透明的哦
      //设置下theme属性就好啦
      <activity 
          android:name=".BActivity"  
          android:theme="@style/AppTheme.TransparentActivity"    />```

>>* 2、需要侧滑退出的`activity`的布局文件中嵌套上咱得自定义`SwipeBackLayout`.

<?xml version="1.0" encoding="utf-8"?>
<com.sunflower812.SwipeBackLayout
android:id="@+id/swipe_layout_two"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#00eeaa" />
</com.sunflower812.SwipeBackLayout>

* 3、Ok!!!最后一步是什么呢~尼玛就是应用了呗。在`activity`中得到侧滑退出布局,设置他的回调接口.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b); //找到控件
//设置回调,然后就没然后了~~~
SwipeBackLayout swipeBackLayoutTwo = (SwipeBackLayout) findViewById(R.id.swipe_layout_two);
swipeBackLayoutTwo.setCallBack(new SwipeBackLayout.CallBack() {
@Override
public void onFinish() {
finish();
}
});
}

* 4、哦!对了。很重要的就是。。自己写个页面跳转过来吧~调转到设置了滑动退出的这个页面。然后效果就实现了,侧滑退出!

>#结尾:#
* 附带DEMO代码:[Sunflower812博客--侧滑退出activity测试代码](http://download.csdn.net/detail/qq_33456552/9570882)

路人葵:希望能帮助到有需求写这个功能的小伙伴们~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容