Android: ViewPager dọc [đã đóng]


130

Có cách nào để làm cho một ViewPagercái không cuộn theo chiều ngang, nhưng theo chiều dọc?!


1
Có một triển khai mã nguồn mở không chính thức mới của ViewPager dọc: Thông báo: plus.google.com/107777704046743444096/posts/1FTJfrvnY8w Mã: github.com/LambergaR/V
verticalViewPager

Triển khai máy nhắn tin theo chiều dọc của Antoine Merle: github.com/castorflex/V
verticalViewPager

Có một triển khai mới dựa trên thư viện hỗ trợ 19: github.com/castorflex/V
verticalViewPager

Điều này không giống như github.com/castorflex/V verticalViewPager , mặc dù có một tên tương tự.
Flimm

1
Có một điều khiển được gọi là ViewPager2 kiểm tra tại đây để xem demo stackoverflow.com/a/54643817/7666442
Nilesh Rathod

Câu trả lời:


227

Bạn có thể sử dụng ViewPager.PageTransformer để tạo ảo giác về chiều dọc ViewPager. Để đạt được cuộn bằng dọc thay vì kéo ngang, bạn sẽ phải ghi đè ViewPagercác sự kiện chạm mặc định của nó và hoán đổi tọa độ của MotionEvents trước khi xử lý chúng, ví dụ:

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

}

Tất nhiên bạn có thể điều chỉnh các cài đặt này khi bạn thấy phù hợp. Kết thúc như thế này:

Bản demo dọcViewPager


3
@Der Golem làm thế nào để sử dụng bố cục cho việc này?
bShah

Câu hỏi chính xác là gì? Nhân tiện, tôi không đăng câu trả lời, chỉ thêm hình ảnh được giới thiệu.
Phantômaxx

1
@Brett trong ví dụ này tôi muốn thực hiện một số hành động khi vuốt sang trái và phải. làm thế nào để làm điều đó
Mitchs

1
@Brett nó hoạt động như mong đợi, quá trình chuyển đổi đang diễn ra theo chiều dọc. Nhưng vấn đề là tôi phải vuốt sang phải / trái để thực hiện chuyển đổi và khi vuốt trên / dưới không có chuyển đổi nào diễn ra.
Karan Khurana

2
@Brett Tôi đã sử dụng giải pháp của bạn. nhưng bây giờ tôi đang gặp vấn đề trong các thiết bị bánh andorid. Có ai phải đối mặt với cùng một vấn đề?
Jishant

20

ViewPager dọc

Các câu trả lời khác ở đây dường như có một số vấn đề với họ. Ngay cả các dự án nguồn mở được đề xuất cũng không hợp nhất các yêu cầu kéo gần đây với sửa lỗi. Sau đó, tôi tìm thấy VerticalViewPagertừ Google rằng họ đã sử dụng một số ứng dụng DeskClock. Tôi tin tưởng sử dụng triển khai của Google nhiều hơn các câu trả lời khác trôi nổi quanh đây. (Phiên bản của Google tương tự như câu trả lời được bình chọn hàng đầu hiện tại, nhưng kỹ lưỡng hơn.)

Ví dụ đầy đủ

Ví dụ này gần giống hệt như Ví dụ ViewPager cơ bản của tôi , với một vài thay đổi nhỏ để sử dụng VerticalViewPagerlớp.

nhập mô tả hình ảnh ở đây

XML

Thêm bố cục xml cho hoạt động chính và cho mỗi trang (đoạn). Lưu ý rằng chúng tôi sử dụng VerticalViewPagerchứ không phải là tiêu chuẩn ViewPager. Tôi sẽ bao gồm mã cho bên dưới.

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>

Mã cho VerticalViewPagerkhông phải là của tôi. Nó chỉ là một phiên bản rút gọn (không có bình luận) từ mã nguồn Google. Kiểm tra cái đó cho phiên bản cập nhật nhất. Các ý kiến ​​cũng có ích để hiểu những gì đang xảy ra.

DọcViewPager.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

Tôi chỉ đổi chỗ VerticalViewPagercho 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;
        }
    }
}

Đã kết thúc

Bạn sẽ có thể chạy ứng dụng và xem kết quả trong hình động ở trên.

Xem thêm


3
Mã đang hoạt động tốt, chỉ cần 1 trợ giúp nhỏ. Trong mã hiện tại, chúng tôi cần vuốt từ dưới lên trên để lấy trang tiếp theo, nhưng tôi muốn ngay cả thao tác vuốt nhỏ cũng nên lấy trang tiếp theo.
AMIT

20

Tôi có một giải pháp phù hợp với tôi theo hai bước.

  1. onInstantiateItem() của PagerAdapter , tạo chế độ xem và xoay nó theo -90:

    view.setRotation(-90f)

    Nếu bạn đang sử dụng FragmentPagerAdapter, thì:

    objFragment.getView().setRotation(-90)
  2. Xoay ViewPagergóc nhìn 90 độ:

    objViewPager.setRotation(90)

