Android : Vertical ViewPager [닫힘]


131

ViewPager가로로 스크롤하지 않고 세로로 스크롤 하는 방법이 있습니까 ?!


1
수직 ViewPager의 새로운 비공식 오픈 소스 구현이 있습니다 : 발표는 : plus.google.com/107777704046743444096/posts/1FTJfrvnY8w 코드 : github.com/LambergaR/VerticalViewPager
바실리 Sochinsky

Antoine Merle의 수직 뷰 호출기 구현 : github.com/castorflex/VerticalViewPager
micnoy

19 개의 지원 라이브러리를 기반으로하는 새로운 구현이 있습니다 : github.com/castorflex/VerticalViewPager
Vasily Sochinsky

이름은 비슷하지만 github.com/castorflex/VerticalViewPager 와 동일하지 않습니다 .
Flimm

1
컨트롤이 있습니다 ViewPager2의 체크 데모 여기 stackoverflow.com/a/54643817/7666442
Nilesh Rathod

답변:


227

ViewPager.PageTransformer 를 사용 하여 세로의 환영을 줄 수 있습니다 ViewPager. 가로 드래그 대신 세로로 스크롤을 수행하려면 ViewPager의 기본 터치 이벤트 를 재정의 MotionEvent하고 처리하기 전에 의 좌표를 교체 해야합니다. 예 :

