Como desativar a paginação deslizando com o dedo no ViewPager, mas ainda assim é possível deslizar programaticamente?

550

Eu tenho o ViewPager e abaixo dele tenho 10 botões. Ao clicar no botão, por exemplo # 4, o pager vai imediatamente para a página # 4 por mPager.setCurrentItem(3);. Mas, eu quero desativar a paginação passando o dedo na horizontal. Assim, a paginação é feita SOMENTE clicando nos botões. Então, como posso desativar a passagem com o dedo?

teatral
fonte
Que tal usar o ViewFlipper em primeiro lugar? Isso poupará muita dor de cabeça.
Alex Semeniuk

Respostas:

885

Você precisa subclassificar ViewPager. onTouchEventpossui muitas coisas boas que você não deseja alterar, como permitir que as visualizações de crianças sejam tocadas. onInterceptTouchEventé o que você quer mudar. Se você procurar o código ViewPager, verá o comentário:

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

Aqui está uma solução completa:

Primeiro, adicione esta classe à sua srcpasta:

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

Em seguida, certifique-se de usar essa classe em vez da regular ViewPager, que você provavelmente especificou como android.support.v4.view.ViewPager. No seu arquivo de layout, você deve especificá-lo com algo como:

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

Este exemplo em particular está em um LinearLayoute pretende ocupar a tela inteira, e é por isso quelayout_weight é 1 e layout_heighté 0dp.

E o setMyScroller();método é para uma transição suave

louielouie
fonte
3
@louielouie Em uma nota lateral: existe algum motivo em particular, por que você escolheu a solução de 0dpaltura / 1peso sobre a match_parentaltura para obter o efeito de tela cheia? Você obtém melhorias de desempenho fazendo isso?
Ubuntudroid
29
Esta resposta não impede o deslizamento de página ao usar as teclas esquerda / direita do teclado (tente no emulador). Pode não ser um problema para dispositivos de toque, mas com TV e laptops pode ser um.
Vincent Mimoun-Prat
8
@MarvinLabs @Thorbear A maneira correta de desativar a rolagem da página pelo teclado é substituir o executeKeyEvent(). Este é o método que então chama allowScroll(). // Never allow swiping by keyboard LEFT, RIGHT, TAB and SHIFT+TAB keys @Override public boolean executeKeyEvent(KeyEvent event) { return false; }
Araks
6
bem, isso desativa também a rolagem vertical ... isso é ruim, se você estiver usando listviews.
Maysi
5
Espero que o Google possa ter fornecido apenas um método ao qual fornecemos nosso método de interface sobre como lidar com toques / deslizamentos, porque acredito que não faria mal?
Neon Warge
466

A extensão mais geral ViewPagerseria criar um SetPagingEnabledmétodo para que possamos ativar e desativar a paginação em tempo real. Para ativar / desativar a passagem, basta substituir dois métodos: onTouchEvente onInterceptTouchEvent. Ambos retornarão "false" se a paginação foi desativada.

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

Em seguida, selecione isso em vez do viewpager interno em XML

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

Você só precisa chamar o setPagingEnabledmétodo falsee os usuários não poderão deslizar para paginar.

Rajul
fonte
3
Funciona perfeitamente para uma exibição que possui várias subvisões em que se usa rolagem horizontal (por exemplo, gráfico AChartEngine). No meu fragmento, uso um retorno de chamada para minha atividade dizendo para desativar ou desativar a paginação, dependendo se o usuário tocou (ACTION_MOVE) no gráfico ou o deixou (ACTION_CANCEL). Muito obrigado!
maduras
32
Você pode simplificar suas onTouchEvente onInterceptTouchEventmétodos comreturn enabled && super.onTouchEvent(event);
nbarraille
2
@nbarraille isso é apenas uma questão de estilo. Você pode usar qualquer estilo que lhe parecer mais legível.
Rajul 22/08/14
7
Eu também recomendaria alterar o nome do campo de "enabled" para "swipePageChangeEnabled" ou algo assim. Um mês após escrever o código, você dificilmente se lembrará do que "ativado" significa, especialmente quando sua classe é chamada "CustomViewPager", onde não está claro qual é a personalização. Isso também é uma questão de estilo, mas o estilo é importante se você não quiser terminar com um projeto não suportável, que é mais fácil reescrever completamente do que corrigi-lo.
Bytefu
4
Onde eu chamo setPagingEnabled? ._.
Ntikki 6/11/15
107

