Jak wyłączyć stronicowanie, przesuwając palcem w programie ViewPager, ale nadal móc przesuwać programowo?

549

Mam ViewPager, a pod nim mam 10 przycisków. Kliknięcie przycisku, na przykład # 4, powoduje natychmiastowe przejście do strony nr 4 przez mPager.setCurrentItem(3);. Chcę jednak wyłączyć stronicowanie, przesuwając palcem poziomo. Tak więc stronicowanie odbywa się WYŁĄCZNIE poprzez kliknięcie przycisków. Jak mogę wyłączyć przesuwanie palcem?

teista
źródło
Co powiesz na korzystanie z ViewFlipper ? Zaoszczędzi ci to dużo bólu głowy.
Alex Semeniuk

Odpowiedzi:

885

Musisz podklasę ViewPager. onTouchEventzawiera wiele dobrych rzeczy, których nie chcesz zmieniać, na przykład pozwalając, aby widoki dziecka były poprawiane. onInterceptTouchEventjest tym, co chcesz zmienić. Jeśli spojrzysz na kod ViewPager, zobaczysz komentarz:

    /*
     * 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.
     */

Oto kompletne rozwiązanie:

Najpierw dodaj tę klasę do swojego srcfolderu:

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*/);
        }
    }
}

Następnie upewnij się, że używasz tej klasy zamiast zwykłej ViewPager, którą prawdopodobnie określiłeś jako android.support.v4.view.ViewPager. W pliku układu będziesz chciał określić go za pomocą czegoś takiego:

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

Ten konkretny przykład znajduje się w punkcie a LinearLayouti ma zajmować cały ekran, dlatego layout_weightjest to 1, a layout_height0dp.

I setMyScroller();sposób jest płynne przejście

Louielouie
źródło
3
@louielouie Na marginesie: czy istnieje jakiś szczególny powód, dla którego wybrałeś rozwiązanie 0dpwzrost / 1waga zamiast match_parentwzrostu, aby uzyskać efekt pełnoekranowy? Czy zyskujesz dzięki temu poprawę wydajności?
ubuntudroid
28
Ta odpowiedź nie zapobiega przesuwaniu strony podczas używania klawiszy lewo / prawo klawiatury (spróbuj w emulatorze). Może nie stanowić problemu dla urządzeń dotykowych, ale może to być jeden z telewizorami i laptopami.
Vincent Mimoun-Prat
8
@MarvinLabs @Thorbear Prawidłowym sposobem wyłączenia przewijania strony za pomocą klawiatury jest przesłonięcie opcji executeKeyEvent(). Jest to metoda, która następnie wywołuje allowScroll(). // Never allow swiping by keyboard LEFT, RIGHT, TAB and SHIFT+TAB keys @Override public boolean executeKeyEvent(KeyEvent event) { return false; }
araks
6
cóż, to wyłącza także przewijanie w pionie ... to źle, jeśli używasz listviews.
maysi
5
Mam nadzieję, że Google mógł właśnie udostępnić metodę, której dostarczamy naszą metodę interfejsu dotyczącą obsługi dotykania / przeciągania, ponieważ uważam, że nie zaszkodzi?
Neon Warge
466

Bardziej ogólnym rozszerzeniem ViewPagerbyłoby stworzenie SetPagingEnabledmetody umożliwiającej włączanie i wyłączanie stronicowania w locie. Aby włączyć / wyłączyć przesuwanie, po prostu pomiń dwie metody: onTouchEventi onInterceptTouchEvent. Oba zwrócą „fałsz”, jeśli stronicowanie zostało wyłączone.

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

Następnie wybierz to zamiast wbudowanego podglądu w XML

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

Wystarczy wywołać setPagingEnabledmetodę, falsea użytkownicy nie będą mogli przesunąć palcem do strony.

