Как отключить пейджинг, проводя пальцем в ViewPager, но все же иметь возможность проводить программно? - PullRequest
489 голосов
/ 11 марта 2012

У меня есть ViewPager и под ним у меня 10 кнопок.При нажатии на кнопку, например # 4, пейджер сразу переходит на страницу № 4 по mPager.setCurrentItem(3);.Но я хочу отключить пейджинг, проводя пальцем по горизонтали.Таким образом, пейджинг осуществляется ТОЛЬКО нажатием на кнопки.Итак, как я могу отключить смахивание пальцем?

Ответы [ 23 ]

838 голосов
/ 11 марта 2012

Вам нужно создать подкласс 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*/);
        }
    }
}

Далее, убедитесь, что используете этот класс вместо обычного ViewPager, который вы, вероятно, указали как android.support.v4.view.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 равен 0 дп.

А setMyScroller(); Метод для плавного перехода

441 голосов
/ 18 ноября 2012

Более общим расширением ViewPager будет создание метода SetPagingEnabled, чтобы мы могли включать и отключать пейджинг на лету. Чтобы включить / отключить считывание, просто измените два метода: onTouchEvent и onInterceptTouchEvent. Обе вернутся «ложь», если подкачка была отключена.

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, и пользователи не смогут пролистывать страницы.

101 голосов
/ 15 ноября 2012

Самый простой способ - setOnTouchListener и возврат true для ViewPager.

mPager.setOnTouchListener(new OnTouchListener()
    {           
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            return true;
        }
    });
53 голосов
/ 05 января 2016

Только переопределение onTouchEvent и onInterceptTouchEvent недостаточно, если у вас есть сам 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);
    }

}
53 голосов
/ 08 сентября 2013

Лучше объявить его в стиле, так что вы можете изменить его свойство с 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;
}

А в ваших ценностях / 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.

29 голосов
/ 01 августа 2016

Если вы выходите из ViewPager, вы также должны переопределить executeKeyEvent, как указано ранее @araks

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

Поскольку некоторые устройства, такие как Galaxy Tab 4 10 ', показывают этикнопки, на которых большинство устройств их не отображают:

Keyboard buttons

28 голосов
/ 16 марта 2016

Для отключения свайпа

mViewPager.beginFakeDrag();

Для включения прокрутки

mViewPager.endFakeDrag();
13 голосов
/ 27 июня 2015

Мне нужно было отключить перелистывание на одной конкретной странице и дать ему хорошую анимацию с резинкой, вот как:

    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);
            }
        }
11 голосов
/ 12 мая 2016

Я знаю, что это очень поздно, чтобы опубликовать это, но вот крошечный хак для достижения вашего результата;)

Просто добавьте фиктивный вид ниже Ваш пейджер:

<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 голосов
/ 14 апреля 2016

Я написал 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);
    }
}

Если вы установите canScroll на true, этот ViewPager может быть проведен пальцем, false наоборот.

Я использую это в своем проекте, и он прекрасно работает до сих пор.

...