Android: Vertical ViewPager [ปิด]


131

มีวิธีทำให้ a ViewPagerที่ไม่เลื่อนในแนวนอน แต่แนวตั้งหรือไม่!


1
มีการใช้งานโอเพนซอร์สอย่างไม่เป็นทางการใหม่ของ ViewPager แนวตั้ง: ประกาศ: plus.google.com/107777704046743444096/posts/1FTJfrvnY8w รหัส: github.com/LambergaR/VerticalViewPager
Vasily 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.PageTransformerViewPagerเพื่อให้ภาพลวงตาของแนวตั้ง เพื่อให้การเลื่อนด้วยแนวตั้งแทนที่จะเป็นการลากแนวนอนคุณจะต้องแทนที่ViewPagerเหตุการณ์การสัมผัสเริ่มต้นและสลับพิกัดของMotionEvents ก่อนการจัดการเช่น

/**
 * Uses a combination of a PageTransformer and swapping X & Y coordinates
 * of touch events to create the illusion of a vertically scrolling ViewPager. 
 * 
 * Requires API 11+
 * 
 */
public class VerticalViewPager extends ViewPager {

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

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

    private void init() {
        // The majority of the magic happens here
        setPageTransformer(true, new VerticalPageTransformer());
        // The easiest way to get rid of the overscroll drawing that happens on the left and right
        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements ViewPager.PageTransformer {

        @Override
        public void transformPage(View view, float position) {

            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);

            } else if (position <= 1) { // [-1,1]
                view.setAlpha(1);

                // Counteract the default slide transition
                view.setTranslationX(view.getWidth() * -position);

                //set Y position to swipe in from top
                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);

            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

    /**
     * Swaps the X and Y coordinates of your touch event.
     */
    private MotionEvent swapXY(MotionEvent ev) {
        float width = getWidth();
        float height = getHeight();

        float newX = (ev.getY() / height) * width;
        float newY = (ev.getX() / width) * height;

        ev.setLocation(newX, newY);

        return ev;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev){
        boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
        swapXY(ev); // return touch coordinates to original reference frame for any child views
        return intercepted;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(swapXY(ev));
    }

}

แน่นอนคุณสามารถปรับแต่งการตั้งค่าเหล่านี้ตามที่เห็นสมควร จบลงด้วยการมีลักษณะเช่นนี้:

การสาธิต VerticalViewPager


4
@Der Golem วิธีใช้เลย์เอาต์สำหรับสิ่งนี้?
bShah

คำถามที่แน่นอนคืออะไร? โดยวิธีการที่ฉันไม่ได้โพสต์คำตอบเพียงแค่เพิ่มภาพที่อ้างถึง
Phantômaxx

1
@ เบร็ทในตัวอย่างนี้ฉันต้องการดำเนินการบางอย่างกับการปัดซ้ายและขวา วิธีการทำเช่นนั้น
Prabs

1
@ เบร็ททำงานได้ตามที่คาดหวังการเปลี่ยนแปลงกำลังดำเนินไปในแนวตั้ง แต่ปัญหาคือฉันต้องปัดไปทางขวา / ซ้ายเพื่อทำการเปลี่ยนและในการปัดบน / ล่างไม่มีการเปลี่ยนแปลงเกิดขึ้น
Karan Khurana

2
@ เบร็ทฉันใช้โซลูชันของคุณ แต่ตอนนี้ฉันได้รับปัญหาการ swipping ในอุปกรณ์ ororid pie มีผู้ใดประสบปัญหาเดียวกันหรือไม่
Jishant

21

ฉันมีวิธีแก้ปัญหาที่เหมาะกับฉันในสองขั้นตอน

  1. onInstantiateItem()จากPagerAdapterสร้างมุมมองและหมุนโดย -90:

    view.setRotation(-90f)

    หากคุณกำลังใช้FragmentPagerAdapterงานอยู่:

    objFragment.getView().setRotation(-90)
  2. หมุนViewPagerมุมมอง 90 องศา:

    objViewPager.setRotation(90)

ทำงานอย่างมีเสน่ห์อย่างน้อยก็สำหรับความต้องการของฉัน


4
วิธีนี้ใช้งานได้ แต่คุณยังต้องกวาดในแนวนอนในขณะที่ viewPager เลื่อนไปตามแนวตั้ง
leochab

@Kulai ฉันไม่ชัดเจนว่าจะทำอย่างไรที่นี่คุณสามารถอธิบายหน่อยได้ตามความเข้าใจของฉันเรามีวัตถุสาธารณะ instantiateItem (คอนเทนเนอร์ ViewGroup ตำแหน่ง int) ที่นี่เราต้องทำ container.setRotation (-90f);
varun

1
การทำเช่นนั้นทำงานได้อย่างมีเสน่ห์! ด้วยมุมมองที่ได้รับการตัดในส่วนบนและด้านล่างและฉันไม่สามารถคิดออกว่าทำไม: - /
Nivaldo Bondança

2
มันทำงานได้อย่างถูกต้องสำหรับภาพสี่เหลี่ยมจัตุรัสและไม่เหมาะกับสี่เหลี่ยม ขนาดผิดไปเมื่อสี่เหลี่ยมผืนผ้าหมุน
Kulai

1
ฉันไม่แน่ใจว่าใครโหวตคำตอบนี้ นี่ไม่ใช่ VerticalViewPager นี่คือ ViewPager ที่หมุนได้ 90 องศาท่าทางและการเปลี่ยนจะตรงกันข้าม และมันไม่ได้เป็นธรรมชาติเลย
droidev

20

มุมมองแนวตั้ง

คำตอบอื่น ๆ ที่นี่ทั้งหมดดูเหมือนจะมีปัญหาบางอย่างกับพวกเขา แม้แต่โครงการโอเพ่นซอร์สที่แนะนำก็ไม่ได้รวมคำขอดึงล่าสุดกับการแก้ไขข้อบกพร่อง จากนั้นฉันพบ a VerticalViewPagerจาก Google ว่าพวกเขาใช้แอป DeskClock ฉันเชื่อมั่นในการใช้งานของ Google มากกว่าคำตอบอื่น ๆ (เวอร์ชันของ Google คล้ายกับคำตอบที่ได้รับคะแนนสูงสุดในปัจจุบัน แต่ละเอียดยิ่งขึ้นกว่านี้)

ตัวอย่างเต็ม

ตัวอย่างนี้เกือบเหมือนกับตัวอย่างพื้นฐานของViewPagerของฉันโดยมีการเปลี่ยนแปลงเล็กน้อยเพื่อใช้VerticalViewPagerคลาส

ป้อนคำอธิบายรูปภาพที่นี่

XML

เพิ่มเลย์เอาต์ xml สำหรับกิจกรรมหลักและสำหรับแต่ละหน้า (แฟรกเมนต์) หมายเหตุที่เราใช้มากกว่ามาตรฐานVerticalViewPager ViewPagerฉันจะรวมรหัสสำหรับด้านล่าง

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.verticalviewpager.MainActivity">

    <com.example.myapp.VerticalViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

fragment_one.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textview"
        android:textSize="30sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

</RelativeLayout>

รหัส

รหัสสำหรับVerticalViewPagerไม่ใช่ของฉัน มันเป็นเพียงเวอร์ชันที่ถูกตัดทอน (ไม่มีความคิดเห็น) จากซอร์สโค้ดของ Google ลองดูเวอร์ชั่นล่าสุดสำหรับเวอร์ชั่นล่าสุด ความคิดเห็นที่มีประโยชน์สำหรับการทำความเข้าใจสิ่งที่เกิดขึ้น

VerticalViewPager.java

import android.support.v4.view.ViewPager;    

public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        this(context, null);
    }

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

    @Override
    public boolean canScrollHorizontally(int direction) {
        return false;
    }

    @Override
    public boolean canScrollVertically(int direction) {
        return super.canScrollHorizontally(direction);
    }

    private void init() {
        setPageTransformer(true, new VerticalPageTransformer());
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final boolean toIntercept = super.onInterceptTouchEvent(flipXY(ev));
        flipXY(ev);
        return toIntercept;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final boolean toHandle = super.onTouchEvent(flipXY(ev));
        flipXY(ev);
        return toHandle;
    }

    private MotionEvent flipXY(MotionEvent ev) {
        final float width = getWidth();
        final float height = getHeight();
        final float x = (ev.getY() / height) * width;
        final float y = (ev.getX() / width) * height;
        ev.setLocation(x, y);
        return ev;
    }

    private static final class VerticalPageTransformer implements ViewPager.PageTransformer {
        @Override
        public void transformPage(View view, float position) {
            final int pageWidth = view.getWidth();
            final int pageHeight = view.getHeight();
            if (position < -1) {
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);
                view.setTranslationX(pageWidth * -position);
                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);
            } else {
                view.setAlpha(0);
            }
        }
    }
}