A maneira mais simples é setOnTouchListenere retorno truepara ViewPager.

mPager.setOnTouchListener(new OnTouchListener()
    {           
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            return true;
        }
    });
Wayne
fonte
53
Às vezes não funciona. Estou usando um ViewPager com um FragmentPagerAdapter e vários fragmentos. Depois de definir OnTouchListener como pager, se eu atirar para a esquerda, a interface do usuário ainda se moverá para a esquerda um pouco.
26413 Chris_Zou
16
Funciona quando você adiciona pager.setCurrentItem(pager.getCurrentItem());antes de retornar true.
dng 18/09/13
1
funcionou para mim antes. Não faço ideia por que não funciona mais.
desenvolvedor android
Parece funcionar para mim. Para resolver algumas falhas de layout que tenho public int getItemPosition(Object object) { return POSITION_NONE; }no meu adaptador, o que força a recriação de páginas e talvez a solução de outros problemas também.
r-hold
6
Esta é uma solução que funciona parcialmente. Os furtos horizontais são tratados de uma maneira estranha. Eu testei isso com um Drag'n Drop Gridview como parte de um ViewPager. Ao arrastar usando esta solução, o arrasto da esquerda para a direita e da direita para a esquerda falha. Pessoalmente, acho a abordagem de Rajul a melhor.
Ton Snoei
58

Melhor declará-lo estiloso, para que você possa alterar sua propriedade de 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;
}

E em seus valores / attr.xml:

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

para que você possa usá-lo em seu layout 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" />

Obviamente, você ainda pode ter uma propriedade get / set.

Pietro
fonte
58

Substituindo apenas onTouchEventeonInterceptTouchEvent não é suficiente caso você tenha o ViewPager em outro ViewPager. O Child ViewPager roubaria os eventos de toque de rolagem horizontal do ViewPager pai, a menos que esteja posicionado na primeira / última página.

Para fazer essa configuração funcionar corretamente, você também precisa substituir o canScrollHorizontallymétodo.

Veja a LockableViewPagerimplementação abaixo.

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
fonte
3
Obrigado, isso funciona muito bem em um ViewPager dentro de outro ViewPager.
Fernanda Bari
1
Isso funciona para mim, também para um ViewPager dentro de outro ViewPager. A solução correta não funcionou para mim nesse caso.
Rafael Ruiz Muñoz
para a animação também quando usado em guias.
Rishabh Srivastava
Se eu desativá-lo e suponho que quero ativá-lo, onde posso obter o evento para chamar setSwipeLocked (false)?
Ravi Yadav
58

Agora não precisamos criar customizações ViewPager

Um novo ViewPager2 nome Ver disponível no android

Suporte de orientação vertical

  • ViewPager2suporta paginação vertical, além da paginação horizontal tradicional. Você pode ativar a paginação vertical para um ViewPager2elemento configurando seu android:orientationatributo

Usando XML

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

Usando código

Para desativar a passagem em viewpager2uso

viewPager2.setUserInputEnabled(false);

Para habilitar o viewpager2uso em Usar

viewPager2.setUserInputEnabled(true);

para mais informações, verifique isto

ATUALIZAR

Nilesh Rathod
fonte
3
É ótimo, mas ainda parece incompleto. Eu tentei-o para fora com 5 fragmentos diferentes e depois de alternar entre as páginas um dos fragmentos estava meio perdido, ou seja vista não foi nem restaurado nem re-inflados
Toochka
@Toochka muito em ouvir isso para mim é trabalhar bem, você pode encontrar o código de trabalho de amostra a partir daqui stackoverflow.com/a/54643817/7666442 se possível por favor, compartilhe o seu código
Nilesh Rathod
1
Eu poderia desativar com sucesso swiping em um ViewPager2 utilizando este método
voghDev
1
@voghDev feliz em ouvir isso #
Nilesh Rathod
1
@PhaniRithvij, verifique esta resposta stackoverflow.com/a/54643817/7666442 i Adicionei todos os detalhes de como usar viewpager2com #RecyclerView.Adapter
Nilesh Rathod
35

