Android: ViewPager vertical [fechado]

130

Existe uma maneira de fazer um ViewPagerque não role horizontalmente, mas verticalmente ?!

user1709805
fonte
1
Há uma nova implementação open source não oficial de um ViewPager vertical: Anúncio: plus.google.com/107777704046743444096/posts/1FTJfrvnY8w cupom: github.com/LambergaR/VerticalViewPager
Vasily Sochinsky
Implementação vista pager Vertical por Antoine Merle: github.com/castorflex/VerticalViewPager
micnoy
Há uma nova implementação baseada na biblioteca de suporte 19: github.com/castorflex/VerticalViewPager
Vasily Sochinsky
Não é o mesmo que github.com/castorflex/VerticalViewPager , apesar de ter um nome semelhante.
Flimm
1
Existe um controle chamado ViewPager2, verifique aqui a demonstração stackoverflow.com/a/54643817/7666442
Nilesh Rathod

Respostas:

227

Você pode usar um ViewPager.PageTransformer para dar a ilusão de uma vertical ViewPager. Para conseguir rolagem com um arrasto vertical em vez de horizontal, você terá que substituir ViewPageros eventos de toque padrão e trocar as coordenadas de MotionEvents antes de manipulá-los, por exemplo:

/**
 * Uses a combination of a PageTransformer and swapping X & Y coordinates
 * of touch events to create the illusion of a vertically scrolling ViewPager. 
 * 
 * Requires API 11+
 * 
 */
public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        super(context);
        init();
    }

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

    private void init() {
        // The majority of the magic happens here
        setPageTransformer(true, new VerticalPageTransformer());
        // The easiest way to get rid of the overscroll drawing that happens on the left and right
        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements ViewPager.PageTransformer {

        @Override
        public void transformPage(View view, float position) {

            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);

            } else if (position <= 1) { // [-1,1]
                view.setAlpha(1);

                // Counteract the default slide transition
                view.setTranslationX(view.getWidth() * -position);

                //set Y position to swipe in from top
                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);

            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

    /**
     * Swaps the X and Y coordinates of your touch event.
     */
    private MotionEvent swapXY(MotionEvent ev) {
        float width = getWidth();
        float height = getHeight();

        float newX = (ev.getY() / height) * width;
        float newY = (ev.getX() / width) * height;

        ev.setLocation(newX, newY);

        return ev;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev){
        boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
        swapXY(ev); // return touch coordinates to original reference frame for any child views
        return intercepted;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(swapXY(ev));
    }

}

Claro que você pode ajustar essas configurações como achar melhor. Termina assim:

Demonstração do VerticalViewPager

Brett
fonte
3
@ Der Golem como usar o layout para isso?
bShah
Qual é a pergunta exata? A propósito, eu não postei a resposta, apenas adicionei a imagem referida.
Phantômaxx
1
@Brett neste exemplo, quero executar alguma ação ao deslizar para a esquerda e para a direita. como fazer isso #
Prabs
1
@Brett funciona como esperado, a transição está tomando verticalmente. Mas o problema é que eu tenho que deslizar para a direita / esquerda para fazer a transição e, ao deslizar para cima / baixo, nenhuma transição ocorre.
Karan Khurana
2
@Brett Eu estava usando sua solução. mas agora estou recebendo o problema de swipping nos dispositivos de torta andorid. Alguém está enfrentando o mesmo problema?
Jishant
20

Vertical ViewPager

As outras respostas aqui pareciam ter alguns problemas com elas. Mesmo os projetos de código aberto recomendados não estavam mesclando solicitações de recebimento recentes com correções de bugs. Então eu achei um VerticalViewPagerdo Google que eles usavam algum aplicativo DeskClock. Confio em usar a implementação do Google muito mais do que as outras respostas que circulam por aqui. (A versão do Google é semelhante à atual resposta mais votada, mas mais completa.)

Exemplo completo

Este exemplo é quase exatamente o mesmo que meu exemplo básico do ViewPager , com algumas pequenas alterações para fazer uso da VerticalViewPagerclasse.

insira a descrição da imagem aqui

XML

