hello大家好,2018快结束了,掐指一算才发现自己才写了两篇博客,年初定下的目标也只完成了一半。不是不想写,只是不知道写些什么,不过好在快把《明朝那些事儿》看完了,有兴趣的话我们一起交流交流吧~
说会正题,最近项目提了一个新需求,就是在界面上实现全屏右滑返回效果。老板说,这个效果别人APP都有,我们也要。IOS端倒好,系统提供了侧滑返回事件,只需监听屏幕滑动位置来回调侧滑返回事件即可实现效果。没办法,既然都提了肯定有办法解决。老规矩,先来看看我的实现效果吧:
其实已经有人已经写好了,效果还非常的不错,感兴趣的可以Star一下:SwipeBackLayout
其实实现起来非常简单,只需要获取当前屏幕的DecorView,然后监听dispatchTouchEvent事件,来根据滑动距离来偏移DecorView,当左右滑动的时候禁用ScrollView的上下滑动。可能你们已经发现了,顶部还有一个轮播图控件,这样一来不会造成滑动冲突吗?答案是会的,但是我们可以通过按下的位置来判断当前按下的是否是设置忽略的控件。来看代码吧,注释很详细,我相信你能看懂~
**
* Created by fySpring
* Date : 2018-11-15
* To do :继承你的BaseActivity,或者直接继承AppCompatActivity
*/
public class BaseSlideActivity extends BaseActivity {
//该控件子控件中包含ConvenientBanner的集合 ,也可以放别的控件
private List<ConvenientBanner> mViewPagers = new LinkedList<>();
View decorView;
int screenWidth;//屏宽
CustomScrollView combineSv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获取屏幕的宽度以及底层的View
decorView = getWindow().getDecorView();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels;
}
float startX, startY, endX, endY, distanceX, distanceY;
//当前按下的是ConvenientBanner
boolean isTouchC = false;
//当前按下的是ScrollView
boolean isTouchS = false;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
ConvenientBanner cb = getTouchViewPager(event);
if (cb != null) {
//当前按下的是ConvenientBanner,不拦截
isTouchC = true;
isTouchS = false;
return super.dispatchTouchEvent(event);
} else {
isTouchC = false;
isTouchS = true;
}
break;
case MotionEvent.ACTION_MOVE:
endX = event.getX();
endY = event.getY();
distanceX = endX - startX;
distanceY = Math.abs(endY - startY);
if (isTouchC) {
//当手指移动过程中,按下的是ConvenientBanner,不能进行屏幕偏移
return super.dispatchTouchEvent(event);
} else {
//1.判断手势右滑 2.横向滑动的距离要大于竖向滑动的距离
if (endX - startX > 0 && distanceY < distanceX && isTouchS) {
decorView.setX(distanceX);
//禁用ScrollView的竖直滑动事件
if (combineSv != null) combineSv.setScrollFlag(true);
}
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (isTouchC) {
isTouchC = false;
return super.dispatchTouchEvent(event);
} else {
isTouchS = false;
endX = event.getX();
distanceX = endX - startX;
endY = event.getY();
distanceY = Math.abs(endY - startY);
//1.判断手势右滑 2.横向滑动的距离要大于竖向滑动的距离 3.横向滑动距离大于屏幕三分之一才能finish
if (endX - startX > 0 && distanceY < distanceX && distanceX > screenWidth / 3) {
moveOn(distanceX);
} else if (endX - startX > 0 && distanceY < distanceX) {
//1.判断手势右滑 2.横向滑动的距离要大于竖向滑动的距离 但是横向滑动距离不够则返回原位置
backOrigin(distanceX);
} else {
decorView.setX(0);
}
if (combineSv != null) combineSv.setScrollFlag(false);
}
break;
}
return super.dispatchTouchEvent(event);
}
/**
* 设置忽略左滑的ConvenientBanner控件
*/
public void setViewPagers(List<ConvenientBanner> mViewPagers) {
this.mViewPagers = mViewPagers;
}
public void setCombineSv(CustomScrollView combineSv) {
this.combineSv = combineSv;
}
/**
* 通过点击的位置判断是否等于我所设置的控件位置
*
* @param ev 触摸事件
* @return 当前触摸的ConvenientBanner
*/
private ConvenientBanner getTouchViewPager(MotionEvent ev) {
if (mViewPagers == null || mViewPagers.isEmpty()) {
return null;
}
Rect mRect = new Rect();
int[] location = new int[2];
for (ConvenientBanner v : mViewPagers) {
v.getLocationInWindow(location);
mRect.set(location[0], location[1], location[0] + v.getMeasuredWidth(), location[1] + v.getMeasuredHeight());
if (mRect.contains((int) ev.getX(), (int) ev.getY())) {
return v;
}
}
return null;
}
/**
* 返回原点
*
* @param distanceX 横向滑动距离
*/
private void backOrigin(float distanceX) {
ObjectAnimator.ofFloat(decorView, "X", distanceX, 0).setDuration(300).start();
}
/**
* 划出屏幕
*
* @param distanceX 横向滑动距离
*/
private void moveOn(float distanceX) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(distanceX, screenWidth);
valueAnimator.setDuration(300);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
decorView.setX((Float) animation.getAnimatedValue());
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
finish();
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
}
记得为你的Activity设置一个透明主题。
<style name="SlideTheme" parent="AppTheme">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowIsTranslucent">true</item>
</style>
<activity
android:name=".activities.GoodsDetailActivity"
android:theme="@style/SlideTheme" />
好了,就是以上这些代码,如果有左右滑动的控件,记得在外面设置进去。有问题的话欢迎留言~接下来我要去完成我的目标了,嘿嘿