Android: Vertikaler ViewPager [geschlossen]

130

Gibt es eine Möglichkeit, eine zu erstellen ViewPager, die nicht horizontal, sondern vertikal scrollt?!

user1709805
quelle
1
Es gibt eine neue inoffizielle Open-Source-Implementierung eines vertikalen ViewPagers: Ankündigung: plus.google.com/107777704046743444096/posts/1FTJfrvnY8w Code: github.com/LambergaR/VerticalViewPager
Vasily Sochinsky
Vertikale Ansicht Pager Implementierung von Antoine Merle: github.com/castorflex/VerticalViewPager
micnoy
Es gibt eine neue Implementierung basierend auf der 19 Support-Bibliothek: github.com/castorflex/VerticalViewPager
Vasily Sochinsky
Dies ist nicht dasselbe wie github.com/castorflex/VerticalViewPager , obwohl es einen ähnlichen Namen hat.
Flimm
1
Es gibt Kontrolle namens ViewPager2 Check hier für Demo stackoverflow.com/a/54643817/7666442
Nilesh Rathod

Antworten:

227

Sie können einen ViewPager.PageTransformer verwenden , um die Illusion einer Vertikalen zu erzeugenViewPager . Um einen Bildlauf mit vertikalem statt horizontalem Ziehen zu erreichen, müssen Sie die ViewPagerStandardberührungsereignisse überschreiben und die Koordinaten von MotionEvents vertauschen, bevor Sie sie verarbeiten, z.

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

}

Natürlich können Sie diese Einstellungen nach Belieben anpassen. Sieht am Ende so aus:

VerticalViewPager-Demo

Brett
quelle
3
@Der Golem wie benutzt man das Layout dafür?
bShah
Was ist die genaue Frage? Übrigens habe ich die Antwort nicht gepostet, sondern nur das verwiesene Bild hinzugefügt.
Phantômaxx
1
@Brett In diesem Beispiel möchte ich eine Aktion beim Wischen nach links und rechts ausführen. wie das geht
Prabs
1
@Brett es funktioniert wie erwartet, der Übergang erfolgt vertikal. Aber das Problem ist, dass ich nach rechts / links wischen muss, um einen Übergang durchzuführen, und beim Wischen von oben / unten findet kein Übergang statt.
Karan Khurana
2
@Brett Ich habe Ihre Lösung verwendet. aber jetzt bekomme ich das Swipping-Problem in Andorid Pie-Geräten. Hat jemand das gleiche Problem?
Jishant
20

Vertikaler ViewPager

Die anderen Antworten hier schienen alle einige Probleme mit ihnen zu haben. Selbst die empfohlenen Open Source-Projekte haben die letzten Pull-Anfragen nicht mit Fehlerkorrekturen zusammengeführt. Dann fand ich eine VerticalViewPagervon Google, dass sie eine DeskClock-App verwendeten. Ich vertraue darauf, dass die Implementierung von Google viel mehr verwendet wird als die anderen Antworten, die hier herumschwirren. (Die Version von Google ähnelt der aktuellen Antwort mit den meisten Stimmen, ist jedoch gründlicher.)

Vollständiges Beispiel

Dieses Beispiel entspricht fast genau meinem Basic ViewPager-Beispiel , mit einigen geringfügigen Änderungen, um die VerticalViewPagerKlasse zu verwenden.

Geben Sie hier die Bildbeschreibung ein

XML

Fügen Sie die XML-Layouts für die Hauptaktivität und für jede Seite (Fragment) hinzu. Beachten Sie, dass wir VerticalViewPagereher als den Standard verwenden ViewPager. Ich werde den Code dafür unten einfügen.

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>

Code

Der Code für das VerticalViewPagerist nicht meins. Es ist nur eine abgespeckte Version (ohne Kommentare) aus dem Google-Quellcode. Schauen Sie sich diese Version an, um die aktuellste Version zu erhalten. Die Kommentare dort sind auch hilfreich, um zu verstehen, was passiert.

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

Ich nur ausgelagert VerticalViewPagerfür 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;
        }
    }
}

Fertig

Sie sollten in der Lage sein, die App auszuführen und das Ergebnis in der obigen Animation zu sehen.

Siehe auch

Suragch
quelle
3
Der Code funktioniert gut, ich brauche nur 1 kleine Hilfe. Im aktuellen Code müssen wir von unten nach oben wischen, um die nächste Seite zu erhalten, aber ich möchte, dass auch ein kleiner Wisch die nächste Seite erhält.
AMIT
20

Ich habe eine Lösung, die in zwei Schritten für mich funktioniert.

  1. onInstantiateItem()von PagerAdapter, erstellen Sie die Ansicht , und drehen Sie es um -90:

    view.setRotation(-90f)

    Wenn Sie verwenden FragmentPagerAdapter, dann:

    objFragment.getView().setRotation(-90)
  2. ViewPagerAnsicht um 90 Grad drehen :

    objViewPager.setRotation(90)