Rajul
źródło
3
Działa idealnie w przypadku widoku, który ma kilka widoków podrzędnych, w których wykorzystuje się przewijanie w poziomie (np. Wykres AChartEngine). W moim fragmencie używam wywołania zwrotnego do mojej aktywności, mówiącego o wyłączeniu lub wyłączeniu stronicowania w zależności od tego, czy użytkownik dotknął (ACTION_MOVE) wykresu, czy go opuścił (ACTION_CANCEL). Wielkie dzięki!
riper
32
Możesz uprościć swoje onTouchEventi onInterceptTouchEventmetody za pomocąreturn enabled && super.onTouchEvent(event);
nbarraille
2
@nbarraille to tylko kwestia stylu. Możesz użyć dowolnego stylu, który wydaje ci się bardziej czytelny.
Rajul
7
Poleciłbym również zmianę nazwy pola z „włączone” na „swipePageChangeEnabled” lub coś w tym rodzaju. Miesiąc po napisaniu kodu prawie nie pamiętasz, co oznacza „włączony”, zwłaszcza gdy twoja klasa nazywa się „CustomViewPager”, gdzie nie jest jasne, na czym polega dostosowanie. To także kwestia stylu, ale styl ma znaczenie, jeśli nie chcesz skończyć z nieobsługiwanym projektem, łatwiej jest całkowicie przepisać niż naprawić.
bytefu,
3
Gdzie mogę wywołać setPagingEnabled? ._.
Ntikki
107

Najprostszym sposobem jest setOnTouchListeneri powrotu truedo ViewPager.

mPager.setOnTouchListener(new OnTouchListener()
    {           
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            return true;
        }
    });
Wayne
źródło
53
Czasami nie działa. Używam ViewPager z FragmentPagerAdapter i kilkoma Fragmentami. Po ustawieniu OnTouchListener na pager, jeśli rzucę się w lewo, interfejs użytkownika nadal przesunie się trochę w lewo.
Chris.Zou,
16
Działa, gdy dodajesz pager.setCurrentItem(pager.getCurrentItem());przed powrotem true.
dng
1
wcześniej mi to działało. nie mam pojęcia, dlaczego to już nie działa dobrze.
programista Androida
wydaje się działać dla mnie. Aby rozwiązać niektóre problemy z układem, które mam public int getItemPosition(Object object) { return POSITION_NONE; }w moim adapterze, co wymusza odtwarzanie stron i może również rozwiązywanie innych problemów.
r-hold
6
To jest częściowo działające rozwiązanie. Poziome przeciągnięcia są obsługiwane w jakiś dziwny sposób. Przetestowałem to za pomocą Drag'n Drop Gridview jako części ViewPager. Podczas przeciągania za pomocą tego rozwiązania przeciąganie od lewej do prawej i od prawej do lewej kończy się niepowodzeniem. Osobiście uważam, że podejście Rajula jest najlepsze.
Ton Snoei,
58

Lepiej zadeklarować stylowość, aby można było zmienić jego właściwość z 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;
}

A w twoich wartościach / attr.xml:

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

abyś mógł go używać w swoim układzie 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" />

Oczywiście nadal możesz mieć właściwość get / set.

Pietro
źródło
58

Przesłanianie tylko onTouchEventi onInterceptTouchEventnie jest wystarczające, jeśli masz ViewPager w innym ViewPager. Dziecko ViewPager kradnie zdarzenia dotyku przewijania w poziomie od nadrzędnego ViewPager, chyba że zostanie umieszczony na pierwszej / ostatniej stronie.

Aby ta konfiguracja działała poprawnie, musisz zastąpić również canScrollHorizontallymetodę.

Zobacz LockableViewPagerimplementację poniżej.

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

}
Sidon
źródło
3
Dziękuję, działa to bardzo dobrze na ViewPager w innym ViewPager.
Fernanda Bari
1
To działa dla mnie, także dla ViewPager w innym ViewPager. W takim przypadku poprawne rozwiązanie nie działało dla mnie.
Rafael Ruiz Muñoz
zatrzymuje także animację, gdy jest używana w kartach.
Rishabh Srivastava
Jeśli ją wyłączę i przypuszczam, że chcę ją włączyć, to gdzie mogę uzyskać zdarzenie wywołujące setSwipeLocked (false)?
Ravi Yadav
57

