Skip to content

Commit

Permalink
[FIX] 添加弹性dismiss的方式
Browse files Browse the repository at this point in the history
  • Loading branch information
sunyichao committed Oct 16, 2017
1 parent e8bd74f commit 8353854
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 19 deletions.
13 changes: 1 addition & 12 deletions app/src/main/java/cn/demo/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,7 @@ public void showImage(int position, String path, ImageView imageView) {
new CustomViewpagerAdapter(MainActivity.this))
.setIndex(3)
.setPaths(paths)
.setOnDestroyCallback(new OnDestroyCallback() {
@Override
public void onDestroy(int position) {
Toast.makeText(MainActivity.this, "OnDestroyCallback" + position, Toast.LENGTH_SHORT).show();
}
})
.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onChange(int position) {
Toast.makeText(MainActivity.this, "OnPageChangeListener" + position, Toast.LENGTH_SHORT).show();
}
})
.setExtraDismissType(ImageViewer.TYPE_ELASTIC_DIMISS)
.setTransformerType(ImageViewer.TYPE_ZOOMOUT_TRANSFORMER)
.build()
.show(getSupportFragmentManager(), "ImageViewer");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
package cn.imageviewer.dragable;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;

/**
* Created by cloudist on 2017/9/21.
*/

public class ElasticDismissListener implements View.OnTouchListener {

// Cached ViewConfiguration and system-wide constant values
private int mSlop;
private int mMinFlingVelocity;
private int mMaxFlingVelocity;
private long mAnimationTime;

// Fixed properties
private View mView;
private ElasticDismissListener.DismissCallbacks mCallbacks;
private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
private int mViewHeight = 1;

// Transient properties
private float mDownY;
private boolean mSwiping;
private VelocityTracker mVelocityTracker;
private float mTranslationX;
private float mTranslationY;
private int mWindowHeight;
private int mWindowWidth;

private boolean mTiltEnabled = true;

public interface DismissCallbacks {

boolean canSwipe();

void onDismiss(View view, boolean toTop);

void onSwiping(float degree);
}

public ElasticDismissListener( ElasticDismissListener.DismissCallbacks callbacks) {
mCallbacks = callbacks;
}

public void setView(View mView) {
this.mView = mView;
ViewConfiguration vc = ViewConfiguration.get(mView.getContext());

//getScaledTouchSlop是一个距离,表示滑动的时候,
// 手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件,如viewpager就是用这个距离来判断用户是否翻页
mSlop = vc.getScaledTouchSlop();
mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
mAnimationTime = mView.getContext().getResources().getInteger(
android.R.integer.config_shortAnimTime);

WindowManager wm = (WindowManager) mView.getContext()
.getSystemService(Context.WINDOW_SERVICE);
Point size = new Point();
wm.getDefaultDisplay().getSize(size);
mWindowHeight = size.y;
mWindowWidth = size.x;
}

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// offset because the view is translated during swipe
motionEvent.offsetLocation(mTranslationX, mTranslationY);

if (mViewWidth < 2) {
mViewWidth = mView.getWidth();
}

if (mViewHeight < 2) {
mViewHeight = mView.getHeight();
}

switch (motionEvent.getActionMasked()) {
// 一次ACTION_DOWN和ACTION_UP消费一次motionEvent
case MotionEvent.ACTION_DOWN: {
// 每一次手指按下,记为实例化一个 VelocityTracker
// VelocityTracker 是一个跟踪触摸事件滑动速度的帮助类,通过addMovement分析MotionEvent在单位时间类发生的位移来计算速度。
mDownY = motionEvent.getRawY();
// 这个token并木有用到
if (mCallbacks.canSwipe()) {
mVelocityTracker = VelocityTracker.obtain();
mVelocityTracker.addMovement(motionEvent);
}
return false;
}

case MotionEvent.ACTION_UP: {
if (mVelocityTracker == null) {
mView.performClick();
break;
}

//mDownX为起点,motionEvent.getRawX()为终点 deltaX为以前按压事件移动的距离
float deltaY = motionEvent.getRawY() - mDownY;
mVelocityTracker.addMovement(motionEvent);
// VelocityTracker先调用computeCurrentVelocity(int)来初始化速率的单位 。
mVelocityTracker.computeCurrentVelocity(1000);
// 横向速度
float velocityX = mVelocityTracker.getXVelocity();
float velocityY = mVelocityTracker.getYVelocity();
float absVelocityX = Math.abs(velocityX);
float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
boolean dismiss = false;
final boolean dismissTop;
// 当移动距离大于40 并且mSwiping时 进行dimiss操作
if (Math.abs(deltaY) > 40) {
dismiss = true;
// 如果deltaX > 0 向右dimiss
dismissTop = deltaY > 0;
} else if (mMinFlingVelocity <= absVelocityY && absVelocityY <= mMaxFlingVelocity
&& absVelocityY > absVelocityX && mSwiping) {
// 当速率方向与移动方向一致时 进行dimiss
dismiss = (velocityY < 0) == (deltaY < 0);
// 当速率>0时 向右dimiss
dismissTop = mVelocityTracker.getYVelocity() > 0;
} else {
dismissTop = false;
}

if (dismiss) {
// dismiss
mView.animate()
.translationY(dismissTop ? -mWindowHeight : mWindowHeight)
.setDuration(mAnimationTime)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
performDismiss(dismissTop);
}
});
mCallbacks.onSwiping(0);
// mSwiping指翻滚中 翻滚状态下如果不满足dimiss的操作 会停止动画 还原
} else if (mSwiping) {
// cancel
mView.animate()
.translationY(0)
.setDuration(mAnimationTime)
.setListener(null);
mCallbacks.onSwiping(1);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mTranslationY = 0;
mDownY = 0;
mSwiping = false;
break;
}