Adicione os layouts de xml para a atividade principal e para cada página (fragmento). Observe que usamos VerticalViewPagermais do que o padrão ViewPager. Vou incluir o código para isso abaixo.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.verticalviewpager.MainActivity">

    <com.example.myapp.VerticalViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

fragment_one.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textview"
        android:textSize="30sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

Código

O código para o VerticalViewPagernão é meu. É apenas uma versão simplificada (sem comentários) do código-fonte do Google. Confira esse para a versão mais atualizada. Os comentários também são úteis para entender o que está acontecendo.

VerticalViewPager.java

import android.support.v4.view.ViewPager;    

public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        this(context, null);
    }

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

    @Override
    public boolean canScrollHorizontally(int direction) {
        return false;
    }

    @Override
    public boolean canScrollVertically(int direction) {
        return super.canScrollHorizontally(direction);
    }

    private void init() {
        setPageTransformer(true, new VerticalPageTransformer());
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final boolean toIntercept = super.onInterceptTouchEvent(flipXY(ev));
        flipXY(ev);
        return toIntercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final boolean toHandle = super.onTouchEvent(flipXY(ev));
        flipXY(ev);
        return toHandle;
    }

    private MotionEvent flipXY(MotionEvent ev) {
        final float width = getWidth();
        final float height = getHeight();
        final float x = (ev.getY() / height) * width;
        final float y = (ev.getX() / width) * height;
        ev.setLocation(x, y);
        return ev;
    }

    private static final class VerticalPageTransformer implements ViewPager.PageTransformer {
        @Override
        public void transformPage(View view, float position) {
            final int pageWidth = view.getWidth();
            final int pageHeight = view.getHeight();
            if (position < -1) {
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);
                view.setTranslationX(pageWidth * -position);
                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);
            } else {
                view.setAlpha(0);
            }
        }
    }
}

MainActivity.java

Eu apenas troquei VerticalViewPagerpor ViewPager.

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;

public class MainActivity extends AppCompatActivity {

    static final int NUMBER_OF_PAGES = 2;

    MyAdapter mAdapter;
    VerticalViewPager mPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAdapter = new MyAdapter(getSupportFragmentManager());
        mPager = findViewById(R.id.viewpager);
        mPager.setAdapter(mAdapter);
    }

    public static class MyAdapter extends FragmentPagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUMBER_OF_PAGES;
        }

        @Override
        public Fragment getItem(int position) {

            switch (position) {
                case 0:
                    return FragmentOne.newInstance(0, Color.WHITE);
                case 1:
                    // return a different Fragment class here
                    // if you want want a completely different layout
                    return FragmentOne.newInstance(1, Color.CYAN);
                default:
                    return null;
            }
        }
    }

    public static class FragmentOne extends Fragment {

        private static final String MY_NUM_KEY = "num";
        private static final String MY_COLOR_KEY = "color";

        private int mNum;
        private int mColor;

        // You can modify the parameters to pass in whatever you want
        static FragmentOne newInstance(int num, int color) {
            FragmentOne f = new FragmentOne();
            Bundle args = new Bundle();
            args.putInt(MY_NUM_KEY, num);
            args.putInt(MY_COLOR_KEY, color);
            f.setArguments(args);
            return f;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mNum = getArguments() != null ? getArguments().getInt(MY_NUM_KEY) : 0;
            mColor = getArguments() != null ? getArguments().getInt(MY_COLOR_KEY) : Color.BLACK;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.fragment_one, container, false);
            v.setBackgroundColor(mColor);
            TextView textView = v.findViewById(R.id.textview);
            textView.setText("Page " + mNum);
            return v;
        }
    }
}

Acabado

Você deve conseguir executar o aplicativo e ver o resultado na animação acima.

Veja também

Suragch
fonte
3
O código está funcionando bem, só preciso de uma pequena ajuda. No código atual, precisamos deslizar de baixo para cima para obter a próxima página, mas eu quero que até mesmo um furto pequeno também deva ter a próxima página.
AMIT
20

Eu tenho uma solução que funciona para mim em duas etapas.

  1. onInstantiateItem()de PagerAdapter, crie a vista e gire-a em -90:

    view.setRotation(-90f)

    Se você estiver usando FragmentPagerAdapter, então:

    objFragment.getView().setRotation(-90)
  2. Gire a ViewPagervista em 90 graus:

    objViewPager.setRotation(90)

