365連休

にわかのandroidとかの開発メモ。

AndroidのViewPagerのスワイプを一時的に無効化

ViewPagerのsetEnabledを設定してもスワイプを無効化できない。

 

そこでググったら

code-examples.net

 

様々な方法を編み出してて笑った。

 

みんなViewPager好き過ぎ。

 

結局ViewPagerを継承し、setPagingEnabledを追加する方法を採用した。

//引用元 https://code-examples.net/ja/q/773b81
    private boolean isPagingEnabled = true;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return this.isPagingEnabled && super.onTouchEvent(event); //読み間違いに注意
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return this.isPagingEnabled && super.onInterceptTouchEvent(event); //読み間違いに注意
    }

 

fakeDragやonTouch{return true}も試したが、Androidの流儀に従ってinterceptを制御した方が他のViewとの連携がスマートにできた。

 

 

2019/10/21追記

onTouchの最中にスワイプを無効化し、いくつかタッチ操作の後に、有効化された場合、ViewPagerの内部で保持していたポインタID(ViewPagerのメンバ変数actionPointerId)がMotionEventに存在しないと

//ViewPager#onInterceptTouchEvent(MotionEvent ev)内
//switch case ACTION_MOVE節
final int pointerIndex = ev.findPointerIndex(activePointerId);

で例外が発生する。

 

これは、ACTION_DOWNイベントを生成してViewPagerの内部状態を変化させることで回避できた。

    private boolean isPagingEnabled = true;
    private boolean onEnable = false;
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { if(onEnable){ //有効にされた直後に一度だけ通る onEnable = false; //以下の条件の時にsuper#onInterceptTouchEvent内で例外が発生するのを阻止 if(ev.getActionMasked() == MotionEvent.ACTION_MOVE){ MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties(); properties.id = ev.getPointerId(0); MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords(); ev.getPointerCoords(0, coords); //ViewPagerにダミーTouchEventを流し込んで、ViewPager内で保持するPointerIDを更新する super.onInterceptTouchEvent( MotionEvent.obtain(ev.getDownTime(), ev.getEventTime(), MotionEvent.ACTION_DOWN, ev.getPointerCount(), new MotionEvent.PointerProperties[]{properties}, new MotionEvent.PointerCoords[]{coords}, ev.getMetaState(), ev.getButtonState(), ev.getXPrecision(), ev.getYPrecision(), ev.getDeviceId(), ev.getEdgeFlags(), ev.getSource(), ev.getFlags()) ); } } return this.isPagingEnabled && super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { return this.isPagingEnabled && super.onTouchEvent(ev); } public void setPagingEnabled(boolean isPagingEnabled) { if(this.isPagingEnabled != isPagingEnabled){ onEnable = isPagingEnabled; //有効化された、直後のonInterceptTouchで処理 } this.isPagingEnabled = isPagingEnabled; } public boolean getPagingEnabled(){ return isPagingEnabled; }