case MotionEvent.ACTION_CANCEL: {
//如果没走ACTION_DOWN 无视他
if (mVelocityTracker == null) {
mView.performClick();
break;
}

//停止动画 还原
mView.animate()
.translationY(0)
.setDuration(mAnimationTime)
.setListener(null);
mCallbacks.onSwiping(1);
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationY = 0;
mDownY = 0;
mSwiping = false;
break;
}

case MotionEvent.ACTION_MOVE: {
//如果没走ACTION_DOWN 无视他
if (mVelocityTracker == null) {
mView.performClick();
break;
}

mVelocityTracker.addMovement(motionEvent);
float deltaY = motionEvent.getRawY() - mDownY;
//如果x轴移动距离大于 离开控件的距离 并且Y轴移动小于x轴二分之一
if (Math.abs(deltaY) > mSlop) {
mSwiping = true;
mView.getParent().requestDisallowInterceptTouchEvent(true);

// Cancel listview's touch
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
(motionEvent.getActionIndex() <<
MotionEvent.ACTION_POINTER_INDEX_SHIFT));
mView.onTouchEvent(cancelEvent);
cancelEvent.recycle();
}
// 设置拖拽中的动画
if (mSwiping) {
mTranslationY = deltaY;
float moveY = Math.min(Math.abs(deltaY), 100) * (deltaY > 0 ? 1 : -1);
//设置左右偏移量
mView.setTranslationY(moveY / 3);
//设置透明度
float minAlpha = 1f - 2f * Math.abs(deltaY) / mViewHeight;
mCallbacks.onSwiping(Math.max(0f, Math.min(1f, minAlpha)));
return true;
}
break;
}
}
return false;
}

// 执行dimiss操作
private void performDismiss(final boolean toTop) {
final ViewGroup.LayoutParams lp = mView.getLayoutParams();
final int originalHeight = mView.getHeight();

ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);

animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//回调
mCallbacks.onDismiss(mView, toTop);
//重置View 如果你在onDismiss中dimiss了dialog是看不到效果的
mView.setTranslationX(0);
mView.setTranslationY(0);
lp.height = originalHeight;
mView.setLayoutParams(lp);
}
});

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
lp.height = (Integer) valueAnimator.getAnimatedValue();
mView.setLayoutParams(lp);
}
});

animator.start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

public class SwipeableFrameLayout extends FrameLayout {

private SwipeDismissTouchListener mTouchListener;
private SwipeDismissTouchListener mSwipeDismissTouchListener;
private ElasticDismissListener mElasticDismissListener;

public SwipeableFrameLayout(@NonNull Context context) {
super(context);
Expand All @@ -19,18 +20,32 @@ public SwipeableFrameLayout(@NonNull Context context, @Nullable AttributeSet att
super(context, attrs);
}

public void setSwipeDismissTouchListener(SwipeDismissTouchListener touchListener) {
mTouchListener = touchListener;
mTouchListener.setView(this);
setOnTouchListener(touchListener);
public void setSwipeDismissTouchListener(SwipeDismissTouchListener swipeDismissTouchListener) {
mSwipeDismissTouchListener = swipeDismissTouchListener;
mSwipeDismissTouchListener.setView(this);
setOnTouchListener(swipeDismissTouchListener);
setClickable(true);
}

public void setmElasticDismissListener(ElasticDismissListener elasticDismissListener) {
mElasticDismissListener = elasticDismissListener;
mElasticDismissListener.setView(this);
setOnTouchListener(mElasticDismissListener);
setClickable(true);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mTouchListener != null) {
if (mSwipeDismissTouchListener != null) {
//当有mTouchListener时 直接拦截onTouch事件
if (mSwipeDismissTouchListener.onTouch(this, ev)) {
return true;
}
}

if (mElasticDismissListener != null) {
//当有mTouchListener时 直接拦截onTouch事件
if (mTouchListener.onTouch(this, ev)) {
if (mElasticDismissListener.onTouch(this, ev)) {
return true;
}
}
Expand Down
21 changes: 21 additions & 0 deletions imageviewer/src/main/java/cn/imageviewer/view/ImageViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import cn.imageviewer.R;
import cn.imageviewer.adapter.ViewpagerAdapter;
import cn.imageviewer.dragable.ElasticDismissListener;
import cn.imageviewer.dragable.SwipeDismissTouchListener;
import cn.imageviewer.dragable.SwipeableFrameLayout;
import cn.imageviewer.helper.ImageLoader;
Expand All @@ -39,6 +40,7 @@ public class ImageViewer extends DialogFragment {

public static final int TYPE_NO_EXTRA_DIMISS = 2011;
public static final int TYPE_SWIPE_DIMISS = 2012;
public static final int TYPE_ELASTIC_DIMISS = 2013;

Window window;

Expand Down Expand Up @@ -87,6 +89,25 @@ public void onDismiss(View view) {
dismiss();
}

@Override
public void onSwiping(float degree) {
WindowManager.LayoutParams windowParams = window.getAttributes();
windowParams.dimAmount = 0.8f * degree;
window.setAttributes(windowParams);
}
}));
} else if (extraDismissType == TYPE_ELASTIC_DIMISS) {
layout.setmElasticDismissListener(new ElasticDismissListener(new ElasticDismissListener.DismissCallbacks() {
@Override
public boolean canSwipe() {
return true;
}

@Override
public void onDismiss(View view, boolean toTop) {
dismiss();
}

@Override
public void onSwiping(float degree) {
WindowManager.LayoutParams windowParams = window.getAttributes();
Expand Down

0 comments on commit 8353854

Please sign in to comment.