Funciona como um encanto, pelo menos para a minha exigência.

Kulai
fonte
4
funciona este solução, mas você ainda tem que deslizar horizontalmente enquanto o viewPager agora rola verticalmente
leochab
@Kulai Não estou claro o que fazer aqui, você pode explicar um pouco, de acordo com o meu entendimento, de que temos public Object instantiateItem (container ViewGroup, int position) aqui precisamos fazer container.setRotation (-90f);
varun
1
Fazer isso funciona como um encanto! Embora a visão seja cortada na parte superior e inferior, não consigo entender por que: - /
Nivaldo Bondança 28/04
2
Funciona corretamente para uma imagem quadrada e não para um retangular. As dimensões dão errado quando um retângulo é girado.
Kulai
1
Não tenho certeza de quem votou positivamente nesta resposta. não é VerticalViewPager, é ViewPager com rotação de 90 graus, o gesto e a transição são exatamente opostos. e não é nada natural
droidev 12/07/19
14

Para alguém que está lutando com como fazer o ViewPager vertical funcionar na horizontal, faça o seguinte:

Vertical ViewPager

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

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

    private void init() {
        setPageTransformer(true, new VerticalPageTransformer());
        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements ViewPager.PageTransformer {

        @Override
        public void transformPage(View view, float position) {

            if (position < -1) {
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);

                view.setTranslationX(view.getWidth() * -position);

                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);
            } else {
                view.setAlpha(0);
            }
        }
    }

    private MotionEvent swapXY(MotionEvent ev) {
        float width = getWidth();
        float height = getHeight();

        float newX = (ev.getY() / height) * width;
        float newY = (ev.getX() / width) * height;

        ev.setLocation(newX, newY);

        return ev;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
        swapXY(ev);
        return intercepted;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(swapXY(ev));
    }

}

Horizontal ViewPager

public class HorizontalViewPager extends ViewPager {
    private GestureDetector xScrollDetector;

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

    public HorizontalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        xScrollDetector = new GestureDetector(getContext(), new XScrollDetector());
    }

    class XScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return Math.abs(distanceX) > Math.abs(distanceY);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (xScrollDetector.onTouchEvent(ev)) {
            super.onInterceptTouchEvent(ev);
            return true;
        }

        return super.onInterceptTouchEvent(ev);
    }

}
Mergulhadores
fonte
Como posso adicionar esse pager de exibição horizontal e vertical à minha exibição?
user1810931
Como implemento as classes de pager de exibição Horizontal e Vertical acima em minha exibição? Ajuda do snippet de código
user1810931 16/10
O ViewPager já é view, não entendo o que você está perguntando.
Divers
Estou usando uma biblioteca chamada "Material Calendar View" ( github.com/prolificinteractive/material-calendarview ) e ela já possui o viewpager horizontal e eu queria adicionar o vertical.
user1810931
8

Uma pequena extensão dessa resposta me ajudou a cumprir minha exigência (Vertical View Pager para animar similar como em Inshorts - Notícias em 60 palavras )

public class VerticalViewPager extends ViewPager {

public VerticalViewPager(Context context) {
    super(context);
    init();
}

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

private void init() {
    // The majority of the magic happens here
    setPageTransformer(true, new VerticalPageTransformer());
    // The easiest way to get rid of the overscroll drawing that happens on the left and right
    setOverScrollMode(OVER_SCROLL_NEVER);
}

private class VerticalPageTransformer implements ViewPager.PageTransformer {
 private static final float MIN_SCALE = 0.75f;
    @Override
    public void transformPage(View view, float position) {

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        }  else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page
            view.setAlpha(1);
            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);

            //set Y position to swipe in from top
            float yPosition = position * view.getHeight();
            view.setTranslationY(yPosition);
            view.setScaleX(1);
            view.setScaleY(1);

        } else if (position <= 1) { // [0,1]
            view.setAlpha(1);

            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);


            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }

    }

}

/**
 * Swaps the X and Y coordinates of your touch event.
 */