Hoạt động như một sự quyến rũ ít nhất cho yêu cầu của tôi.


4
giải pháp này hoạt động, NHƯNG bạn vẫn phải vuốt theo chiều ngang trong khi viewPager bây giờ cuộn theo chiều dọc
leochab

@Kulai tôi không rõ phải làm gì ở đây, bạn có thể giải thích một chút theo sự hiểu biết của tôi không
varun

1
Làm như vậy hoạt động như một nét duyên dáng! Althoug chế độ xem bị cắt ở phần trên cùng và dưới cùng, và tôi không thể hiểu tại sao: - /
Nivaldo Bondança

2
Nó hoạt động đúng cho một hình ảnh vuông và không phải cho một hình chữ nhật. Kích thước sai khi xoay hình chữ nhật.
Kulai

1
Tôi không chắc ai đã bình chọn câu trả lời này. Đây không phải là dọcViewPager, đây là ViewPager với góc quay 90 độ, cử chỉ và chuyển đổi hoàn toàn ngược lại. và nó hoàn toàn không tự nhiên
droidev

14

Đối với ai đó đang vật lộn với cách làm cho ViewPager dọc hoạt động theo chiều ngang, chỉ cần thực hiện các công cụ sau:

ViewPager dọc

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 ngang

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

}

Làm cách nào tôi có thể thêm máy nhắn tin chế độ xem ngang và dọc này vào chế độ xem của mình?
dùng1810931


Làm cách nào để triển khai các lớp máy nhắn tin xem ngang và dọc ở trên trong chế độ xem của tôi? Đoạn mã giúp
dùng1810931

ViewPager đã được xem, tôi không hiểu bạn hỏi gì.
Thợ lặn

Tôi đang sử dụng một thư viện có tên "Chế độ xem lịch vật liệu" ( github.com/prolificinteractive/m vật liệu- calWikiview ) và nó đã có chế độ xem ngang trong đó và tôi muốn thêm chế độ xem dọc trong đó.
dùng1810931

8

Một phần mở rộng nhỏ câu trả lời này đã giúp tôi đạt được yêu cầu của mình (Máy nhắn tin dạng xem dọc để hoạt hình tương tự như trong Inshorts - Tin tức trong 60 từ )

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

Tôi hy vọng điều này có thể hữu ích cho người khác.


1
Giá trị lý tưởng cho MIN_SCALE?
divyenduz

Bạn không thấy vấn đề với việc vuốt lên nhanh quá trình chuyển đổi không suôn sẻ
Praneeth

Tại sao trên trái đất ai đó sẽ vuốt lên nhanh?
Amrut Bidri

Chỉ cần một nhận xét để làm rõ: Giải pháp này thay đổi hình ảnh động theo cách mà trang mới không đến từ bên dưới mà là từ phía sau trang cũ. Vì vậy, về cơ bản, bạn không có các trang nằm cạnh nhau mà thay vào đó là một loạt các trang, nằm chồng lên nhau. Vì vậy, giải pháp này có thể không phải là những gì câu hỏi ban đầu đang cố gắng làm.
Benjamin Basmaci

4

Có một vài dự án nguồn mở tuyên bố sẽ làm điều này. Họ đây rồi:

Những điều này đã được đánh dấu phản đối bởi các tác giả của họ:

Và một điều nữa:

  • Ngoài ra còn có một tên tệp verticalViewPager.java trong nguồn Android từ deskclockứng dụng, nhưng dường như nó không được hỗ trợ chính thức vì tôi không thể tìm thấy tài liệu cho nó.

3

Hãy xem điều này: https://github.com/JakeWharton/Android-DirectionalViewPager

Hoặc câu hỏi sau đây có thể giúp bạn: Dọc 'Gridview with page' hoặc 'Viewpager'


2
Một điều cần lưu ý là DirectionalViewPagerđã không được cập nhật trong một thời gian dài và do đó thiếu một số tính năng mới hơn của ViewPagerthư viện hỗ trợ; tức setPageMargin(int). Nói chung nó nên làm công việc mặc dù. Và nếu không, sẽ không quá khó để lấy mã nguồn ViewPagervà trao đổi tất cả logic x / y và chiều rộng / chiều cao.
MH.

Tôi đã xem xét DirectionalViewPagernhưng, như MH đã nói, nó không được cập nhật (nhà phát triển của nó coi nó là ĐỔI) !! Thật đáng kinh ngạc khi các nhà phát triển Android đã không cung cấp cho cộng đồng theo chiều dọc ViewPagermà chỉ có tầm nhìn. Tôi mới hơn với Android, phát triển ViewPagerviệc thay đổi theo chiều dọc x / y không dễ dàng đối với tôi .. tôi muốn một giải pháp đã được xây dựng .. dù sao, cảm ơn bạn
user1709805