Se você estiver estendendo do ViewPager, também deverá substituirexecuteKeyEvent como indicado anteriormente por @araks

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

Como alguns dispositivos como o Galaxy Tab 4 10 'mostram esses botões onde a maioria dos dispositivos nunca os mostra:

Botões do teclado

Graxa
fonte
50
A Samsung está sempre estragando tudo para os desenvolvedores do Android.
toobsco42
2
@ toobsco42 A Samsung não está sozinha nesse caso. O SwiftKey (aplicativo de teclado popular) permite que os usuários coloquem flechas nos teclados.
Sufian 29/11
1
Essa também é a correção, se você deseja impedir que alguém usando uma bola de teclado / tracker pagine seu pager.
se22as
28

Para desativar o furto

mViewPager.beginFakeDrag();

Para ativar o furto

mViewPager.endFakeDrag();
KAMAL VERMA
fonte
22
Não é uma boa solução, pois permite pequenas porções de movimento, pelo menos no meu aplicativo.
Koras
Funciona bem para mim. Quais são as desvantagens em comparação com as outras soluções fornecidas?
userM1433372
13

Eu precisava desativar o deslize em uma página específica e dar uma ótima animação com elástico, eis como:

    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
fonte
Aguarda até que a próxima página esteja parcialmente visível. Um código para a próxima página onPageSelectedserá executado. Até a próxima página mudará. Portanto, esse código não é necessário.
CoolMind
13

Eu sei que é muito tarde para postar isso, mas aqui está um pequeno truque para alcançar seu resultado;)

Basta adicionar uma visualização simulada abaixo do seu 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>

Em seguida, adicione um OnClickListenerao seu RelativeLayout.

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

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

Seja um pouco criativo com layouts, canais e comportamento e aprenderá a encontrar uma maneira de fazer absolutamente tudo o que imaginar :)

Boa sorte!

Dinuka Jay
fonte
Uma maneira mais fácil é usar, em setClickablevez de setOnClickListener, se você não precisar manipular onClickeventos.
Caos
isso também não bloqueia toques no viewpager?
desenvolvedor android
Sim vai. É o comportamento esperado exigido pelo OP @androiddeveloper
Dinuka Jay
@RickGrimesTheCoder Acho que você não entendeu minha pergunta. Quero dizer visualizações dentro dos fragmentos do viewpager. Eles ainda serão tocáveis?
desenvolvedor android
Não, eles não serão, uma vez que o próprio viewpager possui um ouvinte de clique. Isso é adequado apenas para casos em que você não possui elementos interativos nos fragmentos. Por exemplo, um Bem-vindo ViewPager que muda seus fragmentos dinamicamente @androiddeveloper
Dinuka Jay
12

Eu escrevi um CustomViewPagercom um controle swiping:

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

Se você definir canScrolla true, este ViewPagerpode ser passando com o dedo, falsepelo contrário.

Eu uso isso no meu projeto e funciona muito bem até agora.

L. Swifter
fonte
1
E se eu tiver um botão dentro do ViewPager e desejar o clique? esta solução pára tudo abaixo viewpager de ser clicado ..
aimiliano
6

Eu usei essa aula com sucesso. É necessário substituir o executeKeyEvent para evitar o uso de setas em alguns dispositivos ou para acessibilidade:

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

}

E no xml chame assim:

<package.path.ViewPagerNoSwipe
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
madx
fonte
Funciona. Apenas o furto está desativado e o clique em uma guia está ativado. AS avisa que o performClick()método não é substituído.
CoolMind
5

Em Kotlin, minha solução, combinando as respostas acima.

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
fonte
A substituição onInterceptTouchEvent()impedirá que as visualizações secundárias recebam entrada. Na maioria dos casos, esse não é o comportamento pretendido.
Alex Semeniuk
Consegui interagir com as visões filho de cada fragmento. Não sei ao que você está se referindo.
21919 Jeff Padgett
5