private MotionEvent swapXY(MotionEvent ev) {
    float width = getWidth();
    float height = getHeight();

    float newX = (ev.getY() / height) * width;
    float newY = (ev.getX() / width) * height;

    ev.setLocation(newX, newY);

    return ev;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
    boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
    swapXY(ev); // return touch coordinates to original reference frame for any child views
    return intercepted;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}
}

Espero que isso possa ser útil para outra pessoa.

Amrut Bidri
fonte
1
Valor ideal para MIN_SCALE?
Divyenduz
Você não encontrou o problema de com deslizando-se rapidamente a transição não é bom
Praneeth
Por que diabos alguém passaria rápido?
Amrut Bidri 28/02
Apenas um comentário para esclarecer: Esta solução altera a animação de uma maneira que a nova página não vem de baixo, mas de trás da página antiga. Então, basicamente, você não tem páginas dispostas uma ao lado da outra, mas um conjunto de páginas, uma sobre a outra. Portanto, essa solução pode não ser o que a pergunta original está tentando fazer.
Benjamin Basmaci 13/05/19
4

Existem alguns projetos de código aberto que afirmam fazer isso. Aqui estão eles:

Estes foram marcados como obsoletos por seus autores:

E mais uma coisa:

  • Há também um nome de arquivo VerticalViewPager.java na fonte Android do deskclockaplicativo, mas ele não parece ser oficialmente suportado, pois não consigo encontrar a documentação para ele.
Flimm
fonte
3

Confira: https://github.com/JakeWharton/Android-DirectionalViewPager

Ou a seguinte pergunta pode ajudá-lo: Vertical 'GridView with pages' ou 'Viewpager'

sdabet
fonte
2
Algo a ter em mente é que DirectionalViewPagerele não foi atualizado por um bom tempo e, portanto, está faltando alguns dos recursos mais recentes da ViewPagerbiblioteca de suporte; ie setPageMargin(int). Geralmente, ele deve fazer o trabalho. E, se não, não é muito complicado pegar o código-fonte ViewPagere trocar toda a lógica x / y e largura / altura.
MH.
Eu já levei em consideração o DirectionalViewPagermas, como MH disse, ele não é atualizado (o desenvolvedor o considera DEPRECADO) !! É incrível que os desenvolvedores do Android não tenham fornecido à comunidade uma vertical ViewPager, mas apenas a horizontal. Eu sou novo para o Android, desenvolver a minha vertical, ViewPagertrocando x / y não é tão fácil para mim .. eu prefiro uma solução já construída .. De qualquer forma, obrigado
user1709805
2
oi, você conseguiu fazer o viewpager vertical ?? thansk
Paul
3

Apenas uma melhoria nas respostas de @Brett e @ Salman666 para transformar corretamente as coordenadas (X, Y) em (Y, X), pois as telas do dispositivo são retangulares:

...

/**
 * Swaps the X and Y coordinates of your touch event
 */
@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return super.onInterceptTouchEvent(swapXY(ev));
}

private MotionEvent swapXY(MotionEvent ev) {

    //Get display dimensions
    float displayWidth=this.getWidth();
    float displayHeight=this.getHeight();

    //Get current touch position
    float posX=ev.getX();
    float posY=ev.getY();

    //Transform (X,Y) into (Y,X) taking display dimensions into account
    float newPosX=(posY/displayHeight)*displayWidth;
    float newPosY=(1-posX/displayWidth)*displayHeight;

    //swap the x and y coords of the touch event
    ev.setLocation(newPosX, newPosY);

    return ev;
}

...

No entanto, ainda é necessário fazer algo para melhorar a capacidade de resposta da tela sensível ao toque. O problema pode estar relacionado ao que @msdark comentou na resposta de @ Salman666.