/**
 * 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 데모


4
@Der Golem이 레이아웃을 사용하는 방법은 무엇입니까?
bShah

정확한 질문은 무엇입니까? 그건 그렇고, 나는 대답을 게시하지 않고 참조 된 이미지를 추가했습니다.
Phantômaxx

1
이 예에서 @Brett는 왼쪽과 오른쪽으로 스 와이프하여 작업을 수행하려고합니다. 방법
Prabs

1
@Brett 예상대로 작동하며 전환이 수직으로 진행됩니다. 그러나 문제는 전환을 수행하기 위해 오른쪽 / 왼쪽으로 스 와이프해야하며 스 와이프 상단 / 하단에서 전환이 발생하지 않아야한다는 것입니다.
카란 Khurana

2
@Brett 나는 당신의 솔루션을 사용하고있었습니다. 하지만 지금은 ororid 파이 장치에서 스와이 핑 문제가 발생합니다. 같은 문제에 직면 한 사람이 있습니까?
Jishant

21

두 단계로 나에게 적합한 솔루션이 있습니다.

  1. onInstantiateItem()PagerAdapter보기를 작성하고 -90만큼 회전시킵니다.

    view.setRotation(-90f)

    를 사용하는 경우 FragmentPagerAdapter:

    objFragment.getView().setRotation(-90)
  2. ViewPager뷰를 90도 회전 :

    objViewPager.setRotation(90)

적어도 내 요구 사항에는 매력처럼 작동합니다.


4
이 솔루션은 효과가 있지만, 여전히 가로로 스 와이프해야하지만 viewPager가 세로로 스크롤됩니다
leochab

@ 쿨라이 나는 여기서 무엇을 해야할지 모르겠다. 내 이해에 따라 우리가 public Object instantiateItem (ViewGroup container, int position)을 가지고 있다고 설명 할 수있다 여기 container.setRotation (-90f);
varun

1
그렇게하는 것이 매력처럼 작동합니다! Althoug보기가 상단과 하단 부분에서
잘려나가는

2
정사각형 이미지가 아닌 정사각형 이미지에는 올바르게 작동합니다. 사각형을 회전하면 치수가 잘못됩니다.
Kulai

1
누가이 답변을 투표했는지 잘 모르겠습니다. 이것은 VerticalViewPager가 아니며, 90도 회전 된 ViewPager이며 제스처와 전환은 반대입니다. 그리고 그것은 자연
스럽지

20

세로보기

다른 답변은 모두 문제가있는 것 같습니다. 권장되는 오픈 소스 프로젝트조차도 최근 풀 요청을 버그 수정과 병합하지 않았습니다. 그런 다음VerticalViewPager Google에서 DeskClock 앱을 사용했다는 것을 . 나는 구글의 구현을 여기에 떠있는 다른 답변보다 훨씬 많이 사용한다고 신뢰합니다. (Google 버전은 현재 가장 인기있는 답변과 비슷하지만 더 철저합니다.)

전체 예

이 예제는 기본 ViewPager Example 과 거의 동일 하며 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;
        }
    }
}

끝마친

앱을 실행하고 위 애니메이션에서 결과를 볼 수 있어야합니다.

또한보십시오


3
코드가 잘 깨어 나면 1 작은 도움이 필요합니다. 현재 코드에서는 다음 페이지를 얻기 위해 아래에서 위로 스 와이프해야하지만 작은 스 와이프도 다음 페이지를 가져와야합니다.
AMIT

14

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

}

가로보기

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 년


뷰에서 위의 가로 및 세로보기 호출기 클래스를 어떻게 구현합니까? 코드 스 니펫 도움
user1810931

ViewPager가 이미 표시되어 있습니다. 나는 당신이 무엇을 요구하는지 이해하지 못합니다.
Divers

"Material Calendar View"( github.com/prolificinteractive/material-calendarview ) 라는 라이브러리를 사용 하고 있으며 이미 수평 viewpager가 있고 수직 viewpager를 추가하고 싶었습니다.
user1810931

8

약간의 확장 (처럼 애니메이션 유사한 수직의 뷰 호출기 대답은 내 요구 사항을 달성하기 위해 나에게 도움이 - 60 개 단어의 뉴스 Inshorts )

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

빠르게 스 와이프하는 문제가 발견되지 않았습니까? 전환이 매끄럽지 않습니다
Praneeth

왜 지구상에서 누군가가 빠르게 스 와이프합니까?
Amrut Bidri 2018

명확하게 설명하기 :이 솔루션은 새 페이지가 아래에서가 아니라 이전 페이지에서 오는 방식으로 애니메이션을 변경합니다. 따라서 기본적으로 서로 옆에 페이지를 놓지 않고 서로 위에 놓인 페이지 데크가 있습니다. 따라서이 솔루션은 원래 질문이 시도하는 것이 아닐 수도 있습니다.
벤자민 바스 마치

4

이것을 주장하는 오픈 소스 프로젝트가 몇 가지 있습니다. 여기 있습니다:

이들은 저자가 더 이상 사용하지 않는 것으로 표시되었습니다.

그리고 하나 더:

  • 이 파일 이름 또한 안드로이드 소스 VerticalViewPager.java 로부터 deskclock응용 프로그램,하지만 나는 그것을 위해 문서를 찾을 수 없기 때문에 공식적으로 지원하지 않는 것 같습니다.

3

이것을 확인하십시오 : https://github.com/JakeWharton/Android-DirectionalViewPager

또는 다음 질문이 도움이 될 수 있습니다. 세로 '페이지가있는 Gridview'또는 'Viewpager'


2
명심해야 DirectionalViewPager할 것은 상당히 오래 업데이트되지 않았기 때문에 ViewPager지원 라이브러리에서 새로운 기능 중 일부가 누락되었다는 것입니다 . 즉 setPageMargin(int). 일반적으로 작업을 수행해야합니다. 그렇지 않은 경우 소스 코드를 가져 ViewPager와서 모든 x / y 및 너비 / 높이 논리를 교체하는 것은 까다 롭지 않습니다 .
MH.

나는 이미 고려 DirectionalViewPager했지만 MH가 말했듯이 업데이트되지 않았습니다 (개발자가 DEPRECATED로 간주합니다) !! 안드로이드 개발자가 커뮤니티에 수직적 ViewPager이지만 호의적 인 것만 제공 한 것은 놀라운 일입니다 . 나는 안드로이드에 새로운 해요, 내 수직 개발 ViewPager어쨌든 .. 난 이미 구축 솔루션을 원합니다 .. X / Y 나를 위해 그렇게 쉬운 일이 아닙니다 스와핑을, 감사합니다
user1709805

2
안녕하세요, 수직 viewpager을 했습니까? thansk
Paul

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의 답변에 대해 언급 한 내용과 관련이있을 수 있습니다.


난 항상 반환하여 몇 가지 개선이 trueonInterceptTouchEvent나는 또한 키 바인딩을 수정 그래서 UP / DOWN와 스크롤을 트리거하는 DPAD를 대신 사용하는 것은 떠났다 / 우측했습니다 gist.github.com/zevektor/fbacf4f4f6c39fd6e409
Vektor88

Vektor88 항상 터치 이벤트를 수신 내부 의견을 방지 할 진정한 복귀 .. @ 가장 좋은 방법은 브렛의 대답과 같다 ..
모하마드 Zekrallah

2
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class VerticalViewPager extends ViewPager {

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


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

        setPageTransformer(true, new VerticalPageTransformer());

        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements PageTransformer {

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

            if (position < -1) {

                view.setAlpha(0);

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


                view.setTranslationX(pageWidth * -position);


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

            } else {

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

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

        return super.onTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        ev.setLocation(ev.getY(), ev.getX());
        return super.onInterceptTouchEvent(ev);
    }
}

1
이것은 매우 잘 작동하지만 요소 또는 왼쪽 / 스 와이프 이벤트에서 touchEvent를 잃습니다 ...
matiasfha

0

실제로 안드로이드 소스 에 이미 하나 있습니다. 그래도 더 잘 작동하도록 수정했습니다.

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

이것은 제대로 작동하지 않습니다 .. 안드로이드 소스 버전조차도 .. 그것의 결함이 있고 오른쪽 / 왼쪽 제스처에만 작동합니다 .. 위 / 아래로 스크롤하면 스크롤되지 않습니다 .. 적어도 나를 위해 ..
Mohammad Zekrallah


0

이것은 세로 스크롤 가능한 ViewPager 구현입니다. RecyclerView 및 ListView와 잘 작동합니다. guochong / 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에 오신 것을 환영합니다. 도와 주셔서 감사합니다. 코드를 추가하여 더 나은 답변을 원할 수 있습니다.
엘리아스 MP

0

심지어 X와 Y를 바꾸어 ViewPager를 세로로 만드는 것과 같은 문제에 직면했습니다.

스와이 핑 각도가 차단하는 동안 7.125도 = arctan (1/8) 미만이고 만지는 동안 14도 = arctan (1/4) 미만인 경우에만 작동했기 때문입니다. 스와이 핑 각도가 가로채는 동안 26.565도 = arctan (1/2)보다 작고 터치하는 동안 45도 = arctan (1)보다 작은 경우 원래 ViewPager가 수평으로 작동합니다.

그렇기 때문에 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

더 좋은 방법은 viewpager를 90도 회전시키고 constraintLayout을 사용하여 위치를 조정하는 것입니다.


0

여기에서 본 모든 솔루션에 결함이 있기 때문에 세로 또는 가로로 스크롤 할 수 있는 새로운 DirectionalViewPager 를 만들었습니다 .

  1. 기존의 VerticalViewPager 구현 (castorflex 및 LambergaR)

    • 이들은 매우 오래된 지원 라이브러리 버전을 기반으로합니다.
  2. 좌표 교환이 가능한 변환 트릭

    • 오버 스크롤러는 여전히 왼쪽 / 오른쪽 가장자리에 표시됩니다.
    • 좌표가 바뀌어도 VelocityTracker.computeCurrentVelocityX 축으로 속도를 계산 하기 때문에 페이지 플링이 제대로 작동하지 않습니다. 내부적으로 좌표 스왑을 무시하는 기본 호출을 사용하기 때문일 수 있습니다.
  3. 회전보기

    • 모든 자식보기도 회전 해야하는 해킹.
    • 다른 것에 대한 좌표를 읽으려면 축을 바꿔야합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.