我从NestedScrollView创建了这个扩展类,以便当用户从scoll视图着陆时将事件调度到父级(我的ViewPager)。这种行为效果很好。
滚动视图用红色矩形表示:
但:如果滚动视图位于底部,并且我想从滚动视图(从滚动!)滑至下一个屏幕(下方),则viewpager不会什么都不要做。我该怎么办?
非常感谢!
public class VerticalNestedScrollview extends NestedScrollView {
public class VerticalPagerTouchDownEvent extends BaseEvent {
}
private long mDownTime;
private final long mAreaThreshold = 60; // In pixels
private boolean mCatchMoveTouchEvent = true;
private int mDownX, mDownY, mPagesCount = 0;
private ViewPager mParentViewPager;
private boolean mIsBottomReached = false, mIsTopReached = true;
public VerticalNestedScrollview(Context context) {
super(context);
init();
}
public VerticalNestedScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public VerticalNestedScrollview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mParentViewPager = getViewPagerParent();
if (mParentViewPager != null) {
PagerAdapter pagerAdapter = mParentViewPager.getAdapter();
mPagesCount = pagerAdapter.getCount();
}
int contentHeight = getChildAt(0).getHeight();
mCatchMoveTouchEvent = getHeight() < contentHeight + getPaddingTop() + getPaddingBottom();
}
});
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
refreshTopBottomReachedInfos();
super.onScrollChanged(l, t, oldl, oldt);
}
private void refreshTopBottomReachedInfos() {
mIsTopReached = getScrollY() == 0;
// Grab the last child placed in the ScrollView, we need it to determinate the bottom position.
View view = getChildAt(getChildCount() - 1);
// Calculate the scroll diff
int diff = (view.getBottom() - (getHeight() + getScrollY())) + getPaddingBottom();
// if diff is zero, then the bottom has been reached
mIsBottomReached = diff <= 0;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mCatchMoveTouchEvent) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mDownTime = SystemClock.uptimeMillis();
mDownX = (int) ev.getRawX();
mDownY = (int) ev.getRawY();
refreshTopBottomReachedInfos();
} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {
Rect rect = new Rect();
getHitRect(rect);
rect.bottom += mAreaThreshold;
rect.top -= mAreaThreshold;
boolean isDownSwipe = mDownY > (int) ev.getRawY();
// The move action is outside this scrollview
if (!rect.contains((int) ev.getX(), (int) ev.getY())) {
dispatchTouchDownToViewPager(ev, isDownSwipe, 0);
return true;
}
} else {
mIsBottomReached = false;
mIsTopReached = false;
}
return super.dispatchTouchEvent(ev);
} else {
return true;
}
}
private boolean checkDispatchValidity(boolean isDownSwipe) {
if (isDownSwipe && mParentViewPager != null &&
mParentViewPager.getCurrentItem() == mPagesCount - 1)
return false;
if (!isDownSwipe && mParentViewPager != null &&
mParentViewPager.getCurrentItem() == 0)
return false;
return true;
}
private void dispatchTouchDownToViewPager(MotionEvent ev, boolean isDownSwipe, long deltaY) {
if (checkDispatchValidity(isDownSwipe)) {
MotionEvent motionEvent = MotionEvent.obtain(
mDownTime,
SystemClock.uptimeMillis() + 1000,
MotionEvent.ACTION_DOWN, (int) ev.getRawX(),
(int) ev.getRawY() - deltaY, 0
);
if (mParentViewPager != null) {
mParentViewPager.dispatchTouchEvent(motionEvent);
EventBus.getDefault().post(new VerticalPagerTouchDownEvent());
}
}
}
private ViewPager getViewPagerParent() {
ViewParent parent = getParent();
do {
if (parent instanceof ViewPager) {
return ((ViewPager) parent);
}
parent = parent.getParent();
} while (parent != null);
return null;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
return true;
}
}