Teraz nie musimy tworzyć niestandardowych ViewPager

Nowa ViewPager2 nazwa Zobacz dostępna w Androidzie

Obsługa orientacji pionowej

  • ViewPager2obsługuje tradycyjne stronicowanie oprócz tradycyjnego poziomego stronicowania. Możesz włączyć stronicowanie pionowe dla ViewPager2elementu, ustawiając jego android:orientationatrybut

Korzystanie z XML

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:orientation="vertical" />

Za pomocą kodu

Aby wyłączyć przeciąganie w viewpager2użyciu

viewPager2.setUserInputEnabled(false);

Aby włączyć przesuwanie w viewpager2użyciu

viewPager2.setUserInputEnabled(true);

Aby uzyskać więcej informacji, sprawdź to

AKTUALIZACJA

Nilesh Rathod
źródło
3
Jest świetny, ale wciąż wydaje się niekompletny. Próbowałem go z 5 różnych fragmentów i po przełączeniu między stronami jeden z fragmentów był trochę zagubiony, czyli widok nie był ani przywrócona ani re-napompowane
Toochka
@Toochka przykro mi to słyszeć, że dla mnie działa dobrze, możesz znaleźć przykładowy kod roboczy stąd stackoverflow.com/a/54643817/7666442 jeśli to możliwe, proszę udostępnij swój kod
Nilesh Rathod
1
Mogłem z powodzeniem wyłączyć przeciąganie w ViewPager2 przy użyciu tej metody
voghDev
1
@voghDev z przyjemnością to słyszy
Nilesh Rathod
1
@PhaniRithvij proszę sprawdzić tę odpowiedź stackoverflow.com/a/54643817/7666442 i Dodałem wszystkie szczegóły dotyczące korzystania viewpager2zRecyclerView.Adapter
Nilesh Rathod
35

Jeśli korzystasz z ViewPager, musisz również zastąpić,executeKeyEvent jak wskazano wcześniej przez @araks

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

Ponieważ niektóre urządzenia, takie jak Galaxy Tab 4 10 ', pokazują te przyciski, w których większość urządzeń nigdy ich nie pokazuje:

Przyciski klawiatury

Smar
źródło
50
Samsung zawsze psuje rzeczy deweloperom Androida.
toobsco42,
2
@ toobsco42 Samsung nie jest sam w tym przypadku. SwiftKey (popularna aplikacja na klawiaturę) pozwala użytkownikom umieszczać strzałki na klawiaturze.
Sufian
1
Jest to również poprawka, jeśli chcesz, aby ktoś korzystający z klawiatury / trackera nie stronicował twojego pagera.
se22as
28

Aby wyłączyć przeciąganie

mViewPager.beginFakeDrag();

Aby włączyć przesuwanie

mViewPager.endFakeDrag();
KAMAL VERMA
źródło
22
To nie jest dobre rozwiązanie, ponieważ pozwala na małe ruchy, przynajmniej w mojej aplikacji.
koras
Działa dobrze dla mnie. Jakie są wady w porównaniu z innymi oferowanymi rozwiązaniami?
userM1433372
13

Musiałem wyłączyć przesuwanie po jednej określonej stronie i nadać mu ładną animację z gumką, oto jak:

    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);
            }
        }
Oded Breiner
źródło
Czeka, aż kolejna strona będzie częściowo widoczna. Kod dla następnej strony onPageSelectedzostanie wykonany. Przełącza się nawet następna strona. Więc ten kod nie jest potrzebny.
CoolMind
13

Wiem, że jest bardzo późno, aby to opublikować, ale oto mały hack, aby osiągnąć swój wynik;)

Po prostu dodaj fikcyjny widok poniżej przeglądarki:

