Android: Vertical ViewPager [cerrado]


130

¿Hay alguna manera de hacer un ViewPagerque no se desplace horizontalmente, sino verticalmente?


1
Hay una nueva implementación no oficial de código abierto de un ViewPager vertical: Anuncio: plus.google.com/107777704046743444096/posts/1FTJfrvnY8w Código: github.com/LambergaR/VerticalViewPager
Vasily Sochinsky

Implementación del localizador de vista vertical por Antoine Merle: github.com/castorflex/VerticalViewPager
micnoy

Hay una nueva implementación basada en la biblioteca de soporte 19: github.com/castorflex/VerticalViewPager
Vasily Sochinsky

Esto no es lo mismo que github.com/castorflex/VerticalViewPager , a pesar de tener un nombre similar.
Flimm

1
Hay un control llamado ViewPager2, compruebe aquí la demo stackoverflow.com/a/54643817/7666442
Nilesh Rathod

Respuestas:


227

Puede usar un ViewPager.PageTransformer para dar la ilusión de una vertical ViewPager. Para lograr el desplazamiento con un arrastre vertical en lugar de uno horizontal, tendrá que anular ViewPagerlos eventos táctiles predeterminados e intercambiar las coordenadas de MotionEvents antes de manejarlos, por ejemplo:

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

}

Por supuesto, puede ajustar esta configuración como mejor le parezca. Termina luciendo así:

Demo de VerticalViewPager


3
@Der Golem, ¿cómo usar el diseño para esto?
bShah

¿Cuál es la pregunta exacta? Por cierto, no publiqué la respuesta, solo agregué la imagen referida.
Phantômaxx

1
@Brett en este ejemplo, quiero realizar alguna acción al deslizar hacia la izquierda y hacia la derecha. cómo hacer eso
Prabs

1
@Brett funciona como se esperaba, la transición se está realizando verticalmente. Pero el problema es que tengo que deslizar hacia la derecha / izquierda para hacer la transición y al deslizar hacia arriba / abajo no se realiza la transición.
Karan Khurana

2
@ Brett Estaba usando tu solución. pero ahora estoy teniendo el problema de swipping en dispositivos de pastel andorid. ¿Alguien tiene el mismo problema?
Jishant

20

ViewPager vertical

Las otras respuestas aquí parecen tener algunos problemas con ellas. Incluso los proyectos de código abierto recomendados no combinaban solicitudes de extracción recientes con correcciones de errores. Luego encontré una VerticalViewPagerde Google que usaba alguna aplicación DeskClock. Confío en usar la implementación de Google mucho más que las otras respuestas que flotan por aquí. (La versión de Google es similar a la respuesta actual más votada, pero más exhaustiva).

Ejemplo completo

Este ejemplo es casi exactamente el mismo que mi ejemplo de ViewPager básico , con algunos cambios menores para hacer uso de la VerticalViewPagerclase.

ingrese la descripción de la imagen aquí

XML

Agregue los diseños xml para la actividad principal y para cada página (fragmento). Tenga en cuenta que usamos en VerticalViewPagerlugar del estándar ViewPager. Incluiré el código para eso a continuación.

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

El código para el VerticalViewPagerno es mío. Es solo una versión simplificada (sin comentarios) del código fuente de Google. Echa un vistazo a esa para obtener la versión más actualizada. Los comentarios allí también son útiles para comprender lo que está sucediendo.

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

Solo cambié 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;
        }
    }
}

Terminado

Debería poder ejecutar la aplicación y ver el resultado en la animación anterior.

Ver también


3
El código funciona bien, solo necesito 1 pequeña ayuda. En el Código actual, debemos deslizar de abajo hacia arriba para obtener la siguiente página, pero quiero que incluso un pequeño deslizamiento también obtenga la siguiente página.
AMIT

20

Tengo una solución que me funciona en dos pasos.

  1. onInstantiateItem()de PagerAdapter, cree la vista y gírela por -90:

    view.setRotation(-90f)

    Si está usando FragmentPagerAdapter, entonces:

    objFragment.getView().setRotation(-90)
  2. Girar la ViewPagervista en 90 grados:

    objViewPager.setRotation(90)

Funciona como un encanto al menos para mi requerimiento.


44
esta solución funciona, PERO aún debe deslizar horizontalmente mientras que viewPager ahora se desplaza verticalmente
leochab

@Kulai, no tengo claro qué hacer aquí, ¿puede explicarme un poco, según tengo entendido? Tenemos un objeto público instantiateItem (ViewGroup container, int position) aquí tenemos que hacer container.setRotation (-90f);
varun

1
¡Hacerlo funciona de maravilla! Aunque la vista se corta en la parte superior e inferior, y no puedo entender por qué: - /
Nivaldo Bondança

2
Funciona correctamente para una imagen cuadrada y no para una rectangular. Las dimensiones salen mal cuando se gira un rectángulo.
Kulai

1
No estoy seguro de quién votó esta respuesta. esto no es VerticalViewPager, esto es ViewPager con 90 grados rotados, el gesto y la transición son justo opuestos. y no es del todo natural
droidev

14

Para alguien que está luchando con cómo hacer que ViewPager vertical funcione dentro de horizontal, solo haga lo siguiente:

ViewPager vertical

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

}

ViewPager horizontal

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

}

¿Cómo puedo agregar este localizador de vista horizontal y vertical a mi vista?
user1810931


¿Cómo implemento las clases de buscapersonas de vista horizontal y vertical anteriores en mi vista? Fragmento de código ayuda
user1810931

ViewPager ya es vista, no entiendo por qué preguntas.
Buceadores

Estoy usando una biblioteca llamada "Vista de calendario material" ( github.com/prolificinteractive/material-calendarview ) y ya tiene un visor horizontal y quería agregar un visor vertical.
user1810931

