web-dev-qa-db-ja.com

ViewPagerで指でスワイプしてページングを無効にする方法を教えてください。

ViewPagerがあり、その下には10個のボタンがあります。 #4などのボタンをクリックすると、ポケットベルはmPager.setCurrentItem(3);によってすぐに4ページに移動します。しかし、私は水平方向に指でスワイプしてページングを無効にしたいです。このように、ページングは​​ボタンをクリックすることによって行われますONLY。それで、どのように私は指でスワイプを無効にすることができますか?

476
theateist

ViewPagerをサブクラス化する必要があります。 onTouchEventにはたくさんの良いことがありますので、子のビューに触れることを許可するように変更したくはありません。 onInterceptTouchEventはあなたが変更したいものです。 ViewPagerのコードを見ると、コメントが表示されます。

    /*
     * This method JUST determines whether we want to intercept the motion.
     * If we return true, onMotionEvent will be called and we do the actual
     * scrolling there.
     */

これが完全な解決策です:

まず、このクラスをsrcフォルダに追加します。

import Android.content.Context;
import Android.support.v4.view.ViewPager;
import Android.util.AttributeSet;
import Android.view.MotionEvent;
import Android.view.animation.DecelerateInterpolator;
import Android.widget.Scroller;
import Java.lang.reflect.Field;

public class NonSwipeableViewPager extends ViewPager {

    public NonSwipeableViewPager(Context context) {
        super(context);
        setMyScroller();
    }

    public NonSwipeableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setMyScroller();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    //down one is added for smooth scrolling

    private void setMyScroller() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new MyScroller(getContext()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class MyScroller extends Scroller {
        public MyScroller(Context context) {
            super(context, new DecelerateInterpolator());
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
        }
    }
}

次に、通常はAndroid.support.v4.view.ViewPagerとして指定した通常のViewPagerの代わりにこのクラスを必ず使用してください。レイアウトファイルでは、次のように指定します。

<com.yourcompany.NonSwipeableViewPager
    Android:id="@+id/view_pager"
    Android:layout_width="match_parent"
    Android:layout_height="0dp"
    Android:layout_weight="1" />

この例はLinearLayout内にあり、画面全体を占めることを意図しています。そのため、layout_weightが1でlayout_heightが0dpです。

そしてsetMyScroller();メソッドはスムーズな移行のためのものです

824
louielouie

ViewPagerのより一般的な拡張は、その場でページングを有効または無効にできるようにSetPagingEnabledメソッドを作成することです。スワイプを有効/無効にするには、onTouchEventonInterceptTouchEventの2つのメソッドをオーバーライドするだけです。ページングが無効になっている場合、両方とも "false"を返します。

public class CustomViewPager extends ViewPager {

    private boolean enabled;

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onInterceptTouchEvent(event);
        }

        return false;
    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    } 
}

次に、XMLのビルトインビューページャの代わりにこれを選択してください。

<mypackage.CustomViewPager 
    Android:id="@+id/myViewPager" 
    Android:layout_height="match_parent" 
    Android:layout_width="match_parent" />

setPagingEnabledメソッドをfalseと一緒に呼び出すだけで、ユーザーはページ番号までスワイプすることはできません。

439
Rajul

最も簡単な方法は、setOnTouchListenerを返し、trueに対してViewPagerを返すことです。

mPager.setOnTouchListener(new OnTouchListener()
    {           
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            return true;
        }
    });
98
Wayne

それをスタイル可能と宣言したほうがよいので、そのプロパティをxmlから変更できます。

private boolean swipeable;

public MyViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyViewPager);
    try {
        swipeable = a.getBoolean(R.styleable.MyViewPager_swipeable, true);
    } finally {
        a.recycle();
    }
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return swipeable ? super.onInterceptTouchEvent(event) : false;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return swipeable ? super.onTouchEvent(event) : false;
}

そしてあなたのvalues/attr.xmlで:

<declare-styleable name="MyViewPager">
  <attr name="swipeable" format="boolean" />
</declare-styleable>

あなたがあなたのレイアウトxmlでそれを使うことができるように:

<mypackage.MyViewPager
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/viewPager"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    app:swipeable="false" />

もちろん、あなたはまだget/setプロパティを持つことができます。

53
Pietro

