最近发现越来越多的app中使用到侧滑返回的功能,比如微信,今日头条等等。于是我自己去实现这个功能,博客不罗嗦 尽可能的简洁一些
源码地址:https://github.com/bangbangqiu/SliddingBack.git
自定义view继承字FrameLayout,嵌套在activity的布局的最外层,作为滑动的view。重写onInterceptTouchEvent()方法拦截滑动事件,在onTouchEvent中根据滑动距离调用View的scroolTo()方法。手指松开 计算滑动速度和滑动距离是否达到activity销毁的大小,并提供销毁的回调方法。在Style.xml中配置activity的样式位背景透明
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//如果点击距离屏幕左边界10dp,触发返回销毁activity
float x = ev.getX();
Log.d(TAG, "onInterceptTouchEvent: x:" + ev.getX());
if (!isOpen) return false;
if (x < dp2px(sliddingLength)) {
//注意: 即使拦截 ACTION_DOWN 也会执行一次
isInterupt = true;
} else {
isInterupt = false;
}
return isInterupt;
}
如果按下的点在滑动的区域内就 return true 拦截事件,交给onTouchEvent()处理
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "onTouchEvent: x:" + event.getX() + "y: " + event.getY());
Log.d(TAG, "onTouchEvent: downX:" + downPoint.x + "downY: " + downPoint.y);
Log.d(TAG, "onTouchEvent: currentX:" + currentPoint.x + "currentY: " + currentPoint.y);
//当 isInterrupt==false 或者不在拦截区域 进行拦截
if (!isInterupt || downPoint.x > dp2px(sliddingLength)) {
Log.d(TAG, "onTouchEvent: 拦截==================");
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "onTouchEvent: ACTION_DOWN");
currentPoint.x = downPoint.x = (int) event.getX();
currentPoint.y = downPoint.y = (int) event.getY();
startTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_MOVE:
// Log.d(TAG, "onTouchEvent: ACTION_MOVE");
//滑动操作
speed = (int) ((event.getX() - currentPoint.x) / (System.currentTimeMillis() - startTime) * 1000);
Log.d(TAG, "onTouchEvent: speed: " + speed);
scrollTo(downPoint.x - currentPoint.x, 0);
currentPoint.x = (int) event.getX();
currentPoint.y = (int) event.getY();
startTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "onTouchEvent: ACTION_UP_CANCEL");
int x = (int) event.getX();
//如果速度达到了,并且是正值,负数代表反方向
if (speed > 1000) {
finish();
return true;
}
if (x < 0.3 * widthPixels || speed < -1000) {
// Toast.makeText(getContext(), "距离不够activity不销毁", Toast.LENGTH_SHORT).show();
backActivityListenner.onSliddingOver(false);
backAnimation(currentPoint.x, 0);
} else {
// Toast.makeText(getContext(), "距离达到activity销毁", Toast.LENGTH_SHORT).show();
finish();
}
//初始化
downPoint.set(1, 0);
currentPoint.set(0, 0);
break;
}
return true;
}
不多说了,都在代码中了。完成这两个方法就可以 滑动了
添加动画和绘制引用
//回复动画
public void backAnimation(final int xStart, final int xEnd) {
final ValueAnimator animator = ValueAnimator.ofInt(xStart, xEnd);
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
scrollTo(-animatedValue, 0);
Log.d(TAG, "onAnimationUpdate: " + animatedValue);
if (animatedValue == xEnd) {
animator.removeUpdateListener(this);
}
}
});
animator.setDuration(duration);
animator.start();
}
通过valueAnimator根据值的渐变做动画,记得完成动画后移除监听,防止内存泄漏。
@Override
protected void onDraw(Canvas canvas) {
//绘制阴影
Log.d(TAG, "onDraw: width " + getWidth());
canvas.drawRect(shaderRectF, fillPaint);
super.onDraw(canvas);
}
public interface BackActivityListenner {
void onSliddingOver(boolean canBack);
}
public Point getCurrentPoint() {
return currentPoint;
}
写的第一篇博客献丑了,技术含量不高