Anônimo
fonte
Tenho algumas melhorias, sempre retornando trueem onInterceptTouchEvente eu também modificou as teclas, de modo que o uso de um DPAD ele aciona pergaminho com UP / DOWN em vez de esquerda / direita: gist.github.com/zevektor/fbacf4f4f6c39fd6e409
Vektor88
@ Vektor88 sempre retornando true impedirá vistas internas de receber eventos de toque .. melhor solução é como em resposta Brett ..
Mohammad Zekrallah
2
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        super(context);
        init();
    }


    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    private void init() {

        setPageTransformer(true, new VerticalPageTransformer());

        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements PageTransformer {

        @Override
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            int pageHeight = view.getHeight();

            if (position < -1) {

                view.setAlpha(0);

            } else if (position <= 1) {
                view.setAlpha(1);


                view.setTranslationX(pageWidth * -position);


                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);

            } else {

                view.setAlpha(0);
            }
        }
    }
        @Override
    public boolean onTouchEvent(MotionEvent ev) {

        ev.setLocation(ev.getY(), ev.getX());

        return super.onTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        ev.setLocation(ev.getY(), ev.getX());
        return super.onInterceptTouchEvent(ev);
    }
}
Salman666
fonte
1
Isso funciona muito agradável, mas eu perder a TouchEvent em elementos ou os eventos esquerda / furto ...
matiasfha
0

Na verdade, já existe um na fonte do Android . Eu o modifiquei para funcionar melhor:

package com.crnlgcs.sdk.widgets;



import android.content.Context;
import android.support.v4.view.ViewConfigurationCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;

public class VerticalViewPager extends ViewPager {
    private static final String TAG = "VerticalViewPager";
    private static final boolean DEBUG = true;

    private float mLastMotionX;
    private float mLastMotionY;
    private float mTouchSlop;
    private boolean mVerticalDrag;
    private boolean mHorizontalDrag;

    // Vertical transit page transformer
    private final ViewPager.PageTransformer mPageTransformer = new ViewPager.PageTransformer() {
        @Override
        public void transformPage(View view, float position) {
            final int pageWidth = view.getWidth();
            final int pageHeight = view.getHeight();
            if (position < -1) {
                // This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);
                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);
                // set Y position to swipe in from top
                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);
            } else {
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    };

    public VerticalViewPager(Context context) {
        super(context, null);
    }

    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
        init();
    }

    private void init() {
        // Make page transit vertical
        setPageTransformer(true, mPageTransformer);
        // Get rid of the overscroll drawing that happens on the left and right (the ripple)
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        final float x = ev.getX();
        final float y = ev.getY();

        if (DEBUG) Log.v(TAG, "onTouchEvent " + x + ", " + y);

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mLastMotionX = x;
                mLastMotionY = y;
                if (!super.onTouchEvent(ev))
                    return false;
                return verticalDrag(ev);
            }
            case MotionEvent.ACTION_MOVE: {
                final float xDiff = Math.abs(x - mLastMotionX);
                final float yDiff = Math.abs(y - mLastMotionY);
                if (!mHorizontalDrag && !mVerticalDrag) {
                    if (xDiff > mTouchSlop && xDiff > yDiff) { // Swiping left and right
                        mHorizontalDrag = true;
                    } else if (yDiff > mTouchSlop && yDiff > xDiff) { //Swiping up and down
                        mVerticalDrag = true;
                    }
                }
                if (mHorizontalDrag) {
                    return super.onTouchEvent(ev);
                } else if (mVerticalDrag) {
                    return verticalDrag(ev);
                }
            }
            case MotionEvent.ACTION_UP: {
                if (mHorizontalDrag) {
                    mHorizontalDrag = false;
                    return super.onTouchEvent(ev);
                }
                if (mVerticalDrag) {
                    mVerticalDrag = false;
                    return verticalDrag(ev);
                }
            }
        }
        // Set both flags to false in case user lifted finger in the parent view pager
        mHorizontalDrag = false;
        mVerticalDrag = false;

        return false;
    }


    private boolean verticalDrag(MotionEvent ev) {
        final float x = ev.getX();
        final float y = ev.getY();
        ev.setLocation(y, x);
        return super.onTouchEvent(ev);
    }
}
phreakhead
fonte
isso não está funcionando corretamente .. até a versão original do android não funciona .. é glitchy e funciona apenas para gestos direito / esquerdo .. se você fizer o movimento para cima / baixo, ele não rola .. pelo menos para mim ..
Mohammad Zekrallah
0

Um repositório atualmente mais ativo é o lsjwzh / RecyclerViewPager .

  • last commit 12 ago 2016, 16 colaboradores, 1840 estrelas
  • baseado em RecyclerView
ford04
fonte
0

Esta é uma implementação do ViewPager com rolagem vertical. Funciona bem com o RecyclerView e o ListView. guochong / VerticalViewPager .