Funktioniert zumindest für meine Anforderungen wie ein Zauber.

Kulai
quelle
4
Diese Lösung funktioniert, ABER Sie müssen immer noch horizontal wischen, während der viewPager jetzt vertikal scrollt
Leochab
@ Kulai Ich bin mir nicht sicher, was ich hier tun soll. Kannst du mir bitte ein wenig erklären, wie wir verstehen. Wir haben ein öffentliches Objekt. InstantiateItem (ViewGroup-Container, int-Position). Hier müssen wir container.setRotation (-90f) ausführen.
Varun
1
Das funktioniert wie ein Zauber! Obwohl die Ansicht im oberen und unteren Teil abgeschnitten wird, kann ich nicht herausfinden, warum: - /
Nivaldo Bondança
2
Es funktioniert ordnungsgemäß für ein quadratisches Bild und nicht für ein rechteckiges. Die Abmessungen gehen schief, wenn ein Rechteck gedreht wird.
Kulai
1
Ich bin mir nicht sicher, wer diese Antwort positiv bewertet hat. Dies ist nicht VerticalViewPager, sondern ViewPager mit 90 Grad Drehung, die Geste und der Übergang sind genau entgegengesetzt. und es ist überhaupt nicht natürlich
droidev
14

Für jemanden, der Probleme damit hat, wie vertikaler ViewPager in horizontaler Richtung funktioniert, gehen Sie einfach wie folgt vor:

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

}

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

}
Taucher
quelle
Wie kann ich diesen Pager für horizontale und vertikale Ansicht zu meiner Ansicht hinzufügen?
user1810931
Beginnen Sie mit dem Tutorial - vogella.com/tutorials/AndroidCustomViews/article.html
Divers
Wie implementiere ich die oben genannten Pager-Klassen für die horizontale und vertikale Ansicht in meiner Ansicht? Code-Snippet hilft
user1810931
ViewPager ist bereits angezeigt, ich verstehe nicht, worüber Sie fragen.
Taucher
Ich verwende eine Bibliothek namens "Material Calendar View" ( github.com/prolificinteractive/material-calendarview ) und sie enthält bereits einen horizontalen Viewpager, und ich wollte einen vertikalen Viewpager hinzufügen.
user1810931
8

Eine geringfügige Erweiterung dieser Antwort half mir, meine Anforderung zu erfüllen (Vertical View Pager zum Animieren ähnlich wie in Inshorts - News in 60 Wörtern )

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

Ich hoffe, dass dies jemand anderem hilfreich sein könnte.

Amrut Bidri
quelle
1
Idealer Wert für MIN_SCALE?
Divyenduz
Haben Sie nicht Problem mit Streichen nach oben schnell den Übergang zu finden , ist nicht glatt
Praneeth
Warum um alles in der Welt sollte jemand schnell nach oben streichen?
Amrut Bidri
Nur ein Kommentar zur Verdeutlichung: Diese Lösung ändert die Animation so, dass die neue Seite nicht von unten, sondern von hinten von der alten Seite kommt. Im Grunde genommen liegen also keine Seiten nebeneinander, sondern ein Seitenstapel, der übereinander liegt. Diese Lösung entspricht möglicherweise nicht der ursprünglichen Frage.
Benjamin Basmaci
4

Es gibt einige Open-Source-Projekte, die dies behaupten. Hier sind sie:

Diese wurden von ihren Autoren als veraltet markiert:

Und noch etwas:

Flimm
quelle
3

Überprüfen Sie dies: https://github.com/JakeWharton/Android-DirectionalViewPager

Oder die folgende Frage kann Ihnen helfen: Vertikale "Rasteransicht mit Seiten" oder "Viewpager"

sdabet
quelle
2
Zu beachten ist, dass das DirectionalViewPagerseit einiger Zeit nicht mehr aktualisiert wurde und daher einige der neueren Funktionen des ViewPagerin der Support-Bibliothek fehlen . dh setPageMargin(int). Im Allgemeinen sollte es den Job aber machen. Und wenn nicht, ist es nicht allzu schwierig, den Quellcode zu finden ViewPagerund die gesamte x / y- und width / height-Logik auszutauschen.
MH.
Ich habe das bereits berücksichtigt, DirectionalViewPageraber wie MH sagte, ist es nicht aktualisiert (sein Entwickler betrachtet es als DEPRECATED) !! Es ist unglaublich, dass Android-Entwickler der Community keine vertikale ViewPager, sondern nur horizontale Community zur Verfügung gestellt haben. Ich bin neuer als Android, die Entwicklung meines vertikalen ViewPagerAustauschs von x / y ist für mich nicht so einfach. Ich würde eine bereits erstellte Lösung bevorzugen.
Trotzdem
2
Hallo, hast du es geschafft, den vertikalen Viewpager zu machen? thansk
Paul
3

