Android: Vertical ViewPager [закрыто]

131

Есть ли способ сделать ViewPagerпрокрутку не по горизонтали, а по вертикали ?!

user1709805
источник
1
Появилась новая неофициальная реализация вертикального ViewPager с открытым исходным кодом: Объявление: plus.google.com/107777704046743444096/posts/1FTJfrvnY8w Код: github.com/LambergaR/VerticalViewPager
Василий Сочинский
Реализация пейджера с вертикальным обзором от Антуана Мерля: github.com/castorflex/VerticalViewPager
micnoy 05
Есть новая реализация, основанная на библиотеке поддержки 19: github.com/castorflex/VerticalViewPager
Василий Сочинский,
Это не то же самое, что и github.com/castorflex/VerticalViewPager , несмотря на похожее имя.
Flimm
1
Здесь есть элемент управления ViewPager2, проверьте демонстрацию stackoverflow.com/a/54643817/7666442
Nilesh Rathod

Ответы:

227

Вы можете использовать ViewPager.PageTransformer, чтобы создать иллюзию вертикали ViewPager. Чтобы добиться вертикальной прокрутки вместо горизонтального перетаскивания, вам придется переопределить ViewPagerсобытия касания по умолчанию и поменять местами координаты MotionEvents перед их обработкой, например:

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

}

Конечно, вы можете настроить эти параметры по своему усмотрению. В итоге выглядит так:

Демонстрация VerticalViewPager

Brett
источник
4
@Der Golem, как использовать для этого макет?
bShah
Какой точный вопрос? Кстати, я не публиковал ответ, просто добавил указанное изображение.
Phantômaxx
1
@Brett в этом примере я хочу выполнить какое-то действие, проведя пальцем влево и вправо. как это сделать
Prabs
1
@Brett работает как положено, переход идет вертикально. Но проблема в том, что мне нужно проводить пальцем вправо / влево, чтобы выполнить переход, а при прокрутке вверх / вниз переход не происходит.
Каран Хурана,
2
@Brett Я использовал ваше решение. но теперь у меня проблема с перелистыванием в устройствах andorid pie. Есть ли у кого-нибудь такая же проблема?
Jishant 03
21

У меня есть решение, которое работает для меня в два этапа.

  1. onInstantiateItem()of PagerAdapter, создайте вид и поверните его на -90:

    view.setRotation(-90f)

    Если пользуетесь FragmentPagerAdapter, то:

    objFragment.getView().setRotation(-90)
  2. Повернуть ViewPagerвид на 90 градусов:

    objViewPager.setRotation(90)

Работает как шарм, по крайней мере, для моих требований.

Кулаи
источник
4
это решение работает, НО вам все равно нужно проводить горизонтально, тогда как viewPager теперь прокручивается вертикально
leochab
@Kulai, я не понимаю, что здесь делать, не могли бы вы объяснить немного, насколько я понимаю, у нас есть публичный объект instantiateItem (контейнер ViewGroup, позиция int), здесь нам нужно сделать container.setRotation (-90f);
varun
1
Это работает как шарм! Хотя вид сокращается в верхней и нижней части, и я не могу понять, почему: - /
Нивалдо Бонданса
2
Он работает правильно для квадратного изображения, а не для прямоугольного. Размеры изменяются при повороте прямоугольника.
Кулай
1
Я не уверен, кто поддержал этот ответ. это не VerticalViewPager, это ViewPager с поворотом на 90 градусов, жест и переход прямо противоположные. и это совсем не естественно
дройдев
20

Вертикальный ViewPager

У всех других ответов здесь, похоже, были некоторые проблемы с ними. Даже рекомендованные проекты с открытым исходным кодом не объединяли недавние запросы на вытягивание с исправлениями ошибок. Затем я обнаружил VerticalViewPagerот Google, что они использовали какое-то приложение DeskClock. Я доверяю использованию реализации Google намного больше, чем другие ответы, плавающие здесь. (Версия Google похожа на текущий ответ, получивший наибольшее количество голосов, но более подробный.)

Полный пример