use ViewPager.PageTransformer para fazer o ViewPager rolar verticalmente e também forneça um View.OnTouchListener para lidar com o conflito de rolagem.

/**
 * 1.dispatch ACTION_DOWN,ACTION_UP,ACTION_CANCEL to child<br>
 * 2.hack ACTION_MOVE
 *
 * @param v
 * @param e
 * @return
 */
@Override
public boolean onTouch(View v, MotionEvent e) {
    Log.i(TAG, "onTouchEvent " + ", action " + e.getAction() + ", e.rawY " + e.getRawY() + ",lastMotionY " + lastMotionY + ",downY " + downY);
    switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downY = e.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:

            if (downY == Float.MIN_VALUE && lastMotionY == Float.MIN_VALUE) {
                //not start from MOTION_DOWN, the child dispatch this first motion
                downY = e.getRawY();
                break;
            }

            float diff = e.getRawY() - (lastMotionY == Float.MIN_VALUE ? downY : lastMotionY);
            lastMotionY = e.getRawY();
            diff = diff / 2; //slow down viewpager scroll
            Log.e(TAG, "scrollX " + dummyViewPager.getScrollX() + ",basescrollX " + dummyViewPager.getBaseScrollX());

            if (dummyViewPager.getScrollX() != dummyViewPager.getBaseScrollX()) {
                if (fakeDragVp(v, e, diff)) return true;
            } else {
                if (ViewCompat.canScrollVertically(v, (-diff) > 0 ? 1 : -1)) {
                    Log.e(TAG, "scroll vertically  " + diff + ", move.lastMotionY " + e.getY());
                    break;
                } else {
                    dummyViewPager.beginFakeDrag();
                    fakeDragVp(v, e, diff);
                    adjustDownMotion(v, e);
                    return true;
                }
            }

            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            if (dummyViewPager.isFakeDragging()) {
                try {
                    dummyViewPager.endFakeDrag();
                } catch (Exception e1) {
                    Log.e(TAG, "", e1);
                }
            }
            reset();
            break;
    }

    return false;
}
Chade
fonte
Bem-vindo ao StackOverflow e obrigado por sua ajuda. Você pode melhorar ainda mais sua resposta adicionando algum código.
Elias MP
0

Até eu estava enfrentando o mesmo problema ao tornar o ViewPager vertical trocando X e Y. Não foi nada fácil.

Isso porque costumava funcionar apenas quando o ângulo de passagem era menor que 7,125 graus = arctan (1/8) enquanto interceptava e 14 graus = arctan (1/4) enquanto tocava; como o ViewPager horizontal original, funciona quando o ângulo de passagem é inferior a 26,565 graus = arctan (1/2) enquanto intercepta e 45 graus = arctan (1) enquanto toca.

É por isso que copiei o código do Android support-core-ui e movi os valores para as variáveis, que multipliquei usando reflexão.

Encontre o código e o README em https://github.com/deepakmishra/verticalviewpager e VerticalViewPager em https://github.com/deepakmishra/verticalviewpager/blob/master/app/src/main/java/com/viewpager/VerticalViewPager .Java

Deepak
fonte
0

a melhor maneira é girar o viewpager em 90 graus e usar constraintLayout para ajustar o local.

JackHui
fonte
0

Acabei criando um novo DirectionalViewPager que pode rolar vertical ou horizontalmente porque todas as soluções que vi aqui têm falhas:

  1. Implementações existentes do VerticalViewPager (por castorflex e LambergaR)

    • Eles são baseados em versões muito antigas da biblioteca de suporte.
  2. Truque de transformação com troca de coordenadas

    • O controle excessivo ainda é mostrado pelas bordas esquerda / direita.
    • O arremesso de página não funciona corretamente, porque mesmo com as coordenadas trocadas, VelocityTracker.computeCurrentVelocityainda calcula a velocidade com o eixo X, provavelmente porque isso usa internamente uma chamada nativa que ignora a troca de coordenadas.
  3. Ver rotação

    • Hack que precisa que cada visão infantil também seja rotacionada.
    • Se você quiser ler as coordenadas para outra coisa, precisará trocar o eixo.
inorichi
fonte