|
|
@@ -0,0 +1,563 @@
|
|
|
+package com.itant.shibei.widget;
|
|
|
+
|
|
|
+import android.app.Activity;
|
|
|
+import android.content.Context;
|
|
|
+import android.util.AttributeSet;
|
|
|
+import android.util.Log;
|
|
|
+import android.view.MotionEvent;
|
|
|
+import android.view.View;
|
|
|
+import android.view.ViewGroup;
|
|
|
+import android.webkit.WebView;
|
|
|
+import android.widget.AbsListView;
|
|
|
+import android.widget.ScrollView;
|
|
|
+
|
|
|
+import androidx.core.view.ViewCompat;
|
|
|
+import androidx.customview.widget.ViewDragHelper;
|
|
|
+import androidx.viewpager.widget.ViewPager;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Swipe or Pull to finish a Activity.
|
|
|
+ * <p/>
|
|
|
+ * This layout must be a root layout and contains only one direct child view.
|
|
|
+ * <p/>
|
|
|
+ * The activity must use a theme that with translucent style.
|
|
|
+ * <style name="Theme.Swipe.Back" parent="AppTheme">
|
|
|
+ * <item name="android:windowIsTranslucent">true</item>
|
|
|
+ * <item name="android:windowBackground">@android:color/transparent</item>
|
|
|
+ * </style>
|
|
|
+ * <p/>
|
|
|
+ * Created by Eric on 15/1/8.
|
|
|
+ */
|
|
|
+public class SwipeBackLayout extends ViewGroup {
|
|
|
+
|
|
|
+ private static final String TAG = "SwipeBackLayout";
|
|
|
+
|
|
|
+ public enum DragDirectMode {
|
|
|
+ EDGE,
|
|
|
+ VERTICAL,
|
|
|
+ HORIZONTAL
|
|
|
+ }
|
|
|
+
|
|
|
+ public enum DragEdge {
|
|
|
+ LEFT,
|
|
|
+
|
|
|
+ TOP,
|
|
|
+
|
|
|
+ RIGHT,
|
|
|
+
|
|
|
+ BOTTOM
|
|
|
+ }
|
|
|
+
|
|
|
+ private DragDirectMode dragDirectMode = DragDirectMode.EDGE;
|
|
|
+
|
|
|
+ private DragEdge dragEdge = DragEdge.TOP;
|
|
|
+
|
|
|
+ public void setDragEdge(DragEdge dragEdge) {
|
|
|
+ this.dragEdge = dragEdge;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setDragDirectMode(DragDirectMode dragDirectMode) {
|
|
|
+ this.dragDirectMode = dragDirectMode;
|
|
|
+ if (dragDirectMode == DragDirectMode.VERTICAL) {
|
|
|
+ this.dragEdge = DragEdge.TOP;
|
|
|
+ } else if (dragDirectMode == DragDirectMode.HORIZONTAL) {
|
|
|
+ this.dragEdge = DragEdge.LEFT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final double AUTO_FINISHED_SPEED_LIMIT = 2000.0;
|
|
|
+
|
|
|
+ private ViewDragHelper viewDragHelper;
|
|
|
+
|
|
|
+ private View target;
|
|
|
+
|
|
|
+ private View scrollChild;
|
|
|
+
|
|
|
+ private int verticalDragRange = 0;
|
|
|
+
|
|
|
+ private int horizontalDragRange = 0;
|
|
|
+
|
|
|
+ private int draggingState = 0;
|
|
|
+
|
|
|
+ private int draggingOffset;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Whether allow to pull this layout.
|
|
|
+ */
|
|
|
+ private boolean enablePullToBack = true;
|
|
|
+
|
|
|
+ private static final float BACK_FACTOR = 0.5f;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * the anchor of calling finish.
|
|
|
+ */
|
|
|
+ private float finishAnchor = 0;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Set the anchor of calling finish.
|
|
|
+ *
|
|
|
+ * @param offset
|
|
|
+ */
|
|
|
+ public void setFinishAnchor(float offset) {
|
|
|
+ finishAnchor = offset;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean enableFlingBack = true;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Whether allow to finish activity by fling the layout.
|
|
|
+ *
|
|
|
+ * @param b
|
|
|
+ */
|
|
|
+ public void setEnableFlingBack(boolean b) {
|
|
|
+ enableFlingBack = b;
|
|
|
+ }
|
|
|
+
|
|
|
+ private SwipeBackListener swipeBackListener;
|
|
|
+
|
|
|
+ @Deprecated
|
|
|
+ public void setOnPullToBackListener(SwipeBackListener listener) {
|
|
|
+ swipeBackListener = listener;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setOnSwipeBackListener(SwipeBackListener listener) {
|
|
|
+ swipeBackListener = listener;
|
|
|
+ }
|
|
|
+
|
|
|
+ public SwipeBackLayout(Context context) {
|
|
|
+ this(context, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ public SwipeBackLayout(Context context, AttributeSet attrs) {
|
|
|
+ super(context, attrs);
|
|
|
+
|
|
|
+ viewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelperCallBack());
|
|
|
+ chkDragable();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * This should be added first than any other setting, because it will overwrite the viewDragHelper
|
|
|
+ *
|
|
|
+ * @param onFinishListener listener for what to do when view reach the end
|
|
|
+ */
|
|
|
+ public void setOnFinishListener(OnFinishListener onFinishListener ) {
|
|
|
+ viewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelperCallBack(onFinishListener));
|
|
|
+ }
|
|
|
+
|
|
|
+ float lastY = 0;
|
|
|
+ float newY = 0;
|
|
|
+ float offsetY = 0;
|
|
|
+
|
|
|
+ float lastX = 0;
|
|
|
+ float newX = 0;
|
|
|
+ float offsetX = 0;
|
|
|
+
|
|
|
+ private void chkDragable() {
|
|
|
+ setOnTouchListener(new View.OnTouchListener() {
|
|
|
+ @Override
|
|
|
+ public boolean onTouch(View view, MotionEvent motionEvent) {
|
|
|
+
|
|
|
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
|
|
+ lastY = motionEvent.getRawY();
|
|
|
+ lastX = motionEvent.getRawX();
|
|
|
+ } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
|
|
|
+ newY = motionEvent.getRawY();
|
|
|
+ lastX = motionEvent.getRawX();
|
|
|
+
|
|
|
+ offsetY = Math.abs(newY - lastY);
|
|
|
+ lastY = newY;
|
|
|
+
|
|
|
+ offsetX = Math.abs(newX - lastX);
|
|
|
+ lastX = newX;
|
|
|
+
|
|
|
+ switch (dragEdge) {
|
|
|
+ case TOP:
|
|
|
+ case BOTTOM:
|
|
|
+ setEnablePullToBack(offsetY > offsetX);
|
|
|
+ case LEFT:
|
|
|
+ case RIGHT:
|
|
|
+ setEnablePullToBack(offsetY < offsetX);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setScrollChild(View view) {
|
|
|
+ scrollChild = view;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setEnablePullToBack(boolean b) {
|
|
|
+ enablePullToBack = b;
|
|
|
+ Log.i(TAG, "enablePullToBack:" + enablePullToBack);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ensureTarget() {
|
|
|
+ if (target == null) {
|
|
|
+ if (getChildCount() > 1) {
|
|
|
+ throw new IllegalStateException("SwipeBackLayout must contains only one direct child");
|
|
|
+ }
|
|
|
+ target = getChildAt(0);
|
|
|
+
|
|
|
+ if (scrollChild == null && target != null) {
|
|
|
+ if (target instanceof ViewGroup) {
|
|
|
+ findScrollView((ViewGroup) target);
|
|
|
+ } else {
|
|
|
+ scrollChild = target;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Find out the scrollable child view from a ViewGroup.
|
|
|
+ *
|
|
|
+ * @param viewGroup
|
|
|
+ */
|
|
|
+ private void findScrollView(ViewGroup viewGroup) {
|
|
|
+ scrollChild = viewGroup;
|
|
|
+ if (viewGroup.getChildCount() > 0) {
|
|
|
+ int count = viewGroup.getChildCount();
|
|
|
+ View child;
|
|
|
+ for (int i = 0; i < count; i++) {
|
|
|
+ child = viewGroup.getChildAt(i);
|
|
|
+ if (child instanceof AbsListView || child instanceof ScrollView || child instanceof ViewPager || child instanceof WebView) {
|
|
|
+ scrollChild = child;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
|
+ int width = getMeasuredWidth();
|
|
|
+ int height = getMeasuredHeight();
|
|
|
+ if (getChildCount() == 0) return;
|
|
|
+
|
|
|
+ View child = getChildAt(0);
|
|
|
+
|
|
|
+ int childWidth = width - getPaddingLeft() - getPaddingRight();
|
|
|
+ int childHeight = height - getPaddingTop() - getPaddingBottom();
|
|
|
+ int childLeft = getPaddingLeft();
|
|
|
+ int childTop = getPaddingTop();
|
|
|
+ int childRight = childLeft + childWidth;
|
|
|
+ int childBottom = childTop + childHeight;
|
|
|
+ child.layout(childLeft, childTop, childRight, childBottom);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
|
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
|
+ if (getChildCount() > 1) {
|
|
|
+ throw new IllegalStateException("SwipeBackLayout must contains only one direct child.");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (getChildCount() > 0) {
|
|
|
+ int measureWidth = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY);
|
|
|
+ int measureHeight = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY);
|
|
|
+ getChildAt(0).measure(measureWidth, measureHeight);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
|
|
+ super.onSizeChanged(w, h, oldw, oldh);
|
|
|
+ verticalDragRange = h;
|
|
|
+ horizontalDragRange = w;
|
|
|
+
|
|
|
+ switch (dragEdge) {
|
|
|
+ case TOP:
|
|
|
+ case BOTTOM:
|
|
|
+ finishAnchor = finishAnchor > 0 ? finishAnchor : verticalDragRange * BACK_FACTOR;
|
|
|
+ break;
|
|
|
+ case LEFT:
|
|
|
+ case RIGHT:
|
|
|
+ finishAnchor = finishAnchor > 0 ? finishAnchor : horizontalDragRange * BACK_FACTOR;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int getDragRange() {
|
|
|
+ switch (dragEdge) {
|
|
|
+ case TOP:
|
|
|
+ case BOTTOM:
|
|
|
+ return verticalDragRange;
|
|
|
+ case LEFT:
|
|
|
+ case RIGHT:
|
|
|
+ return horizontalDragRange;
|
|
|
+ default:
|
|
|
+ return verticalDragRange;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
|
|
|
+ boolean handled = false;
|
|
|
+ ensureTarget();
|
|
|
+ if (isEnabled()) {
|
|
|
+ handled = viewDragHelper.shouldInterceptTouchEvent(ev);
|
|
|
+ } else {
|
|
|
+ viewDragHelper.cancel();
|
|
|
+ }
|
|
|
+ return !handled ? super.onInterceptTouchEvent(ev) : handled;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean onTouchEvent(MotionEvent event) {
|
|
|
+ viewDragHelper.processTouchEvent(event);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void computeScroll() {
|
|
|
+ if (viewDragHelper.continueSettling(true)) {
|
|
|
+ ViewCompat.postInvalidateOnAnimation(this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean canChildScrollUp() {
|
|
|
+ return ViewCompat.canScrollVertically(scrollChild, -1);
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean canChildScrollDown() {
|
|
|
+ return ViewCompat.canScrollVertically(scrollChild, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean canChildScrollRight() {
|
|
|
+ return ViewCompat.canScrollHorizontally(scrollChild, -1);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean canChildScrollLeft() {
|
|
|
+ return ViewCompat.canScrollHorizontally(scrollChild, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void finish() {
|
|
|
+ Activity act = (Activity) getContext();
|
|
|
+ act.finish();
|
|
|
+ act.overridePendingTransition(0, android.R.anim.fade_out);
|
|
|
+ }
|
|
|
+
|
|
|
+ private class ViewDragHelperCallBack extends ViewDragHelper.Callback {
|
|
|
+
|
|
|
+ private OnFinishListener onFinishListener = new OnFinishListener() {
|
|
|
+ @Override
|
|
|
+ public void onFinishState() {
|
|
|
+ finish();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ public ViewDragHelperCallBack() {
|
|
|
+ }
|
|
|
+
|
|
|
+ public ViewDragHelperCallBack(OnFinishListener onFinishListener) {
|
|
|
+ this.onFinishListener = onFinishListener;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean tryCaptureView(View child, int pointerId) {
|
|
|
+ return child == target && enablePullToBack;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int getViewVerticalDragRange(View child) {
|
|
|
+ return verticalDragRange;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int getViewHorizontalDragRange(View child) {
|
|
|
+ return horizontalDragRange;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int clampViewPositionVertical(View child, int top, int dy) {
|
|
|
+
|
|
|
+ int result = 0;
|
|
|
+
|
|
|
+ if (dragDirectMode == DragDirectMode.VERTICAL) {
|
|
|
+ if (!canChildScrollUp() && top > 0) {
|
|
|
+ dragEdge = DragEdge.TOP;
|
|
|
+ } else if (!canChildScrollDown() && top < 0) {
|
|
|
+ dragEdge = DragEdge.BOTTOM;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dragEdge == DragEdge.TOP && !canChildScrollUp() && top > 0) {
|
|
|
+ final int topBound = getPaddingTop();
|
|
|
+ final int bottomBound = verticalDragRange;
|
|
|
+ result = Math.min(Math.max(top, topBound), bottomBound);
|
|
|
+ } else if (dragEdge == DragEdge.BOTTOM && !canChildScrollDown() && top < 0) {
|
|
|
+ final int topBound = -verticalDragRange;
|
|
|
+ final int bottomBound = getPaddingTop();
|
|
|
+ result = Math.min(Math.max(top, topBound), bottomBound);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int clampViewPositionHorizontal(View child, int left, int dx) {
|
|
|
+
|
|
|
+ int result = 0;
|
|
|
+
|
|
|
+ if (dragDirectMode == DragDirectMode.HORIZONTAL) {
|
|
|
+ if (!canChildScrollRight() && left > 0) {
|
|
|
+ dragEdge = DragEdge.LEFT;
|
|
|
+ } else if (!canChildScrollLeft() && left < 0) {
|
|
|
+ dragEdge = DragEdge.RIGHT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dragEdge == DragEdge.LEFT && !canChildScrollRight() && left > 0) {
|
|
|
+ final int leftBound = getPaddingLeft();
|
|
|
+ final int rightBound = horizontalDragRange;
|
|
|
+ result = Math.min(Math.max(left, leftBound), rightBound);
|
|
|
+ } else if (dragEdge == DragEdge.RIGHT && !canChildScrollLeft() && left < 0) {
|
|
|
+ final int leftBound = -horizontalDragRange;
|
|
|
+ final int rightBound = getPaddingLeft();
|
|
|
+ result = Math.min(Math.max(left, leftBound), rightBound);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onViewDragStateChanged(int state) {
|
|
|
+ if (state == draggingState) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((draggingState == ViewDragHelper.STATE_DRAGGING || draggingState == ViewDragHelper.STATE_SETTLING) &&
|
|
|
+ state == ViewDragHelper.STATE_IDLE) {
|
|
|
+ // the view stopped from moving.
|
|
|
+ if (draggingOffset == getDragRange()) {
|
|
|
+ onFinishListener.onFinishState();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ draggingState = state;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
|
|
|
+ switch (dragEdge) {
|
|
|
+ case TOP:
|
|
|
+ case BOTTOM:
|
|
|
+ draggingOffset = Math.abs(top);
|
|
|
+ break;
|
|
|
+ case LEFT:
|
|
|
+ case RIGHT:
|
|
|
+ draggingOffset = Math.abs(left);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //The proportion of the sliding.
|
|
|
+ float fractionAnchor = (float) draggingOffset / finishAnchor;
|
|
|
+ if (fractionAnchor >= 1) {
|
|
|
+ fractionAnchor = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ float fractionScreen = (float) draggingOffset / (float) getDragRange();
|
|
|
+ if (fractionScreen >= 1) {
|
|
|
+ fractionScreen = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (swipeBackListener != null) {
|
|
|
+ swipeBackListener.onViewPositionChanged(fractionAnchor, fractionScreen);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onViewReleased(View releasedChild, float xvel, float yvel) {
|
|
|
+ if (draggingOffset == 0) return;
|
|
|
+
|
|
|
+ if (draggingOffset == getDragRange()) return;
|
|
|
+
|
|
|
+ boolean isBack = false;
|
|
|
+
|
|
|
+ if (enableFlingBack && backBySpeed(xvel, yvel)) {
|
|
|
+ isBack = !canChildScrollUp();
|
|
|
+ } else if (draggingOffset >= finishAnchor) {
|
|
|
+ isBack = true;
|
|
|
+ } else if (draggingOffset < finishAnchor) {
|
|
|
+ isBack = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ int finalLeft;
|
|
|
+ int finalTop;
|
|
|
+ switch (dragEdge) {
|
|
|
+ case LEFT:
|
|
|
+ finalLeft = isBack ? horizontalDragRange : 0;
|
|
|
+ smoothScrollToX(finalLeft);
|
|
|
+ break;
|
|
|
+ case RIGHT:
|
|
|
+ finalLeft = isBack ? -horizontalDragRange : 0;
|
|
|
+ smoothScrollToX(finalLeft);
|
|
|
+ break;
|
|
|
+ case TOP:
|
|
|
+ finalTop = isBack ? verticalDragRange : 0;
|
|
|
+ smoothScrollToY(finalTop);
|
|
|
+ break;
|
|
|
+ case BOTTOM:
|
|
|
+ finalTop = isBack ? -verticalDragRange : 0;
|
|
|
+ smoothScrollToY(finalTop);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean backBySpeed(float xvel, float yvel) {
|
|
|
+ switch (dragEdge) {
|
|
|
+ case TOP:
|
|
|
+ case BOTTOM:
|
|
|
+ if (Math.abs(yvel) > Math.abs(xvel) && Math.abs(yvel) > AUTO_FINISHED_SPEED_LIMIT) {
|
|
|
+ return dragEdge == DragEdge.TOP ? !canChildScrollUp() : !canChildScrollDown();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case LEFT:
|
|
|
+ case RIGHT:
|
|
|
+ if (Math.abs(xvel) > Math.abs(yvel) && Math.abs(xvel) > AUTO_FINISHED_SPEED_LIMIT) {
|
|
|
+ return dragEdge == DragEdge.LEFT ? !canChildScrollLeft() : !canChildScrollRight();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void smoothScrollToX(int finalLeft) {
|
|
|
+ if (viewDragHelper.settleCapturedViewAt(finalLeft, 0)) {
|
|
|
+ ViewCompat.postInvalidateOnAnimation(SwipeBackLayout.this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void smoothScrollToY(int finalTop) {
|
|
|
+ if (viewDragHelper.settleCapturedViewAt(0, finalTop)) {
|
|
|
+ ViewCompat.postInvalidateOnAnimation(SwipeBackLayout.this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public interface OnFinishListener {
|
|
|
+
|
|
|
+ void onFinishState();
|
|
|
+ }
|
|
|
+
|
|
|
+ public interface SwipeBackListener {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Return scrolled fraction of the layout.
|
|
|
+ *
|
|
|
+ * @param fractionAnchor relative to the anchor.
|
|
|
+ * @param fractionScreen relative to the screen.
|
|
|
+ */
|
|
|
+ void onViewPositionChanged(float fractionAnchor, float fractionScreen);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|