8

Una ligera extensión de esta respuesta me ayudó a cumplir mi requisito (Vertical View Pager para animar de manera similar a Inshorts - Noticias en 60 palabras )

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 esto pueda ser útil para alguien más.


1
¿Valor ideal para MIN_SCALE?
divyenduz

¿No ha encontrado con un problema de deslizar rápidamente la transición no es liso
Praneeth

¿Por qué demonios alguien deslizaría rápido?
Amrut Bidri

Solo un comentario para aclarar: esta solución cambia la animación de manera que la nueva página no viene desde abajo sino desde atrás de la página anterior. Así que, básicamente, no tienes páginas colocadas una al lado de la otra, sino más bien un mazo de páginas, una encima de la otra. Entonces, esta solución podría no ser lo que la pregunta original está tratando de hacer.
Benjamin Basmaci

4

Hay algunos proyectos de código abierto que afirman hacer esto. Aquí están:

Estos han sido marcados como obsoletos por sus autores:

Y una cosa más:


3

2
Algo a tener en cuenta es que DirectionalViewPagerno se ha actualizado durante bastante tiempo y, por lo tanto, le faltan algunas de las características más recientes de la ViewPagerbiblioteca de soporte; es decir setPageMargin(int). Sin embargo, generalmente debería hacer el trabajo. Y si no, no es demasiado complicado tomar el código fuente ViewPagere intercambiar toda la lógica x / y ancho / alto.
MH.

Ya he tenido en cuenta el DirectionalViewPagerpero, como dijo MH, ¡no está actualizado (su desarrollador lo considera DEPRECADO)! Es increíble que los desarrolladores de Android no hayan brindado a la comunidad una vertical ViewPager, sino solo horizontal. Soy nuevo en Android, desarrollar mi ViewPagerintercambio vertical x / y no es tan fácil para mí ... Preferiría una solución ya construida ... de todos modos, gracias
User1709805

2
hola, ¿lograste hacer el visor vertical? thansk
Paul

3

Solo una mejora en las respuestas de @Brett y @ Salman666 para transformar correctamente las coordenadas (X, Y) en (Y, X) ya que las pantallas del dispositivo son rectangulares:

...

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

...

Sin embargo, aún queda algo por hacer para mejorar la capacidad de respuesta de la pantalla táctil. El problema podría estar relacionado con lo que @msdark comentó sobre la respuesta de @ Salman666.


Tengo algunas mejoras que siempre devuelve trueen onInterceptTouchEventy yo también he modificado las asociaciones de teclas, por lo que el uso de un DPAD se dispara de desplazamiento con UP / DOWN en lugar de a la izquierda / derecha: gist.github.com/zevektor/fbacf4f4f6c39fd6e409
Vektor88

@ Vektor88 siempre regresando verdadero evitará que las vistas internas reciban eventos táctiles ... la mejor solución es como en la respuesta 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);
    }
}

1
Esto funciona muy bien, pero pierdo el evento touchEvent en elementos o los eventos izquierda / deslizar ...
matiasfha

0

En realidad, ya hay uno en la fuente de Android . Sin embargo, lo he modificado para que funcione mejor:

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

esto no funciona correctamente ... incluso la versión de origen de Android no ... tiene fallas y solo funciona para los gestos derecho / izquierdo ... si lo haces arriba / abajo no se desplaza ... al menos para mí ...
Mohammad Zekrallah


0

Esta es una implementación de ViewPager de desplazamiento vertical. Funciona bien con RecyclerView y ListView. guochong / VerticalViewPager .

use ViewPager.PageTransformer para hacer que ViewPager se desplace verticalmente y también proporcione View.OnTouchListener para lidiar con el conflicto de desplazamiento.

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

Bienvenido a StackOverflow y gracias por tu ayuda. Es posible que desee mejorar su respuesta agregando algo de código.
Elias MP

0

Incluso me enfrentaba al mismo problema al hacer que ViewPager fuera vertical intercambiando X e Y. No fue nada sencillo.

Esto se debe a que solía funcionar solo cuando el ángulo de deslizamiento era inferior a 7.125 grados = arctan (1/8) mientras se interceptaba y 14 grados = arctan (1/4) mientras se toca; como ViewPager original horizontal, uno funciona cuando el ángulo de deslizamiento es inferior a 26.565 grados = arctan (1/2) mientras se intercepta y 45 grados = arctan (1) mientras se toca.

Es por eso que copié el código de Android support-core-ui y moví los valores a variables, que multipliqué usando la reflexión.

Encuentre el código y README en https://github.com/deepakmishra/verticalviewpager y VerticalViewPager en https://github.com/deepakmishra/verticalviewpager/blob/master/app/src/main/java/com/viewpager/VerticalViewPager .Java


0

la mejor manera es rotar el visor 90 grados y usar restricintLayout para ajustar la ubicación.


0

Terminé creando un nuevo DirectionalViewPager que puede desplazarse vertical u horizontalmente porque todas las soluciones que he visto aquí tienen fallas:

  1. Implementaciones existentes de VerticalViewPager (por castorflex y LambergaR)

    • Se basan en versiones de biblioteca de soporte muy antiguas.
  2. Truco de transformación con intercambio de coordenadas

    • El sobredesplazador todavía se muestra desde los bordes izquierdo / derecho.
    • El cambio de página no funciona correctamente, porque incluso con las coordenadas intercambiadas, VelocityTracker.computeCurrentVelocitytodavía calcula la velocidad con el eje X, probablemente porque internamente utiliza una llamada nativa que ignora el intercambio de coordenadas.
  3. Ver rotación

    • Hack que necesita que todas las vistas secundarias se roten también.
    • Si desea leer las coordenadas de otra cosa, debe cambiar el eje.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.