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" />
好了,就是以上這些代碼,如果有左右滑動的控件,記得在外面設置進去。有問題的話歡迎留言~接下來我要去完成我的目標了,嘿嘿