package com.gh4a.widget;
import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.v4.view.NestedScrollingChildHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
public class SwipeRefreshLayout extends android.support.v4.widget.SwipeRefreshLayout
implements AppBarLayout.OnOffsetChangedListener {
public interface ChildScrollDelegate {
boolean canChildScrollUp();
}
private final int mTouchSlop;
private float mDownX;
private float mDownY;
private boolean mChildScrollableOnDown;
private final int[] mParentOffsetInWindow = new int[2];
private final NestedScrollingChildHelper mNestedScrollingChildHelper;
private boolean mHorizontalSwipe;
private boolean mIsOrWasUpSwipe;
private ChildScrollDelegate mChildScrollDelegate;
private boolean mAppBarCanScrollUp;
public SwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
public void setAppBarLayout(AppBarLayout abl) {
abl.addOnOffsetChangedListener(this);
}
public void setChildScrollDelegate(ChildScrollDelegate delegate) {
mChildScrollDelegate = delegate;
}
@Override
public boolean canChildScrollUp() {
if (mAppBarCanScrollUp) {
return true;
}
if (mChildScrollDelegate != null) {
return mChildScrollDelegate.canChildScrollUp();
}
return super.canChildScrollUp();
}
@Override
public void onOffsetChanged(AppBarLayout abl, int verticalOffset) {
mAppBarCanScrollUp = verticalOffset != 0;
}
@Override
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
// Leave nested scrolling up to CoordinatorLayout
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN && shouldPreventRefresh()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getX();
mDownY = event.getY();
mHorizontalSwipe = false;
mIsOrWasUpSwipe = false;
mChildScrollableOnDown = canChildScrollUp();
break;
case MotionEvent.ACTION_MOVE:
final float xDiff = Math.abs(event.getX() - mDownX);
final float yDiff = event.getY() - mDownY;
if (yDiff < -mTouchSlop) {
mIsOrWasUpSwipe = true;
}
if (mHorizontalSwipe || xDiff > mTouchSlop) {
mHorizontalSwipe = true;
return false;
}
break;
}
return super.onInterceptTouchEvent(event);
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
if (mNestedScrollingChildHelper != null) {
mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
}
}
@Override
public boolean isNestedScrollingEnabled() {
return mNestedScrollingChildHelper.isNestedScrollingEnabled();
}
@Override
public boolean startNestedScroll(int axes) {
return mNestedScrollingChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mNestedScrollingChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mNestedScrollingChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow) {
return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
@Override
public void onNestedScroll(final View target, final int dxConsumed, final int dyConsumed,
final int dxUnconsumed, final int dyUnconsumed) {
if (shouldPreventRefresh()) {
dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
mParentOffsetInWindow);
} else {
super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
}
}
private boolean shouldPreventRefresh() {
return mChildScrollableOnDown || mIsOrWasUpSwipe;
}
}