No kotlin, podemos resolver isso criando um widget personalizado que herda a classe ViewPager e adicionando um valor de sinalizador para controlar o comportamento do furto.

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

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

Desative a passagem programada. Se o kotlin-android-extensionsplug-in for aplicado no build.gradle , a passagem pode ser desativada escrevendo o código abaixo.

view_pager.pagingEnabled = false

Caso contrário, podemos desativar a passagem usando o código abaixo:

val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false
Sagar Chapagain
fonte
A substituição onInterceptTouchEvent()impedirá que as visualizações secundárias recebam entrada. Na maioria dos casos, esse não é o comportamento pretendido.
Alex Semeniuk
@AlexSemeniuk Você observou algum problema depois de implementar isso? Eu havia ativado a passagem de itens de exibição do reciclador para algumas ações e está funcionando bem. Portanto, a implementação está funcionando bem no meu caso.
Sagar Chapagain
Sagar Chapagain: claro que sim. Cada uma das minhas páginas contém uma visualização personalizada, que processa os toques de várias maneiras (incluindo rolagem, arraste, toques simples e longos). Não chamar super.onInterceptTouchEvent(event)resultados nessas visualizações não recebe nenhuma entrada (que é o objetivo documentado do onInterceptTouchEventmétodo).
Alex Semeniuk
Se for esse o caso, você deve usar um fragmento filho e manter o backstack.
Sagar Chapagain 17/07/19
Como isso é relevante para a questão atual? Fragmentos são colocados dentro de alguns contêineres (que são Views ) e seu próprio layout contém Views . Independentemente do conteúdo que possuo no ViewPager, ainda estou lidando com o fato de que o onInterceptTouchEvent()método de substituição impede que ele (conteúdo) receba entrada.
Alex Semeniuk
4

Tente substituir e retornar true de onInterceptTouchEvent () e / ou onTouchEvent () , que consumirá eventos de toque no pager.

AdamK
fonte
1
ele não gostaria de voltar truepara sugerir que o evento de toque foi tratado?
edthethird
1

Outra solução fácil para desativar o swiping em uma página específica (neste exemplo, página 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
fonte
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
fonte
1

Se você escrever uma galeria de imagens com ImageViews e ViewPagercompatível com zoom e pan, consulte uma solução simples descrita aqui: Implementando um ImageView com zoom estendendo o ViewPager padrão no Phimpme Android (e amostra do Github - PhotoView ). Esta solução não funciona ViewPagersozinha.

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

Se você estiver usando o ViewPager2, basta usar:

viewpager.setUserInputEnabled(false);

Dos documentos :

Ativar ou desativar a rolagem iniciada pelo usuário. Isso inclui entrada por toque (gestos de rolagem e arremesso) e entrada de acessibilidade. A desativação da entrada do teclado ainda não é suportada. Quando a rolagem iniciada pelo usuário é desabilitada, as rolagens programáticas pelo setCurrentItem ainda funcionam. Por padrão, a rolagem iniciada pelo usuário está ativada.

Obrigado a: https://stackoverflow.com/a/61685871/9026710

Tayyab Mazhar
fonte
0

Se você deseja implementar o mesmo para Android no Xamarin, aqui está uma tradução para C #

Eu escolhi o nome do atributo " ScrollEnabled ". Porque o iOS usa exatamente o mesmo nome. Portanto, você tem nomes iguais nas duas plataformas, facilitando para os desenvolvedores.

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

No arquivo .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
fonte
0

Nenhum do código acima está funcionando corretamente. Tentei isso

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

aqui está minha implementação
se você deseja desativar a animação de furto, pode usar o swipeListener para a esquerda e para a direita e ainda deseja rolar o dedo, mas sem animação

ViewpagerMétodo 1-Override onInterceptTouchEventeonTouchEvent

2- crie o seu próprio GestureDetector

3- detectar o gesto de furto e usar o 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();
    }
}

Quando você estiver configurando o ViewPager, defina o 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
fonte
0

Acabei de personalizar um pouco o viewpager e desabilito o swiping facilmente.

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