Этот пример почти такой же, как и мой базовый пример ViewPager , с небольшими изменениями, позволяющими использовать VerticalViewPagerкласс.

введите описание изображения здесь

XML

Добавьте макеты xml для основного действия и для каждой страницы (фрагмента). Обратите внимание, что мы используем, VerticalViewPagerа не стандартный ViewPager. Я включу код для этого ниже.

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>

Код

Код VerticalViewPagerне мой. Это просто урезанная версия (без комментариев) из исходного кода Google. Проверьте это, чтобы получить самую последнюю версию. Комментарии также полезны для понимания того, что происходит.

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

Я только поменял VerticalViewPagerна 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;
        }
    }
}

Законченный

Вы должны иметь возможность запустить приложение и увидеть результат на анимации выше.

Смотрите также

Suragch
источник
3
Код работает нормально, просто нужна небольшая помощь. В текущем коде нам нужно провести снизу вверх, чтобы перейти на следующую страницу, но я хочу, чтобы даже небольшое смахивание также привело к переходу на следующую страницу.
AMIT
14

Для тех, кто пытается заставить вертикальный ViewPager работать внутри горизонтального, просто выполните следующие действия:

Вертикальный 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));
    }

}

Горизонтальный 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);
    }

}
различный
источник
Как я могу добавить этот пейджер горизонтального и вертикального просмотра к моему представлению?
user1810931
Начните с учебника - vogella.com/tutorials/AndroidCustomViews/article.html
Дайверы
Как мне реализовать в моем представлении указанные выше классы пейджера горизонтального и вертикального представления? Фрагмент кода помогает
user1810931
ViewPager уже просматривает, я не понимаю, о чем вы спрашиваете.
Дайверы
Я использую библиотеку под названием «Представление календаря материалов» ( github.com/prolificinteractive/material-calendarview ), и в ней уже есть горизонтальный пейджер, и я хотел добавить в него вертикальный пейджер.
user1810931
8

Небольшое расширение этого ответа помогло мне выполнить мои требования (вертикальный пейджер для анимации, как в Inshorts - Новости в 60 словах )

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

Надеюсь, это может быть полезно кому-то еще.

Амрут Бидри
источник
1
Идеальное значение для MIN_SCALE?
divyenduz 02
Разве вы не обнаружили проблемы с быстрым
смахиванием
Зачем кому-то быстро смахивать вверх?
Амрут Бидри
Просто поясняющий комментарий: это решение изменяет анимацию таким образом, что новая страница появляется не снизу, а из-за старой страницы. Таким образом, в основном у вас не страницы, лежащие рядом друг с другом, а скорее набор страниц, лежащих друг на друге. Таким образом, это решение может быть не тем, что пытается сделать исходный вопрос.
Бенджамин Басмачи
4

Есть несколько проектов с открытым исходным кодом, которые утверждают, что это делают. Они здесь:

Они были отмечены их авторами как устаревшие:

И вот еще:

  • Существует также имя файла VerticalViewPager.java в источнике Android из deskclockприложения, но, похоже, он официально не поддерживается, так как я не могу найти для него документацию.
Флимм
источник
3

Проверьте это: https://github.com/JakeWharton/Android-DirectionalViewPager

Или вам может помочь следующий вопрос: Вертикальная «сетка со страницами» или «Viewpager»

sdabet
источник
2
Следует иметь в виду, что в DirectionalViewPagerтечение некоторого времени не обновлялся и, следовательно, ViewPagerв библиотеке поддержки отсутствуют некоторые новые функции ; то есть setPageMargin(int). В общем, он должен работать. А если нет, не так сложно получить исходный код ViewPagerи поменять местами всю логику x / y и ширины / высоты.
MH.
Я уже учел, DirectionalViewPagerно, как сказал MH, он не обновляется (его разработчик считает УСТАРЕВШИМ) !! Невероятно, что разработчики Android предоставили сообществу не вертикаль ViewPager, а только горизонт. Я новичок в Android, разработать вертикальную ViewPagerзамену x / y для меня не так просто .. я бы предпочел уже построенное решение .. в любом случае, спасибо
user1709805
2
привет, удалось сделать вертикальный просмотрщик ?? thansk
Пол
3