MainActivity.java

ผมสลับเดียวที่ออกมาสำหรับVerticalViewPagerViewPager

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

}

แนวนอน ViewPager

public class HorizontalViewPager extends ViewPager {
    private GestureDetector xScrollDetector;

    public HorizontalViewPager(Context context) {
        super(context);
    }

    public HorizontalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        xScrollDetector = new GestureDetector(getContext(), new XScrollDetector());
    }

    class XScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return Math.abs(distanceX) > Math.abs(distanceY);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (xScrollDetector.onTouchEvent(ev)) {
            super.onInterceptTouchEvent(ev);
            return true;
        }

        return super.onInterceptTouchEvent(ev);
    }

}

ฉันจะเพิ่มเพจเจอร์มุมมองแนวนอนและแนวตั้งนี้ในมุมมองของฉันได้อย่างไร
user1810931

เริ่มต้นด้วยการสอน - vogella.com/tutorials/AndroidCustomViews/article.html
Divers

ฉันจะใช้คลาสเพจเจอร์มุมมองแนวนอนและแนวตั้งด้านบนในมุมมองของฉันได้อย่างไร ข้อมูลโค้ดช่วย
user1810931

ViewPager มีอยู่แล้วฉันไม่เข้าใจสิ่งที่คุณถาม
Divers

ฉันใช้ห้องสมุดชื่อ "มุมมองปฏิทินวัสดุ" ( github.com/prolificinteractive/material-calendarview ) และมีตัวดูแนวนอนอยู่แล้วและฉันต้องการเพิ่มมุมมองแนวตั้งในตัว
user1810931

8

ส่วนขยายเล็กน้อยคำตอบนี้ช่วยให้ฉันสามารถทำตามความต้องการของฉันได้ (มุมมองแนวตั้งเพจเจอร์ทำให้มีลักษณะคล้ายกันในInshorts - ข่าว 60 คำ )

public class VerticalViewPager extends ViewPager {

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

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

private void init() {
    // The majority of the magic happens here
    setPageTransformer(true, new VerticalPageTransformer());
    // The easiest way to get rid of the overscroll drawing that happens on the left and right
    setOverScrollMode(OVER_SCROLL_NEVER);
}

private class VerticalPageTransformer implements ViewPager.PageTransformer {
 private static final float MIN_SCALE = 0.75f;
    @Override
    public void transformPage(View view, float position) {

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        }  else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page
            view.setAlpha(1);
            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);

            //set Y position to swipe in from top
            float yPosition = position * view.getHeight();
            view.setTranslationY(yPosition);
            view.setScaleX(1);
            view.setScaleY(1);

        } else if (position <= 1) { // [0,1]
            view.setAlpha(1);

            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);


            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }

    }

}

/**
 * Swaps the X and Y coordinates of your touch event.
 */
private MotionEvent swapXY(MotionEvent ev) {
    float width = getWidth();
    float height = getHeight();

    float newX = (ev.getY() / height) * width;
    float newY = (ev.getX() / width) * height;

    ev.setLocation(newX, newY);

    return ev;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
    boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
    swapXY(ev); // return touch coordinates to original reference frame for any child views
    return intercepted;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}
}

ฉันหวังว่านี่จะเป็นประโยชน์กับคนอื่น


1
คุ้มค่าสำหรับ MIN_SCALE หรือไม่
divyenduz

คุณไม่พบปัญหากับการปัดขึ้นอย่างรวดเร็วการเปลี่ยนแปลงไม่ราบรื่น
Praneeth

ทำไมบนโลกนี้ถึงมีคนตบอย่างรวดเร็ว
Amrut Bidri

เพียงความคิดเห็นเพื่อชี้แจง: วิธีนี้จะเปลี่ยนภาพเคลื่อนไหวในลักษณะที่หน้าใหม่ไม่ได้มาจากด้านล่าง แต่มาจากด้านหลังหน้าเก่า โดยพื้นฐานแล้วคุณไม่มีหน้าวางอยู่ข้าง ๆ กัน แต่เป็นหน้าของชั้นวางซ้อนทับกัน ดังนั้นวิธีนี้อาจไม่ใช่คำถามเดิมที่พยายามจะทำ
Benjamin Basmaci

