子View検出
子Viewがいるかどうかの判断。最初に見つかったものを対象にしている。
なので、SwipeRefreshLayoutの直接の子ビューは1つしか対象にできない、ということが分かる。
逆に、addViewやremoveViewは使えるのかも。
private void ensureTarget() { // Don't bother getting the parent height if the parent hasn't been laid // out yet. if (mTarget == null) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (!child.equals(mCircleView)) { mTarget = child; break; } } } }
子Viewが上方スクロール可能かどうかの判断
子ビューがスクロール可能な場合、そのスクロールが完了するまでスワイプの挙動を待つ必要があるのでその判定。
旧バージョンではAbsListViewを継承していれば。それ以外ではcanScrollVarticallyを見ている。
- 14未満の場合にAbsListViewの判定は他でも使えそう。
- 縦スクロール判定でViewCompat.canScrollVerticallyが利用可能らしい。
public boolean canChildScrollUp() { if (android.os.Build.VERSION.SDK_INT < 14) { if (mTarget instanceof AbsListView) { final AbsListView absListView = (AbsListView) mTarget; return absListView.getChildCount() > 0 && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0) .getTop() < absListView.getPaddingTop()); } else { return ViewCompat.canScrollVertically(mTarget, -1) || mTarget.getScrollY() > 0; } } else { return ViewCompat.canScrollVertically(mTarget, -1); } }
TouchEventの冒頭
setEnabled(false)にしておけばタッチイベントは無視される。canChildScrollUpで子ビューの動きを判断している。
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { ensureTarget(); final int action = MotionEventCompat.getActionMasked(ev); if (mReturningToStart && action == MotionEvent.ACTION_DOWN) { mReturningToStart = false; } if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing) { // Fail fast if we're not in a state where a swipe is possible return false; }