前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

SwipeRefreshLayoutソースコード読み

子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;
        }