onTouchEventonInterceptTouchEventだけをオーバーライドしても、ViewPager自体が別のViewPagerの中にある場合は十分ではありません。最初のページまたは最後のページに配置されていない限り、子ViewPagerは親ViewPagerから水平スクロールタッチイベントを取得します。

この設定を正しく機能させるためには、canScrollHorizontallyメソッドもオーバーライドする必要があります。

下記のLockableViewPagerの実装を見てください。

public class LockableViewPager extends ViewPager {

    private boolean swipeLocked;

    public LockableViewPager(Context context) {
        super(context);
    }

    public LockableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public boolean getSwipeLocked() {
        return swipeLocked;
    }

    public void setSwipeLocked(boolean swipeLocked) {
        this.swipeLocked = swipeLocked;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return !swipeLocked && super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return !swipeLocked && super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean canScrollHorizontally(int direction) {
        return !swipeLocked && super.canScrollHorizontally(direction);
    }

}
49
sidon

スワイプを無効にする

mViewPager.beginFakeDrag();

スワイプを有効にする

mViewPager.endFakeDrag();
28
KAMAL VERMA

ViewPagerから拡張する場合は、 @araksで前に示したように、executeKeyEventもオーバーライドする必要があります。

@Override
public boolean executeKeyEvent(KeyEvent event)
{
    return isPagingEnabled ? super.executeKeyEvent(event) : false;
}

Galaxy Tab 4 10 'のような一部のデバイスでは、ほとんどのデバイスでは表示されないこれらのボタンが表示されるためです。

Keyboard buttons

27
Grease

ある特定のページでスワイプを無効にして、素敵な輪ゴムのアニメーションにする必要があります。

    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            if (position == MANDATORY_PAGE_LOCATION && positionOffset > 0.5) {
                mViewPager.setCurrentItem(MANDATORY_PAGE_LOCATION, true);
            }
        }
14
Oded Breiner

私はスワイプコントロールでCustomViewPagerを書きました:

public class ScrollableViewPager extends ViewPager {
    private boolean canScroll = true;
    public ScrollableViewPager(Context context) {
        super(context);
    }
    public ScrollableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public void setCanScroll(boolean canScroll) {
        this.canScroll = canScroll;
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return canScroll && super.onTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return canScroll && super.onInterceptTouchEvent(ev);
    }
}

canScrolltrueに設定した場合、このViewPagerは指でスワイプすることができます。逆にfalse

私は自分のプロジェクトでこれを使っていますが、今までそれはうまく機能します。

12
L. Swifter

私はこれを投稿するのが遅すぎることを知っていますが、ここにあなたの結果を達成するための小さなハックがあります;)

単純にダミービューを追加してください below あなたのviewpager:

<Android.support.v4.view.ViewPager
     Android:layout_width="match_parent"
     Android:layout_height="match_parent">
</Android.support.v4.view.ViewPager>

<RelativeLayout
     Android:id="@+id/dummyView"
     Android:layout_width="match_parent"
     Android:layout_height="match_parent">
</RelativeLayout>

それからOnClickListenerをあなたのRelativeLayoutに追加してください。

dummyView = (RelativeLayout) findViewById(R.id.dummyView);

dummyView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
         //Just leave this empty
    }
});

レイアウト、配置、振る舞いについて少しクリエイティブになりましょう。あなたが想像していることをすべてやる方法を見つけることを学ぶでしょう:)

がんばろう!

11
Dinuka

onInterceptTouchEvent() または /onTouchEvent() のいずれかからオーバーライドしてtrueを返すようにしてください。これらはページャのタッチイベントを消費します。

4
AdamK

私はこのクラスをうまく使いました。 executeKeyEvent をオーバーライドすることは、一部のデバイスでは矢印を使ったスワイプを避けるため、またはアクセシビリティのために必要です。

import Android.content.Context;
import Android.support.v4.view.ViewPager;
import Android.util.AttributeSet;
import Android.view.KeyEvent;
import Android.view.MotionEvent;

public class ViewPagerNoSwipe extends ViewPager {
    /**
     * Is swipe enabled
     */
    private boolean enabled;

    public ViewPagerNoSwipe(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = false; // By default swiping is disabled
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return this.enabled ? super.onTouchEvent(event) : false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return this.enabled ? super.onInterceptTouchEvent(event) : false;
    }

    @Override
    public boolean executeKeyEvent(KeyEvent event) {
        return this.enabled ? super.executeKeyEvent(event) : false;
    }