4

มีโครงการโอเพนซอร์ซสองสามตัวที่อ้างว่าทำสิ่งนี้ ที่นี่พวกเขาคือ:

  • kaelaela / VerticalViewPager คอมมิชชันล่าสุดในเดือนตุลาคม 2558 และหนึ่งในผู้สนับสนุน
  • castorflex / VerticalViewPager , คอมมิชชันล่าสุดในเดือนกุมภาพันธ์ 2014 และผู้สนับสนุนสามคน
  • LambergaR / VerticalViewPager /ล่าสุดคอมมิชชันใน ส.ค. 2556 และหนึ่งในผู้สนับสนุน

สิ่งเหล่านี้ได้ถูกคัดค้านโดยผู้เขียน:

และอีกสิ่งหนึ่ง:

  • นอกจากนี้ยังมีชื่อไฟล์VerticalViewPager.java ในแหล่ง Androidจากdeskclockแอป แต่ดูเหมือนจะไม่ได้รับการสนับสนุนอย่างเป็นทางการเนื่องจากฉันไม่สามารถหาเอกสารของมันได้

3

ลองใช้งานได้เลย: https://github.com/JakeWharton/Android-DirectionalViewPager

หรือคำถามต่อไปนี้อาจช่วยคุณได้: แนวตั้ง 'Gridview with pages' หรือ 'Viewpager'


2
สิ่งที่ต้องคำนึงถึงคือการที่DirectionalViewPagerไม่ได้รับการปรับปรุงมาระยะหนึ่งแล้วจึงขาดคุณสมบัติใหม่บางอย่างViewPagerในไลบรารีการสนับสนุน setPageMargin(int)กล่าวคือ โดยทั่วไปควรจะทำงานแม้ว่า และหากไม่เป็นเช่นนั้นก็ไม่ยุ่งยากเกินกว่าที่จะคว้าซอร์สโค้ดมาViewPagerและสลับออกทั้งหมด x / y และตรรกะความกว้าง / ความสูง
MH

ฉันได้คำนึงถึงสิ่งนี้แล้วDirectionalViewPagerแต่อย่างที่ MH บอกไว้ว่ามันไม่ได้รับการปรับปรุง (นักพัฒนาของมันพิจารณาว่าเป็นไม่ถูกต้อง) !! ไม่น่าเชื่อว่านักพัฒนา Android ไม่ได้ให้แนวตั้งแก่ชุมชนViewPagerแต่มีเพียงขอบเขตอันไกลโพ้น ฉันใหม่สำหรับ Android พัฒนาการ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


ฉันมีการปรับปรุงบางส่วนโดยมักจะกลับมาtrueในonInterceptTouchEventและฉันได้เปลี่ยนไปด้วยปุ่มลัดเพื่อให้ใช้ DPAD มันเป็นต้นเหตุเลื่อนขึ้น / ลงแทนซ้าย / ขวา: gist.github.com/zevektor/fbacf4f4f6c39fd6e409
Vektor88

@ Vektor88 ที่กลับมาจริงจะป้องกันไม่ให้มุมมองจากภายในได้รับการสัมผัสเหตุการณ์ .. ทางออกที่ดีที่สุดคือตอบ brett ..
Mohammad Zekrallah

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

public class VerticalViewPager extends ViewPager {

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


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

