1、概述
*本文代码 非原创 来自于 一个 叫做NBAPlus的开源代码中.https://github.com/SilenceDut/NBAPlus 有兴趣的小伙伴们可以好好去了解下,推荐下,真™可以的~
2、简单描述下,所谓侧滑退出功能便是手指在界面左边或者右边滑动可以执行关闭界面的方法。换咱程序员的说话就是特么的:滑动
activity
执行finish
方法。
效果图:
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中了
图片:
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`.
* 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代码:http://download.csdn.net/detail/qq_33456552/9570882
路人葵:希望能帮助到有需求写这个功能的小伙伴们~~~
“`