    public void setSwipeEnabled(boolean enabled) {
        this.enabled = enabled;
    }

}

そして xml の中でこれを次のように呼びます。

<package.path.ViewPagerNoSwipe
    Android:layout_width="match_parent"
    Android:layout_height="match_parent" />
3
madx

Kotlinでは、ViewPagerクラスを継承するカスタムウィジェットを作成し、スワイプ動作を制御するためのフラグ値を追加することでこれを解決できます。

NoSwipePager.kt

class NoSwipePager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) {

    var pagingEnabled: Boolean = false

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return if (this.pagingEnabled) {
            super.onTouchEvent(event)
        } else false
    }

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        return if (this.pagingEnabled) {
            super.onInterceptTouchEvent(event)
        } else false
    }
}

XMLで

<your.package.NoSwipePager
    Android:id="@+id/view_pager"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_below="@id/tab_layout" />

プログラムでスワイプを無効にします。 kotlin-Android-extensionsプラグインがbuild.gradleに適用されている場合、以下のコードを記述することでスワイプを無効にできます。

view_pager.pagingEnabled = false

それ以外の場合は、以下のコードを使用してスワイプを無効にできます。

val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false
3
Sagar Chapagain

今、私たちはカスタムViewPagerを作成する必要はありません。

新しい ViewPager2 name Androidで表示可能

viewpager2でスワイプを無効にするには

viewPager2.setUserInputEnabled(false);

viewpager2でスワイプを有効にするには

viewPager2.setUserInputEnabled(true);

詳しくはこちらをご覧ください

3
Nilesh Rathod

ズームとパンをサポートするImageViewsおよびViewPagerを使用して画像ギャラリーを作成する場合は、ここで説明する簡単な解決策を参照してください。 Phimpme Android (および Githubサンプル-PhotoView )このソリューションは、ViewPagerだけでは機能しません。

public class CustomViewPager extends ViewPager {
    public CustomViewPager(Context context) {
        super(context);
    }

    public CustomViewPager(Context context, AttributeSet attrs)
    {
        super(context,attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        try {
            return super.onInterceptTouchEvent(event);
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
}
1
CoolMind

特定のページ(この例では2ページ目)でスワイプを無効にするもう1つの簡単な解決策:

int PAGE = 2;
viewPager.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
        if (viewPager.getCurrentItem() == PAGE) {
                viewPager.setCurrentItem(PAGE-1, false);
                viewPager.setCurrentItem(PAGE, false);
                return  true;
        }
        return false;
}
1
Ofir

XamarinでAndroidにも同じように実装したい場合は、C#への翻訳です。

属性に「 ScrollEnabled 」という名前を付けました。 iOSは単にexcatと同じ名前を使っているからです。そのため、両方のプラットフォームで同じ名前を付けることで、開発者にとって簡単になります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Android.Util;

namespace YourNameSpace.ViewPackage {

    // Need to disable swiping for ViewPager, if user performs Pre DSA and the dsa is not completed yet
    // http://stackoverflow.com/questions/9650265/how-do-disable-paging-by-swiping-with-finger-in-viewpager-but-still-be-able-to-s
    public class CustomViewPager: ViewPager {
        public bool ScrollEnabled;

        public CustomViewPager(Context context, IAttributeSet attrs) : base(context, attrs) {
            this.ScrollEnabled = true;
        }

        public override bool OnTouchEvent(MotionEvent e) {
            if (this.ScrollEnabled) {
                return base.OnTouchEvent(e);
            }
            return false;
        }

        public override bool OnInterceptTouchEvent(MotionEvent e) {
            if (this.ScrollEnabled) {
                return base.OnInterceptTouchEvent(e);
            }
            return false;
        }

        // For ViewPager inside another ViewPager
        public override bool CanScrollHorizontally(int direction) {
            return this.ScrollEnabled && base.CanScrollHorizontally(direction);
        }

        // Some devices like the Galaxy Tab 4 10' show swipe buttons where most devices never show them
        // So, you could still swipe through the ViewPager with your keyboard keys
        public override bool ExecuteKeyEvent(KeyEvent evt) {
            return this.ScrollEnabled ? base.ExecuteKeyEvent(evt) : false;
        }
    }
}

.axmlファイルの場合:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">
  <YourNameSpace.ViewPackage.CustomViewPager
      Android:id="@+id/pager"
      Android:layout_width="match_parent"
      Android:layout_height="wrap_content"
      Android:background="@Android:color/white"
      Android:layout_alignParentTop="true" />
</LinearLayout>
0
Lepidopteron

ビューページャを少しカスタマイズして、スワイプを簡単に無効にしました。

public class CustomViewPager extends ViewPager {

private boolean swipeLocked;

public CustomViewPager(Context context) {
    super(context);
}

public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public boolean getSwipeLocked() {
    return swipeLocked;
}

public void setSwipeLocked(boolean swipeLocked) {
    this.swipeLocked = swipeLocked;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return !swipeLocked && super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return !swipeLocked && super.onInterceptTouchEvent(event);
}

@Override
public boolean canScrollHorizontally(int direction) {
    return !swipeLocked && super.canScrollHorizontally(direction);
}
}
0
Shivam Yadav

これが私の実装です
スワイプアニメーションを無効にしたい場合は、swipeListenerを左右に使用しても、指なしではなくアニメーションなしでスクロールすることができます。

ViewpagerメソッドonInterceptTouchEventおよびonTouchEventを1 - オーバーライドする

2-あなた自身のGestureDetectorを作成します

3 - スワイプジェスチャーを検出してsetCurrentItem(item, false)を使う

ViewPager

public class ViewPagerNoSwipe extends ViewPager {
    private final GestureDetector gestureDetector;
    private OnSwipeListener mOnSwipeListener;

    public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
        mOnSwipeListener = onSwipeListener;
    }

    public ViewPagerNoSwipe(@NonNull Context context) {
        super(context);
        gestureDetector = new GestureDetector(context, new GestureListener());

    }

    public ViewPagerNoSwipe(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        gestureDetector = new GestureDetector(context, new GestureListener());


    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        gestureDetector.onTouchEvent(ev);
        return false;
    }

    public class GestureListener extends GestureDetector.SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeRight();
                        } else {
                            if(mOnSwipeListener!=null)
                                mOnSwipeListener.onSwipeLeft();
                        }
                        result = true;
                    }
                } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeBottom();
                    } else {
                        if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeTop();
                    }
                    result = true;
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }

    public interface OnSwipeListener {

         void onSwipeRight();

        void onSwipeLeft();

        void onSwipeTop();

        void onSwipeBottom();
    }
}