<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>

Następnie dodaj a OnClickListenerdo swojego RelativeLayout.

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

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

Zachowaj kreatywność dzięki układom, ich rozmieszczeniu i zachowaniu, a nauczysz się znaleźć sposób na zrobienie absolutnie wszystkiego, co sobie wyobrażasz :)

Powodzenia!

Dinuka Jay
źródło
Łatwiejszym sposobem jest użycie setClickablezamiast setOnClickListener, jeśli nie trzeba obsługiwać onClickzdarzenia.
Chaos
czy nie blokuje to również dotknięć w przeglądarce?
programista Androida
Tak, to będzie. Jest to oczekiwane zachowanie wymagane przez OP @androiddeveloper
Dinuka Jay
@RickGrimesTheCoder Nie sądzę, że zrozumiałeś moje pytanie. Mam na myśli widoki we fragmentach przeglądarki. Czy nadal będą dotykalne?
programista Androida
Nie, nie będą, ponieważ sam viewpager ma detektor kliknięć. Jest to odpowiednie tylko w przypadkach, gdy nie masz interaktywnych elementów w obrębie fragmentów. Na przykład Welcome ViewPager, który dynamicznie zmienia swoje fragmenty @androiddeveloper
Dinuka Jay
12

Napisałem CustomViewPagerz kontrolką przeciągania:

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

Jeśli ustawisz canScrolldo truetego ViewPagermożna przesuwając palcem, falsea wręcz przeciwnie.

Używam tego w moim projekcie i do tej pory działa świetnie.

L. Swifter
źródło
1
Co jeśli mam przycisk wewnątrz ViewPager i chcę kliknąć? to rozwiązanie zatrzymuje klikanie wszystkiego poniżej przeglądarki.
aimiliano,
6

Z powodzeniem wykorzystałem tę klasę. Przesłonięcie executeKeyEvent jest wymagane, aby uniknąć przesuwania za pomocą strzałek w niektórych urządzeniach lub w celu ułatwienia dostępu:

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

}

A w xml nazwij to tak:

<package.path.ViewPagerNoSwipe
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
madx
źródło
To działa. Wyłączone jest tylko przesunięcie, a kliknięcie karty jest włączone. AS ostrzega, że performClick()metoda nie jest przesłonięta.
CoolMind,
5

W Kotlinie moje rozwiązanie, łączące powyższe odpowiedzi.

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
    }
}
Jeff Padgett
źródło
Przesłonięcie onInterceptTouchEvent()uniemożliwi otrzymanie danych wejściowych przez widoki potomne. W większości przypadków nie jest to zamierzone zachowanie.
Alex Semeniuk
Byłem w stanie wchodzić w interakcje z widokami dziecka każdego fragmentu. Nie jestem pewien, o czym mówisz.
Jeff Padgett,
5

W kotlin możemy to rozwiązać, tworząc niestandardowy widget dziedziczący klasę ViewPager i dodając wartość flagi do kontrolowania zachowania podczas przeciągania.

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

W 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" />

Wyłącz przesuwanie programowo. Jeśli kotlin-android-extensionswtyczka zostanie zastosowana w build.gradle , przesuwanie można wyłączyć, pisząc poniżej kodu.

view_pager.pagingEnabled = false

W przeciwnym razie możemy wyłączyć przesuwanie za pomocą kodu poniżej:

val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false
Sagar Chapagain
źródło
Przesłonięcie onInterceptTouchEvent()uniemożliwi otrzymanie danych wejściowych przez widoki potomne. W większości przypadków nie jest to zamierzone zachowanie.
Alex Semeniuk
@AlexSemeniuk Czy zauważyłeś jakiś problem po wdrożeniu tego? Włączyłem przeciąganie elementów widoku recyklera dla niektórych działań i działa dobrze. W moim przypadku wdrożenie działa dobrze.
Sagar Chapagain
Sagar Chapagain: lub oczywiście, że tak. Każda z moich stron zawiera własny widok, który przetwarza dotyk na różne sposoby (w tym przewijanie, przeciąganie, pojedyncze i długie dotknięcia). Brak wywołania super.onInterceptTouchEvent(event)powoduje, że te widoki nie otrzymują żadnych danych wejściowych (co jest udokumentowanym celem onInterceptTouchEventmetody).
Alex Semeniuk
W takim przypadku powinieneś raczej użyć fragmentu potomnego i zachować backstack.
Sagar Chapagain 17.07.19
Jak to się ma do obecnego pytania? Fragmenty są umieszczane w niektórych kontenerach (które są widokami ), a ich własny układ zawiera widoki . Bez względu na to, jaką zawartość mam w ViewPager, wciąż mam do czynienia z faktem, że onInterceptTouchEvent()metoda przesłonięcia zapobiega otrzymywaniu danych wejściowych przez (treść).
Alex Semeniuk
1

Kolejne łatwe rozwiązanie, aby wyłączyć przesuwanie na określonej stronie (w tym przykładzie strona 2):

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;
}
Ofir
źródło
1
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;
                                         }
                                     });
Princewill Iroka
źródło
1

Jeśli napiszesz galerię zdjęć za pomocą ImageView si ViewPager, która obsługuje powiększanie i przesuwanie, zapoznaj się z prostym rozwiązaniem opisanym tutaj: Implementowanie powiększalnego ImageView poprzez rozszerzenie domyślnego ViewPager w Phimpme Android (i próbka Github - PhotoView ). To rozwiązanie nie działa ViewPagersamodzielnie.

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;
        }
    }
}
CoolMind
źródło
0

Jeśli chcesz zaimplementować to samo dla Androida w Xamarin, oto tłumaczenie na C #

Zdecydowałem się nazwać atrybut „ ScrollEnabled ”. Ponieważ iOS używa właśnie tego samego nazewnictwa. Tak więc masz taką samą nazwę na obu platformach, co ułatwia programistom.

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

W pliku .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>
Lepidopteron
źródło
0

Żaden z powyższych kodów nie działa płynnie. Próbowałem tego

<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>
Nandan Singh
źródło
0

oto moja implementacja,
że jeśli chcesz wyłączyć animację przesuwania, możesz użyć swipeListener w lewo i prawo i nadal chcesz przewijać palcem, ale bez animacji

ViewpagerMetoda 1-Zastąp onInterceptTouchEventionTouchEvent

2- stwórz swój własny GestureDetector

3- wykryj gest machnięcia i użyj 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();
    }
}

podczas konfigurowania ViewPager ustaw 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);

            }
             ...
           }
tamtom
źródło
0

Właśnie dostosowałem trochę przeglądarkę i łatwo wyłączam przesuwanie.

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);
}
}
Shivam Yadav
źródło
0

Jeśli używasz ViewPager2, musisz po prostu użyć:

viewpager.setUserInputEnabled(false);

Z dokumentów :

Włącz lub wyłącz przewijanie inicjowane przez użytkownika. Obejmuje to wprowadzanie dotykowe (przewijanie i gesty przewijania) oraz wprowadzanie ułatwień dostępu. Wyłączanie klawiatury nie jest jeszcze obsługiwane. Gdy przewijanie inicjowane przez użytkownika jest wyłączone, programowe przewijanie przez setCurrentItem nadal działa. Domyślnie przewijanie inicjowane przez użytkownika jest włączone.

Dzięki: https://stackoverflow.com/a/61685871/9026710

Tayyab Mazhar
źródło
-1
shareViewPager?.setOnTouchListener(object :View.OnTouchListener{
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                for (PAGE in 0..shareViewPager.adapter!!.count){
                    if (shareViewPager.currentItem==PAGE){
                        shareViewPager.setCurrentItem(PAGE-1,false)
                        shareViewPager.setCurrentItem(PAGE,false)
                    }}
                return true
            }

        })
Cihat Baydan
źródło