Nur eine Verbesserung der Antworten von @Brett und @ Salman666, um die Koordinaten (X, Y) korrekt in (Y, X) umzuwandeln , da die Geräteanzeigen rechteckig sind:

...

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

...

Es muss jedoch noch etwas getan werden, um die Reaktionsfähigkeit des Touchscreens zu verbessern. Das Problem könnte mit dem zusammenhängen, was @msdark zur Antwort von @ Salman666 kommentiert hat.

Anonym
quelle
Ich habe einige Verbesserungen, indem ich immer wieder truezurückkehre, onInterceptTouchEventund ich habe auch die Tastenkombinationen so geändert, dass bei Verwendung eines DPAD ein Bildlauf mit UP / DOWN anstelle von links / rechts ausgelöst wird
Vektor88
@ Vektor88 immer wahr zurückgibt verhindert, dass innere Ansichten Berührungsereignisse empfangen. Die beste Lösung ist wie in der brett Antwort.
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
quelle
1
Das funktioniert sehr gut, aber ich verliere das touchEvent für Elemente oder die Links- / Wischereignisse ...
Matiasfha
0

Es gibt tatsächlich bereits eine in der Android-Quelle . Ich habe es geändert, um besser zu funktionieren:

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
quelle
Dies funktioniert nicht richtig. Selbst die Android-Quellversion funktioniert nicht. Es ist fehlerhaft und funktioniert nur für rechte / linke Gesten. Wenn Sie nach oben / unten gehen, wird nicht gescrollt. Zumindest für mich.
Mohammad Zekrallah
0

Ein derzeit aktiveres Repository ist lsjwzh / RecyclerViewPager .

  • last commit 12 Aug 2016, 16 Mitwirkende, 1840 Sterne
  • beyogen auf RecyclerView
ford04
quelle
0

Dies ist eine vertikal scrollbare ViewPager-Implementierung. Funktioniert gut mit RecyclerView und ListView. Guochong / VerticalViewPager .

Verwenden Sie ViewPager.PageTransformer, um ViewPager vertikal zu scrollen, und stellen Sie außerdem einen View.OnTouchListener bereit, um den Bildlaufkonflikt zu behandeln.

/**
 * 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;
}
Tschad
quelle
Willkommen bei StackOverflow und vielen Dank für Ihre Hilfe. Vielleicht möchten Sie Ihre Antwort noch besser machen, indem Sie Code hinzufügen.
Elias MP
0

Sogar ich hatte das gleiche Problem damit, ViewPager durch Vertauschen von X und Y vertikal zu machen. Es war überhaupt nicht glatt.

Das liegt daran, dass es früher nur funktionierte, wenn der Wischwinkel beim Abfangen weniger als 7,125 Grad = Arctan (1/8) und beim Berühren 14 Grad = Arctan (1/4) betrug. Als ursprünglicher horizontaler ViewPager funktioniert man, wenn der Wischwinkel beim Abfangen weniger als 26,565 Grad = Arctan (1/2) und beim Berühren 45 Grad = Arctan (1) beträgt.

Deshalb habe ich den Code von Android support-core-ui kopiert und die Werte in Variablen verschoben, die ich mit Reflection multipliziert habe.

Den Code und die README-Datei finden Sie unter https://github.com/deepakmishra/verticalviewpager und VerticalViewPager unter https://github.com/deepakmishra/verticalviewpager/blob/master/app/src/main/java/com/viewpager/VerticalViewPager .Java

Deepak
quelle
0

Der bessere Weg ist, den Viewpager um 90 Grad zu drehen und die Position mithilfe des ConstraintLayout anzupassen.

JackHui
quelle
0

Am Ende habe ich einen neuen DirectionalViewPager erstellt , der entweder vertikal oder horizontal scrollen kann, da alle Lösungen, die ich hier gesehen habe, Fehler aufweisen:

  1. Bestehende VerticalViewPager-Implementierungen (von castorflex und LambergaR)

    • Sie basieren auf sehr alten Versionen der Support-Bibliothek.
  2. Transformationstrick mit Koordinatentausch

    • Der Overscroller wird weiterhin am linken / rechten Rand angezeigt.
    • Das Umblättern von Seiten funktioniert nicht richtig, da selbst bei vertauschten Koordinaten VelocityTracker.computeCurrentVelocitydie Geschwindigkeit mit der X-Achse berechnet wird, wahrscheinlich weil intern ein nativer Aufruf verwendet wird, der den Koordinatentausch ignoriert.
  3. Rotation anzeigen

    • Hack, bei dem auch jede untergeordnete Ansicht gedreht werden muss.
    • Wenn Sie Koordinaten für etwas anderes lesen möchten, müssen Sie die Achse tauschen.
inorichi
quelle