viewPagerを設定したときにswipeListenerを設定します。

postsPager.setOnSwipeListener(new ViewPagerNoSwipe.OnSwipeListener() {
            @Override
            public void onSwipeRight() {

              postsPager.setCurrentItem(postsPager.getCurrentItem() + 1,false);

            }

            @Override
            public void onSwipeLeft() {

            postsPager.setCurrentItem(postsPager.getCurrentItem() - 1, false);

            }
             ...
           }
0
tamtom

Kotlinで、私の解決策は、上記の答えを組み合わせたものです。

class CustomViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
    var swipeEnabled = false

    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        return if (swipeEnabled) super.onTouchEvent(ev) else false
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        return if (swipeEnabled) super.onInterceptTouchEvent(ev) else false
    }

    override fun executeKeyEvent(event: KeyEvent): Boolean {
        return if (swipeEnabled) super.executeKeyEvent(event) else false
    }
}
0
Jeff Padgett
This worked for me

viewPager.setOnTouchListener(new View.OnTouchListener() {
                                         @Override
                                         public boolean onTouch(View v, MotionEvent event) {
                                             if (viewPager.getCurrentItem() == 0) {
                                                 viewPager.setCurrentItem(-1, false);
                                                 return true;
                                             }
                                             else if (viewPager.getCurrentItem() == 1) {
                                                 viewPager.setCurrentItem(1, false);
                                                 return true;
                                             }
                                             else if (viewPager.getCurrentItem() == 2) {
                                                 viewPager.setCurrentItem(2, false);
                                                 return true;
                                             }
                                             return true;
                                         }
                                     });
0

上記のコードのどれも円滑に働いていません。私はこれを試しました

<HorizontalScrollView
                    Android:id="@+id/horizontalScrollView"
                    Android:layout_width="match_parent"
                    Android:layout_height="match_parent"
                    Android:fillViewport="true">

                    <Android.support.v4.view.ViewPager
                        Android:id="@+id/pager"
                        Android:layout_width="match_parent"
                        Android:layout_height="match_parent" />
                </HorizontalScrollView>
0
Nandan Singh