        setPageTransformer(true, new VerticalPageTransformer());

        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements PageTransformer {

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

            if (position < -1) {

                view.setAlpha(0);

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


                view.setTranslationX(pageWidth * -position);


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

            } else {

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

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

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

1
นี้ทำงานได้ดีมาก แต่ฉันสูญเสีย touchEvent ในองค์ประกอบหรือเหตุการณ์ซ้าย / รูดที่ ...
matiasfha

0

มีจริงแล้วหนึ่งในแหล่งที่มาของ Android ฉันได้ปรับเปลี่ยนให้ทำงานได้ดีขึ้นแม้ว่า:

package com.crnlgcs.sdk.widgets;



import android.content.Context;
import android.support.v4.view.ViewConfigurationCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;

public class VerticalViewPager extends ViewPager {
    private static final String TAG = "VerticalViewPager";
    private static final boolean DEBUG = true;

    private float mLastMotionX;
    private float mLastMotionY;
    private float mTouchSlop;
    private boolean mVerticalDrag;
    private boolean mHorizontalDrag;

    // Vertical transit page transformer
    private final ViewPager.PageTransformer mPageTransformer = new ViewPager.PageTransformer() {
        @Override
        public void transformPage(View view, float position) {
            final int pageWidth = view.getWidth();
            final int pageHeight = view.getHeight();
            if (position < -1) {
                // This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 1) {
                view.setAlpha(1);
                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);
                // set Y position to swipe in from top
                float yPosition = position * pageHeight;
                view.setTranslationY(yPosition);
            } else {
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    };

    public VerticalViewPager(Context context) {
        super(context, null);
    }

    public VerticalViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        final ViewConfiguration configuration = ViewConfiguration.get(context);
        mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
        init();
    }

    private void init() {
        // Make page transit vertical
        setPageTransformer(true, mPageTransformer);
        // Get rid of the overscroll drawing that happens on the left and right (the ripple)
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        final float x = ev.getX();
        final float y = ev.getY();

        if (DEBUG) Log.v(TAG, "onTouchEvent " + x + ", " + y);

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                mLastMotionX = x;
                mLastMotionY = y;
                if (!super.onTouchEvent(ev))
                    return false;
                return verticalDrag(ev);
            }
            case MotionEvent.ACTION_MOVE: {
                final float xDiff = Math.abs(x - mLastMotionX);
                final float yDiff = Math.abs(y - mLastMotionY);
                if (!mHorizontalDrag && !mVerticalDrag) {
                    if (xDiff > mTouchSlop && xDiff > yDiff) { // Swiping left and right
                        mHorizontalDrag = true;
                    } else if (yDiff > mTouchSlop && yDiff > xDiff) { //Swiping up and down
                        mVerticalDrag = true;
                    }
                }
                if (mHorizontalDrag) {
                    return super.onTouchEvent(ev);
                } else if (mVerticalDrag) {
                    return verticalDrag(ev);
                }
            }
            case MotionEvent.ACTION_UP: {
                if (mHorizontalDrag) {
                    mHorizontalDrag = false;
                    return super.onTouchEvent(ev);
                }
                if (mVerticalDrag) {
                    mVerticalDrag = false;
                    return verticalDrag(ev);
                }
            }
        }
        // Set both flags to false in case user lifted finger in the parent view pager
        mHorizontalDrag = false;
        mVerticalDrag = false;

        return false;
    }


    private boolean verticalDrag(MotionEvent ev) {
        final float x = ev.getX();
        final float y = ev.getY();
        ev.setLocation(y, x);
        return super.onTouchEvent(ev);
    }
}

มันทำงานไม่ถูกต้อง .. แม้แต่เวอร์ชั่นที่ใช้ Android ก็ไม่ได้ทำงานอย่างถูกต้องสำหรับท่าทางซ้าย / ขวา .. ถ้าคุณทำขึ้น / ลงมันไม่เลื่อนเลย .. อย่างน้อยสำหรับฉัน ..
Mohammad Zekrallah

0

พื้นที่เก็บข้อมูลขณะใช้งานมากขึ้นเป็นlsjwzh / RecyclerViewPager