2
xin chào, bạn đã quản lý để xem viewpager dọc ?? tiếng Phạn
Paul

3

Chỉ cần cải thiện câu trả lời từ @Brett@ Salman666 để chuyển đổi chính xác tọa độ (X, Y) thành (Y, X) vì màn hình thiết bị có hình chữ nhật:

...

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

...

Tuy nhiên, vẫn cần phải làm gì đó để đáp ứng màn hình cảm ứng tốt hơn. Vấn đề có thể liên quan đến những gì @msdark nhận xét về câu trả lời của @ Salman666.


Tôi có một số cải tiến bằng cách luôn luôn trở về truetrong onInterceptTouchEventvà Tôi cũng sửa đổi các ràng buộc chính, do đó sử dụng một DPAD nó gây nên cuộn với UP / DOWN thay vì trái / phải: gist.github.com/zevektor/fbacf4f4f6c39fd6e409
Vektor88

@ Vektor88 luôn luôn trả về đúng sẽ ngăn các quan điểm bên trong nhận được các sự kiện chạm .. giải pháp tốt nhất là như trong câu trả lời của brett ..
Mohammad Zekrallah 8/12/2015

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
Điều này hoạt động rất tốt, nhưng tôi mất touchEvent trên các yếu tố hoặc các sự kiện trái / vuốt ...
matiasfha

0

Thực sự đã có một trong nguồn Android . Tôi đã sửa đổi nó để hoạt động tốt hơn mặc dù:

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

Điều này không hoạt động đúng .. ngay cả phiên bản nguồn Android cũng không .. nó bị trục trặc và chỉ hoạt động cho các cử chỉ phải / trái .. nếu bạn làm lên / xuống thì nó không cuộn .. ít nhất là đối với tôi ..
Mohammad Zekrallah 7/2/2016

0

Một kho lưu trữ hiện đang hoạt động nhiều hơn là lsjwzh / RecyclerViewPager .

  • cam kết cuối cùng ngày 12 tháng 8 năm 2016, 16 người đóng góp, 1840 sao
  • dựa trên RecyclerView

0

Đây là một triển khai ViewPager có thể cuộn dọc. Làm việc tốt với RecyclerView và ListView. guochong / dọcViewPager .

sử dụng ViewPager.PageTransformer để tạo ViewPager cuộn theo chiều dọc và cũng cung cấp View.OnTouchListener để xử lý xung đột cuộn.

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

Chào mừng bạn đến với StackOverflow và cảm ơn sự giúp đỡ của bạn. Bạn có thể muốn làm cho câu trả lời của bạn thậm chí tốt hơn bằng cách thêm một số mã.
Elias MP

0

Ngay cả tôi cũng gặp phải vấn đề tương tự với việc tạo ViewPager theo chiều dọc bằng cách hoán đổi X và Y. Nó không hoàn toàn suôn sẻ.

Đó là bởi vì nó chỉ hoạt động khi góc vuốt nhỏ hơn 7.125 độ = arctan (1/8) trong khi chặn và 14 độ = arctan (1/4) khi chạm; như ViewPager ban đầu nằm ngang một tác phẩm khi góc vuốt nhỏ hơn 26,565 độ = arctan (1/2) trong khi chặn và 45 độ = arctan (1) trong khi chạm.

Đó là lý do tại sao tôi đã sao chép mã hỗ trợ Android-core-ui và chuyển các giá trị thành các biến, mà tôi đã nhân lên bằng cách sử dụng sự phản chiếu.

Vui lòng tìm mã và README tại https://github.com/deepakmishra/verticalviewpager và verticalViewPager tại https://github.com/deepakmishra/verticalviewpager/blob/master/app/src/main/java/com/viewpager/V vertical .java


0

cách tốt hơn là xoay chế độ xem 90 độ và sử dụng ràng buộcLayout để điều chỉnh vị trí.


0

Cuối cùng tôi đã tạo ra một DirectionalViewPager mới có thể cuộn theo chiều dọc hoặc chiều ngang bởi vì tất cả các giải pháp tôi thấy ở đây đều có sai sót:

  1. Các triển khai dọcViewPager hiện có (của castorflex và LambergaR)

    • Chúng dựa trên các phiên bản thư viện hỗ trợ rất cũ.
  2. Thủ thuật chuyển đổi với sự phối hợp hoán đổi

    • Bộ vi điều khiển vẫn được hiển thị từ các cạnh trái / phải.
    • Việc lật trang không hoạt động chính xác, bởi vì ngay cả khi tọa độ được hoán đổi, VelocityTracker.computeCurrentVelocityvẫn tính toán vận tốc với trục X, có thể vì nội bộ này sử dụng lệnh gọi gốc mà bỏ qua hoán đổi tọa độ.
  3. Xem xoay

    • Hack cần mọi góc nhìn trẻ em cũng được xoay vòng.
    • Nếu bạn muốn đọc tọa độ cho một cái gì đó khác, bạn phải trao đổi trục.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.