Просто улучшение ответов от @Brett и @ Salman666, чтобы правильно преобразовать координаты (X, Y) в (Y, X), поскольку дисплеи устройств прямоугольные:

...

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

...

Тем не менее, что-то еще нужно сделать, чтобы улучшить отзывчивость сенсорного экрана. Проблема может быть связана с тем, что @msdark прокомментировал ответ @ Salman666.

анонимное
источник
У меня есть некоторые улучшения, всегда возвращаясь trueв onInterceptTouchEventи я также изменил привязок клавиш, так что с помощью DPad это вызывает свиток с UP / DOWN , а не влево / вправо: gist.github.com/zevektor/fbacf4f4f6c39fd6e409
Vektor88
@ Vektor88, всегда возвращающий истину, не позволит внутренним представлениям получать события касания .. Лучшее решение - как в бретт-ответе ..
Мохаммад Зекралла,
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
источник
1
Это работает очень хорошо, но я теряю touchEvent для элементов или событий left / swipe ...
matiasfha
0

Фактически он уже есть в исходниках Android . Я изменил его, чтобы он работал лучше:

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
источник
это не работает должным образом .. даже исходная версия Android не работает .. это глючно и работает только для жестов вправо / влево .. если вы делаете вверх / вниз, он не прокручивается .. по крайней мере для меня ..
Мохаммад Zekrallah 07
0

В настоящее время более активным репозиторием является lsjwzh / RecyclerViewPager .

  • последняя фиксация 12 августа 2016 г., 16 участников, 1840 звезд
  • на основе RecyclerView
ford04
источник
0

Это реализация ViewPager с вертикальной прокруткой, хорошо работает с RecyclerView и ListView. гочонг / VerticalViewPager .

используйте ViewPager.PageTransformer, чтобы заставить ViewPager прокручиваться по вертикали, а также предоставьте View.OnTouchListener для разрешения конфликта прокрутки.

/**
 * 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;
}
Чад
источник
Добро пожаловать в StackOverflow и благодарим за помощь. Возможно, вы захотите улучшить свой ответ, добавив код.
Elias MP
0

Даже я столкнулся с той же проблемой, когда ViewPager стал вертикальным, поменяв местами X и Y. Это было совсем не гладко.

Это потому, что раньше он работал только тогда, когда угол прокрутки был меньше 7,125 градуса = arctan (1/8) при перехвате и 14 градусов = arctan (1/4) при касании; как исходный ViewPager горизонтальный, работает, когда угол прокрутки меньше 26,565 градусов = arctan (1/2) при перехвате и 45 градусов = arctan (1) при касании.

Вот почему я скопировал код Android support-core-ui и переместил значения в переменные, которые умножил с помощью отражения.

Пожалуйста, найдите код и README на https://github.com/deepakmishra/verticalviewpager и VerticalViewPager на https://github.com/deepakmishra/verticalviewpager/blob/master/app/src/main/java/com/viewpager/VerticalViewPager. .Ява

Дипак
источник
0

лучший способ - повернуть окно просмотра на 90 градусов и использовать constraintLayout для настройки местоположения.

JackHui
источник
0

В итоге я создал новый DirectionalViewPager, который может прокручиваться либо по вертикали, либо по горизонтали, потому что все решения, которые я здесь видел, имеют недостатки:

  1. Существующие реализации VerticalViewPager (от castorflex и LambergaR)

    • Они основаны на очень старых версиях библиотеки поддержки.
  2. Трюк с преобразованием с заменой координат

    • Прокрутка по-прежнему отображается с левого / правого края.
    • Перелистывание страниц не работает должным образом, потому что даже при VelocityTracker.computeCurrentVelocityперестановке координат скорость по-прежнему вычисляется по оси X, вероятно, потому, что это внутренне использует собственный вызов, который игнорирует обмен координатами.
  3. Просмотр вращения

    • Взлом, который требует поворота каждого дочернего представления.
    • Если вы хотите прочитать координаты для чего-то еще, вы должны поменять местами ось.
inorichi
источник