  • กระทำครั้งสุดท้าย 12 ส.ค. 2559, 16 ผู้ร่วมงาน, 1840 ดาว
  • ขึ้นอยู่กับ RecyclerView

0

นี่คือการปรับใช้ ViewPager ที่เลื่อนได้ในแนวตั้งทำงานได้ดีกับ RecyclerView และ ListView guochong / VerticalViewPager

ใช้ ViewPager.PageTransformer เพื่อทำให้ ViewPager เลื่อนในแนวตั้งและให้ ViewOnTouchListener เพื่อจัดการกับความขัดแย้งในการเลื่อน

/**
 * 1.dispatch ACTION_DOWN,ACTION_UP,ACTION_CANCEL to child<br>
 * 2.hack ACTION_MOVE
 *
 * @param v
 * @param e
 * @return
 */
@Override
public boolean onTouch(View v, MotionEvent e) {
    Log.i(TAG, "onTouchEvent " + ", action " + e.getAction() + ", e.rawY " + e.getRawY() + ",lastMotionY " + lastMotionY + ",downY " + downY);
    switch (e.getAction()) {
        case MotionEvent.ACTION_DOWN:
            downY = e.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:

            if (downY == Float.MIN_VALUE && lastMotionY == Float.MIN_VALUE) {
                //not start from MOTION_DOWN, the child dispatch this first motion
                downY = e.getRawY();
                break;
            }

            float diff = e.getRawY() - (lastMotionY == Float.MIN_VALUE ? downY : lastMotionY);
            lastMotionY = e.getRawY();
            diff = diff / 2; //slow down viewpager scroll
            Log.e(TAG, "scrollX " + dummyViewPager.getScrollX() + ",basescrollX " + dummyViewPager.getBaseScrollX());

            if (dummyViewPager.getScrollX() != dummyViewPager.getBaseScrollX()) {
                if (fakeDragVp(v, e, diff)) return true;
            } else {
                if (ViewCompat.canScrollVertically(v, (-diff) > 0 ? 1 : -1)) {
                    Log.e(TAG, "scroll vertically  " + diff + ", move.lastMotionY " + e.getY());
                    break;
                } else {
                    dummyViewPager.beginFakeDrag();
                    fakeDragVp(v, e, diff);
                    adjustDownMotion(v, e);
                    return true;
                }
            }

            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            if (dummyViewPager.isFakeDragging()) {
                try {
                    dummyViewPager.endFakeDrag();
                } catch (Exception e1) {
                    Log.e(TAG, "", e1);
                }
            }
            reset();
            break;
    }

    return false;
}

ยินดีต้อนรับสู่ StackOverflow และขอขอบคุณสำหรับความช่วยเหลือของคุณ คุณอาจต้องการคำตอบที่ดียิ่งขึ้นโดยการเพิ่มรหัส
Elias MP

0

แม้ฉันกำลังเผชิญปัญหาเดียวกันกับการทำให้ ViewPager เป็นแนวตั้งโดยการสลับ X และ Y มันไม่ราบรื่นเลย

นั่นเป็นเพราะมันใช้งานได้เฉพาะเมื่อมุมการปัดน้อยกว่า 7.125 องศา = arctan (1/8) ในขณะที่การสกัดกั้นและ 14 องศา = arctan (1/4) ในขณะที่สัมผัส ตามต้นฉบับ ViewPager แนวนอนหนึ่งทำงานเมื่อมุมของการปัดน้อยกว่า 26.565 องศา = arctan (1/2) ในขณะที่ตัดและ 45 องศา = arctan (1) ในขณะที่สัมผัส

นั่นเป็นเหตุผลที่ฉันคัดลอกรหัสของ Android support-core-ui และย้ายค่าไปยังตัวแปรซึ่งฉันคูณด้วยการสะท้อนกลับ

โปรดค้นหารหัสและ README ได้ที่https://github.com/deepakmishra/verticalviewpager และ VerticalViewPager ที่https://github.com/deepakmishra/verticalviewpager/blob/master/app/src/main/java/com/viewpager/VerticalViewPager .java


0

วิธีที่ดีกว่าคือการหมุนตัวรับชมเพจ 90 องศาและใช้ข้อ จำกัด เค้าโครงเพื่อปรับตำแหน่ง


0

ฉันลงเอยด้วยการสร้างDirectionalViewPagerใหม่ที่สามารถเลื่อนได้ทั้งแนวตั้งหรือแนวนอนเพราะโซลูชันทั้งหมดที่ฉันเห็นที่นี่มีข้อบกพร่อง:

  1. การใช้งาน VerticalViewPager ที่มีอยู่ (โดย castorflex และ LambergaR)

    • พวกเขาจะขึ้นอยู่กับรุ่นห้องสมุดสนับสนุนเก่ามาก
  2. เคล็ดลับการแปลงกับการแลกเปลี่ยนประสานงาน

    • overscroller ยังคงแสดงจากขอบซ้าย / ขวา
    • การเหวี่ยงหน้าไม่ทำงานอย่างถูกต้องเพราะถึงแม้จะมีการสลับค่าพิกัด แต่VelocityTracker.computeCurrentVelocityก็ยังคำนวณความเร็วด้วยแกน X ซึ่งอาจเป็นเพราะการใช้การโทรภายในนั้นไม่สนใจการแลกเปลี่ยนพิกัด
  3. ดูการหมุน

    • การแฮ็กที่ต้องการมุมมองของเด็กทุกคนต้องหมุน
    • หากคุณต้องการอ่านพิกัดสำหรับสิ่งอื่นคุณต้องสลับแกน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.