Created
March 21, 2017 11:26
-
-
Save fatihsokmen/7a3d5b1853d62e50339a004365fe1a63 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.annotation.SuppressLint; | |
import android.annotation.TargetApi; | |
import android.content.Context; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.v4.view.MotionEventCompat; | |
import android.support.v4.view.ViewCompat; | |
import android.support.v4.widget.ViewDragHelper; | |
import android.support.v4.widget.ViewDragHelper.Callback; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.view.ViewConfiguration; | |
import android.widget.FrameLayout; | |
public class PullDismissViewLayout extends FrameLayout { | |
private ViewDragHelper dragHelper; | |
private float minFlingVelocity; | |
private PullDismissViewLayout.Listener listener; | |
public PullDismissViewLayout(@NonNull Context context) { | |
super(context); | |
init(context); | |
} | |
public PullDismissViewLayout(@NonNull Context context, @Nullable AttributeSet attrs) { | |
super(context, attrs); | |
init(context); | |
} | |
public PullDismissViewLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
init(context); | |
} | |
@TargetApi(21) | |
public PullDismissViewLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle, int defResStyle) { | |
super(context, attrs, defStyle, defResStyle); | |
init(context); | |
} | |
private void init(@NonNull Context context) { | |
if (!this.isInEditMode()) { | |
ViewConfiguration vc = ViewConfiguration.get(context); | |
this.minFlingVelocity = (float) vc.getScaledMinimumFlingVelocity(); | |
this.dragHelper = ViewDragHelper.create(this, new PullDismissViewLayout.ViewDragCallback()); | |
} | |
} | |
public void setMinFlingVelocity(float minFlingVelocity) { | |
this.minFlingVelocity = minFlingVelocity; | |
} | |
public float getMinFlingVelocity() { | |
return this.minFlingVelocity; | |
} | |
public void setListener(PullDismissViewLayout.Listener listener) { | |
this.listener = listener; | |
} | |
public void computeScroll() { | |
super.computeScroll(); | |
if (this.dragHelper != null && this.dragHelper.continueSettling(true)) { | |
ViewCompat.postInvalidateOnAnimation(this); | |
} | |
} | |
private float deltaY; | |
public boolean onInterceptTouchEvent(MotionEvent event) { | |
int action = MotionEventCompat.getActionMasked(event); | |
boolean pullDown = false; | |
switch (action) { | |
case MotionEvent.ACTION_DOWN: | |
deltaY = event.getY(); | |
case MotionEvent.ACTION_MOVE: | |
final float dy = event.getY() - deltaY; | |
if (dy > dragHelper.getTouchSlop()) { | |
pullDown = true; | |
} | |
break; | |
case MotionEvent.ACTION_UP: | |
case MotionEvent.ACTION_CANCEL: | |
deltaY = 0.0f; | |
break; | |
} | |
if (!this.dragHelper.shouldInterceptTouchEvent(event) && pullDown) { | |
if (this.dragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE && | |
MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_MOVE && | |
this.dragHelper.checkTouchSlop(ViewDragHelper.DIRECTION_VERTICAL)) { | |
View child = getChildAt(0); | |
if (child != null && !listener.shouldInterceptTouchEvent(event)) { | |
this.dragHelper.captureChildView(child, event.getPointerId(0)); | |
return this.dragHelper.getViewDragState() == ViewDragHelper.STATE_DRAGGING; | |
} | |
} | |
} | |
return false; | |
} | |
public boolean onTouchEvent(MotionEvent event) { | |
this.dragHelper.processTouchEvent(event); | |
return this.dragHelper.getCapturedView() != null; | |
} | |
private class ViewDragCallback extends Callback { | |
private int startTop; | |
private float dragPercent; | |
private View capturedView; | |
private boolean dismissed; | |
private ViewDragCallback() { | |
this.dragPercent = 0.0F; | |
this.dismissed = false; | |
} | |
public boolean tryCaptureView(View view, int i) { | |
return this.capturedView == null; | |
} | |
public int clampViewPositionVertical(View child, int top, int dy) { | |
if (top < 0) { | |
return 0; | |
} | |
if (dismissed) { | |
return top; | |
} | |
return top; | |
} | |
public void onViewCaptured(View view, int activePointerId) { | |
this.capturedView = view; | |
this.startTop = view.getTop(); | |
this.dragPercent = 0.0F; | |
this.dismissed = false; | |
} | |
@SuppressLint({"NewApi"}) | |
public void onViewPositionChanged(View view, int left, int top, int dx, int dy) { | |
int range = PullDismissViewLayout.this.getHeight(); | |
int moved = Math.abs(top - this.startTop); | |
if (range > 0) { | |
this.dragPercent = (float) moved / (float) range; | |
} | |
view.setAlpha(1.0F - this.dragPercent); | |
PullDismissViewLayout.this.invalidate(); | |
} | |
public void onViewDragStateChanged(int state) { | |
if (this.capturedView != null) { | |
synchronized (this) { | |
if (PullDismissViewLayout.this.listener != null) { | |
PullDismissViewLayout.this.listener.onDragStateChanged(this.capturedView, state); | |
} | |
if (state == ViewDragHelper.STATE_IDLE) { | |
if (this.dismissed) { | |
PullDismissViewLayout.this.removeView(this.capturedView); | |
if (PullDismissViewLayout.this.listener != null) { | |
PullDismissViewLayout.this.listener.onDismissed(this.capturedView); | |
} | |
} | |
this.capturedView = null; | |
} | |
} | |
} | |
} | |
public void onViewReleased(View view, float xv, float yv) { | |
this.dismissed = this.dragPercent >= 0.50F || | |
(Math.abs(xv) > PullDismissViewLayout.this.minFlingVelocity && this.dragPercent > 0.20F); | |
int finalTop = dismissed ? getHeight() : startTop; | |
PullDismissViewLayout.this.dragHelper.settleCapturedViewAt(0, finalTop); | |
PullDismissViewLayout.this.invalidate(); | |
} | |
} | |
public interface Listener { | |
void onDismissed(View view); | |
void onDragStateChanged(View view, int state); | |
boolean shouldInterceptTouchEvent(MotionEvent event); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment