ปิดการใช้งานเพจจิ้งโดยการปัดด้วยนิ้วใน ViewPager แต่ยังสามารถปัดโปรแกรมได้


549

ฉันมี ViewPager และด้านล่างฉันมี 10 ปุ่ม เมื่อคลิกที่ปุ่มเช่น # 4 เพจเจอร์จะไปที่หน้า # 4 mPager.setCurrentItem(3);ทันที แต่ฉันต้องการปิดใช้งานการเพจโดยปัดด้วยนิ้วในแนวนอน ดังนั้นเพจจะทำเท่านั้นโดยคลิกที่ปุ่ม ดังนั้นฉันจะปิดการใช้งานการปัดด้วยนิ้วได้อย่างไร


วิธีการเกี่ยวกับการใช้ViewFlipperในตอนแรก? มันจะช่วยให้คุณปวดหัวมาก
Alex Semeniuk

คำตอบ:


885

คุณจำเป็นต้อง ViewPagersubclass onTouchEventมีหลายสิ่งที่ดีในนั้นที่คุณไม่ต้องการที่จะเปลี่ยนแปลงเช่นการอนุญาตให้มุมมองของเด็กที่จะได้สัมผัส onInterceptTouchEventคือสิ่งที่คุณต้องการเปลี่ยนแปลง หากคุณดูรหัสViewPagerคุณจะเห็นความคิดเห็น:

    /*
     * This method JUST determines whether we want to intercept the motion.
     * If we return true, onMotionEvent will be called and we do the actual
     * scrolling there.
     */

นี่คือโซลูชันที่สมบูรณ์:

ขั้นแรกเพิ่มคลาสนี้ในsrcโฟลเดอร์ของคุณ:

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
import java.lang.reflect.Field;

public class NonSwipeableViewPager extends ViewPager {

    public NonSwipeableViewPager(Context context) {
        super(context);
        setMyScroller();
    }

    public NonSwipeableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        setMyScroller();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // Never allow swiping to switch between pages
        return false;
    }

    //down one is added for smooth scrolling

    private void setMyScroller() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new MyScroller(getContext()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class MyScroller extends Scroller {
        public MyScroller(Context context) {
            super(context, new DecelerateInterpolator());
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
        }
    }
}

ถัดไปให้แน่ใจว่าจะใช้ชั้นนี้แทนที่จะเป็นปกติซึ่งคุณอาจระบุเป็นViewPager android.support.v4.view.ViewPagerในไฟล์เลย์เอาต์ของคุณคุณจะต้องระบุด้วย:

<com.yourcompany.NonSwipeableViewPager
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />

ตัวอย่างนี้อยู่ในLinearLayoutและมีขึ้นเพื่อใช้หน้าจอทั้งหมดซึ่งเป็นสาเหตุที่layout_weight1 และlayout_height0dp

และsetMyScroller();วิธีการสำหรับการเปลี่ยนแปลงอย่างราบรื่น


3
@louielouie ในด้านหมายเหตุ: มีเหตุผลใดเป็นพิเศษทำไมคุณถึงเลือกโซลูชันส่วน0dpสูง / 1น้ำหนักเหนือmatch_parentส่วนสูงเพื่อให้ได้ผลเต็มหน้าจอ คุณได้รับการปรับปรุงประสิทธิภาพโดยทำเช่นนั้น?
ubuntudroid

28
คำตอบนี้ไม่ได้ป้องกันการปัดหน้าเมื่อใช้แป้นซ้าย / ขวาของแป้นพิมพ์ (ลองใช้ในเครื่องจำลอง) อาจไม่เป็นปัญหาสำหรับอุปกรณ์ระบบสัมผัส แต่ด้วยทีวีและแล็ปท็อปอาจเป็นปัญหา
Vincent Mimoun-Prat

8
@MarvinLabs @Thorbear executeKeyEvent()วิธีที่ถูกต้องในการปิดการใช้งานเลื่อนหน้าโดยแป้นพิมพ์คือการแทนที่ allowScroll()นี่คือวิธีการที่เรียกร้องแล้ว // Never allow swiping by keyboard LEFT, RIGHT, TAB and SHIFT+TAB keys @Override public boolean executeKeyEvent(KeyEvent event) { return false; }
araks

6
ดีนี่ปิดการใช้งานเช่นเดียวกับการเลื่อนแนวตั้ง ... นี่คือไม่ดีถ้าคุณกำลังใช้ listviews
maysi

5
ฉันหวังว่า google จะให้วิธีการที่เราจัดหาวิธีการอินเทอร์เฟซของเราเกี่ยวกับวิธีการจัดการกับการแตะ / ปัดเนื่องจากฉันเชื่อว่ามันจะไม่เจ็บ
Neon Warge

466

ส่วนขยายทั่วไปที่มากกว่าViewPagerนั้นคือการสร้างSetPagingEnabledวิธีการเพื่อให้เราสามารถเปิดใช้งานและปิดใช้งานการเพจได้ทันที เพื่อเปิด / ปิดรูดเพียงทับสองวิธี: และonTouchEvent onInterceptTouchEventทั้งสองจะคืนค่า "เท็จ" ถ้าการเพจถูกปิดใช้งาน

public class CustomViewPager extends ViewPager {

    private boolean enabled;

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onTouchEvent(event);
        }

        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (this.enabled) {
            return super.onInterceptTouchEvent(event);
        }

        return false;
    }

    public void setPagingEnabled(boolean enabled) {
        this.enabled = enabled;
    } 
}

จากนั้นเลือกตัวเลือกนี้แทน viewpager ใน XML

<mypackage.CustomViewPager 
    android:id="@+id/myViewPager" 
    android:layout_height="match_parent" 
    android:layout_width="match_parent" />

คุณเพียงแค่ต้องเรียกใช้setPagingEnabledเมธอดด้วยfalseและผู้ใช้จะไม่สามารถปัดหน้าเพื่อให้เลขหน้าได้


3
ทำงานได้อย่างสมบูรณ์แบบสำหรับมุมมองที่มีหลายมุมมองย่อยโดยที่หนึ่งใช้การเลื่อนแนวนอน (เช่นแผนภูมิ AChartEngine) ในส่วนของฉันฉันใช้โทรกลับไปที่กิจกรรมของฉันบอกให้ปิดหรือปิดเพจจิ้งทั้งนี้ขึ้นอยู่กับว่าผู้ใช้สัมผัส (ACTION_MOVE) แผนภูมิหรือปล่อยไว้ (ACTION_CANCEL) ขอบคุณมาก!
riper

32
คุณสามารถลดความซับซ้อนของคุณonTouchEventและonInterceptTouchEventวิธีการที่มีreturn enabled && super.onTouchEvent(event);
nbarraille

2
@nbarraille นั่นเป็นเพียงเรื่องของสไตล์ คุณสามารถใช้รูปแบบใดก็ได้ที่คุณสามารถอ่านได้
Rajul

7
ฉันขอแนะนำให้เปลี่ยนชื่อเขตข้อมูลจาก "เปิดใช้งาน" เป็น "swipePageChangeEnabled" หรืออะไรทำนองนั้น หนึ่งเดือนหลังจากเขียนโค้ดคุณจะจำได้ไม่ยากว่า "เปิดใช้งาน" หมายความว่าอย่างไรโดยเฉพาะอย่างยิ่งเมื่อคลาสของคุณชื่อ "CustomViewPager" ซึ่งไม่ชัดเจนว่าการปรับแต่งนั้นคืออะไร นั่นเป็นเรื่องของสไตล์ แต่ลักษณะเป็นเรื่องสำคัญหากคุณไม่ต้องการที่จะจบลงด้วยโปรเจ็กต์ที่ไม่รองรับซึ่งจะง่ายกว่าการเขียนใหม่ทั้งหมดเพื่อแก้ไข
bytefu

4
ฉันจะเรียกใช้ setPagingEnabled ได้ที่ไหน ._
Ntikki

107

วิธีที่ง่ายที่สุดคือการsetOnTouchListenerและผลตอบแทนสำหรับtrueViewPager

mPager.setOnTouchListener(new OnTouchListener()
    {           
        @Override
        public boolean onTouch(View v, MotionEvent event)
        {
            return true;
        }
    });

53
บางครั้งใช้งานไม่ได้ ฉันใช้ ViewPager กับ FragmentPagerAdapter และ Fragment หลายรายการ หลังจากตั้งค่า OnTouchListener เป็นเพจเจอร์แล้วถ้าฉันพุ่งไปทางซ้าย UI จะยังคงขยับไปทางซ้ายเล็กน้อย
Chris.Zou

16
มันทำงานได้เมื่อคุณเพิ่มก่อนที่จะกลับpager.setCurrentItem(pager.getCurrentItem()); true
dng

1
มันทำงานให้ฉันก่อน ไม่รู้เลยว่าทำไมมันไม่ได้ผลดีอีกต่อไป
นักพัฒนา android

ดูเหมือนว่าจะทำงานให้ฉัน เพื่อแก้ปัญหาเลย์เอาต์บางอย่างที่ฉันมีpublic int getItemPosition(Object object) { return POSITION_NONE; }ในอะแดปเตอร์ของฉันซึ่งบังคับให้มีการสันทนาการของหน้าและอาจแก้ไขปัญหาอื่น ๆ ด้วย
ถือ

6
นี่เป็นวิธีแก้ปัญหาการทำงานบางส่วน swipes แนวนอนได้รับการจัดการด้วยวิธีแปลก ๆ ฉันทดสอบสิ่งนี้ด้วย Drag'n Drop Gridview ซึ่งเป็นส่วนหนึ่งของ ViewPager เมื่อลากโดยใช้โซลูชันนี้การลากจากซ้ายไปขวาและขวาไปซ้ายล้มเหลว ส่วนตัวแล้วฉันพบว่าวิธีการของ Rajul นั้นดีที่สุด
Ton Snoei

58

ดีกว่าที่จะประกาศให้มีสไตล์ดังนั้นคุณสามารถเปลี่ยนคุณสมบัติได้จาก xml:

private boolean swipeable;

public MyViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyViewPager);
    try {
        swipeable = a.getBoolean(R.styleable.MyViewPager_swipeable, true);
    } finally {
        a.recycle();
    }
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return swipeable ? super.onInterceptTouchEvent(event) : false;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return swipeable ? super.onTouchEvent(event) : false;
}

และในค่า / attr.xml ของคุณ:

<declare-styleable name="MyViewPager">
  <attr name="swipeable" format="boolean" />
</declare-styleable>

เพื่อให้คุณสามารถใช้ในเลย์เอาต์ xml ของคุณ:

<mypackage.MyViewPager
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/viewPager"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:swipeable="false" />

แน่นอนคุณยังสามารถรับทรัพย์สิน / ชุด


58

การเอาชนะเท่านั้นonTouchEventและonInterceptTouchEventไม่เพียงพอในกรณีที่คุณมี ViewPager ภายใน ViewPager อื่น Child ViewPager จะขโมยเหตุการณ์ Touch Touch ในแนวนอนจาก parent ViewPager เว้นแต่ว่าจะอยู่ในตำแหน่งบนหน้าแรก / หน้าสุดท้าย

ในการทำให้การตั้งค่านี้ทำงานอย่างถูกต้องคุณจะต้องแทนที่canScrollHorizontallyวิธีการด้วย

ดูLockableViewPagerการใช้งานด้านล่าง

public class LockableViewPager extends ViewPager {

    private boolean swipeLocked;

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

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

    public boolean getSwipeLocked() {
        return swipeLocked;
    }

    public void setSwipeLocked(boolean swipeLocked) {
        this.swipeLocked = swipeLocked;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return !swipeLocked && super.onTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return !swipeLocked && super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean canScrollHorizontally(int direction) {
        return !swipeLocked && super.canScrollHorizontally(direction);
    }

}

3
ขอบคุณนี้ใช้ได้ดีกับ ViewPager ภายใน ViewPager อื่น
Fernanda Bari

1
สิ่งนี้ใช้งานได้สำหรับฉันและสำหรับ ViewPager ใน ViewPager อื่น ทางออกที่ถูกต้องไม่ได้ผลสำหรับฉันในกรณีนั้น
Rafael Ruiz Muñoz

หยุดเคลื่อนไหวด้วยเมื่อใช้ในแท็บ
Rishabh Srivastava

ถ้าฉันปิดการใช้งานและสมมติว่าฉันต้องการเปิดใช้งานแล้วฉันจะได้รับเหตุการณ์ที่จะเรียก setSwipeLocked (false) ได้ที่ไหน
Ravi Yadav

57

ตอนนี้เราไม่จำเป็นต้องสร้างที่กำหนดเอง ViewPager

ViewPager2 ชื่อใหม่ดูพร้อมใช้งานใน android

รองรับการวางแนวตั้ง

  • ViewPager2รองรับการแบ่งหน้าแนวตั้งนอกเหนือจากการเลื่อนหน้าในแนวนอน คุณสามารถเปิดใช้เพจจิ้งแนวตั้งสำหรับViewPager2องค์ประกอบโดยการตั้งค่าandroid:orientationคุณลักษณะ

ใช้ XML

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:orientation="vertical" />

ใช้รหัส

เพื่อปิดการใช้งานการรูดในการviewpager2ใช้งาน

viewPager2.setUserInputEnabled(false);

เพื่อเปิดใช้งานการรูดในการviewpager2ใช้งาน

viewPager2.setUserInputEnabled(true);

สำหรับข้อมูลเพิ่มเติมตรวจสอบสิ่งนี้

UPDATE


3
มันยอดเยี่ยม แต่ก็ยังดูไม่สมบูรณ์ ฉันได้ลองใช้กับ 5 ชิ้นที่แตกต่างกันและหลังจากสลับไปมาระหว่างหน้าหนึ่งของชิ้นส่วนที่หายไปคือมุมมองไม่ได้ถูกเรียกคืนหรือไม่พองใหม่
Toochka

@Toochka ขอโทษที่ได้ยินว่าสำหรับฉันมันทำงานได้ดีคุณสามารถค้นหาตัวอย่างรหัสการทำงานจากที่นี่stackoverflow.com/a/54643817/7666442ถ้าเป็นไปได้โปรดแบ่งปันรหัสของคุณ
Nilesh Rathod

1
ฉันสามารถปิดการใช้งานการรูดบน ViewPager2 ได้สำเร็จโดยใช้วิธีนี้
voghDev

1
@voghDev ยินดีที่ได้ยินเช่นนั้น
Nilesh Rathod

1
@PhaniRithvij โปรดตรวจสอบคำตอบนี้stackoverflow.com/a/54643817/7666442ฉันได้เพิ่มรายละเอียดทั้งหมดวิธีการใช้viewpager2กับRecyclerView.Adapter
Nilesh Rathod

35

หากคุณกำลังขยายจาก ViewPager คุณต้องแทนที่executeKeyEventตามที่ระบุไว้ก่อนหน้าโดย @araks

@Override
public boolean executeKeyEvent(KeyEvent event)
{
    return isPagingEnabled ? super.executeKeyEvent(event) : false;
}

เนื่องจากอุปกรณ์บางอย่างเช่น Galaxy Tab 4 10 'แสดงปุ่มเหล่านี้ที่อุปกรณ์ส่วนใหญ่ไม่แสดง:

ปุ่มบนคีย์บอร์ด


50
ซัมซุงมักจะทำสิ่งต่าง ๆ ขึ้นสำหรับผู้พัฒนา Android
toobsco42

2
@ toobsco42 Samsung ไม่ได้อยู่คนเดียวในกรณีนี้ SwiftKey (แอพแป้นพิมพ์ยอดนิยม) ช่วยให้ผู้ใช้สามารถวางลูกศรบนคีย์บอร์ดของพวกเขา
Sufian

1
นี่คือการแก้ไขหากคุณต้องการหยุดบางคนที่ใช้แป้นพิมพ์ / ตัวติดตามติดตามเพจเจอร์ของคุณ
se22as

28

หากต้องการปิดใช้งานการปัด

mViewPager.beginFakeDrag();

เพื่อเปิดใช้งานการปัด

mViewPager.endFakeDrag();

22
มันไม่ใช่ทางออกที่ดีเพราะมันช่วยให้มีการเคลื่อนไหวบางส่วนอย่างน้อยในแอพของฉัน
koras

ทำงานได้ดีสำหรับฉัน อะไรคือข้อเสียเมื่อเปรียบเทียบกับโซลูชันอื่น ๆ ที่ให้ไว้?
userM1433372

13

ฉันต้องการปิดการรูดในหน้าใดหน้าหนึ่งและให้ภาพเคลื่อนไหวยางรัดที่ดีนี่คือวิธี:

    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            if (position == MANDATORY_PAGE_LOCATION && positionOffset > 0.5) {
                mViewPager.setCurrentItem(MANDATORY_PAGE_LOCATION, true);
            }
        }

มันรอจนกว่าหน้าถัดไปจะปรากฏเป็นส่วนหนึ่ง รหัสสำหรับหน้าถัดไปonPageSelectedจะถูกดำเนินการ แม้แต่หน้าถัดไปก็จะเปลี่ยน ดังนั้นรหัสนี้ไม่จำเป็นต้องทำ
CoolMind

13

ฉันรู้ว่ามันยิ่งใหญ่ในการโพสต์สิ่งนี้ แต่นี่เป็นแฮ็คเล็ก ๆ เพื่อให้ได้ผลลัพธ์ของคุณ;)

เพียงเพิ่มมุมมองแบบจำลองใต้มุมมองของคุณ:

<android.support.v4.view.ViewPager
     android:layout_width="match_parent"
     android:layout_height="match_parent">
</android.support.v4.view.ViewPager>

<RelativeLayout
     android:id="@+id/dummyView"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
</RelativeLayout>

แล้วเพิ่มที่คุณOnClickListenerRelativeLayout

dummyView = (RelativeLayout) findViewById(R.id.dummyView);

dummyView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
         //Just leave this empty
    }
});

ใช้ความคิดสร้างสรรค์เล็กน้อยกับเลย์เอาต์ตำแหน่งของพวกเขาและพฤติกรรมของพวกเขาและคุณจะได้เรียนรู้ที่จะหาวิธีที่จะทำทุกอย่างที่คุณจินตนาการ :)

โชคดี!


วิธีที่ง่ายกว่าคือใช้setClickableแทนsetOnClickListenerหากคุณไม่ต้องการจัดการonClickเหตุการณ์
ความโกลาหล

สิ่งนี้จะไม่ปิดกั้นการสัมผัสภายในวิวเวอร์หรือไม่
นักพัฒนา android

ใช่! ฉันจะ. เป็นพฤติกรรมที่คาดหวังตามที่ OP @
androiddeveloper

@RickGrimesTheCoder ฉันไม่คิดว่าคุณเข้าใจคำถามของฉัน ฉันหมายถึงจำนวนการดูภายในแฟรกเมนต์ของผู้ชม พวกเขาจะยังคงสามารถสัมผัสได้หรือไม่
นักพัฒนา android

ไม่พวกเขาจะไม่เป็นเช่นนั้นเนื่องจากตัวรับชมมีตัวฟังการคลิก สิ่งนี้เหมาะสำหรับอินสแตนซ์ที่คุณไม่มีองค์ประกอบแบบโต้ตอบภายในแฟรกเมนต์เท่านั้น ตัวอย่างเช่น Welcome ViewPager ที่เปลี่ยน
แฟรกเมนต์

12

ฉันเขียนCustomViewPagerด้วยการควบคุมการปัด:

public class ScrollableViewPager extends ViewPager {
    private boolean canScroll = true;
    public ScrollableViewPager(Context context) {
        super(context);
    }
    public ScrollableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public void setCanScroll(boolean canScroll) {
        this.canScroll = canScroll;
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return canScroll && super.onTouchEvent(ev);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return canScroll && super.onInterceptTouchEvent(ev);
    }
}

ถ้าคุณตั้งค่าcanScrollการtrueนี้ViewPagerสามารถรูดนิ้วfalseในทางตรงกันข้าม

ฉันใช้สิ่งนี้ในโครงการของฉันและมันใช้งานได้ดีจนถึงตอนนี้


1
จะทำอย่างไรถ้าฉันมีปุ่มภายใน ViewPager และฉันต้องการให้คลิก วิธีนี้จะหยุดทุกอย่างที่อยู่ด้านล่างเพื่อให้มีการคลิกเพื่อดู ..
aimiliano

6

ฉันใช้คลาสนี้ด้วยความสำเร็จ การเอาชนะexecuteKeyEventจำเป็นต้องมีเพื่อหลีกเลี่ยงการปัดโดยใช้ลูกศรในอุปกรณ์บางตัวหรือเพื่อการเข้าถึง:

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

public class ViewPagerNoSwipe extends ViewPager {
    /**
     * Is swipe enabled
     */
    private boolean enabled;

    public ViewPagerNoSwipe(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = false; // By default swiping is disabled
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return this.enabled ? super.onTouchEvent(event) : false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return this.enabled ? super.onInterceptTouchEvent(event) : false;
    }

    @Override
    public boolean executeKeyEvent(KeyEvent event) {
        return this.enabled ? super.executeKeyEvent(event) : false;
    }

    public void setSwipeEnabled(boolean enabled) {
        this.enabled = enabled;
    }

}

และในxmlเรียกว่าดังนี้:

<package.path.ViewPagerNoSwipe
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

มันได้ผล. รูดเพียงปิดใช้งานและคลิกที่แท็บเปิดใช้งาน ตามที่เตือนperformClick()วิธีการที่ไม่ได้อยู่เหนือ
CoolMind

5

ใน Kotlin ทางออกของฉันรวมคำตอบข้างต้น

class CustomViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
    var swipeEnabled = false

    override fun onTouchEvent(ev: MotionEvent?): Boolean {
        return if (swipeEnabled) super.onTouchEvent(ev) else false
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        return if (swipeEnabled) super.onInterceptTouchEvent(ev) else false
    }

    override fun executeKeyEvent(event: KeyEvent): Boolean {
        return if (swipeEnabled) super.executeKeyEvent(event) else false
    }
}

การแทนที่จะonInterceptTouchEvent()ป้องกันมุมมองของเด็กเพื่อรับอินพุต ในกรณีส่วนใหญ่นี่ไม่ใช่พฤติกรรมที่ตั้งใจ
Alex Semeniuk

ฉันสามารถโต้ตอบกับมุมมองเด็กของแต่ละส่วนได้ ไม่แน่ใจว่าคุณหมายถึงอะไร
Jeff Padgett

5

ใน kotlin เราสามารถแก้ปัญหานี้ได้โดยการสร้างวิดเจ็ตที่กำหนดเองที่สืบทอดคลาส ViewPager และเพิ่มค่าสถานะสำหรับการควบคุมพฤติกรรมการปัดนิ้ว

NoSwipePager.kt

class NoSwipePager(context: Context, attrs: AttributeSet) : ViewPager(context, attrs) {

    var pagingEnabled: Boolean = false

    override fun onTouchEvent(event: MotionEvent): Boolean {
        return if (this.pagingEnabled) {
            super.onTouchEvent(event)
        } else false
    }

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        return if (this.pagingEnabled) {
            super.onInterceptTouchEvent(event)
        } else false
    }
}

ใน xml

<your.package.NoSwipePager
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/tab_layout" />

ปิดใช้งานการปัดโดยโปรแกรม หากkotlin-android-extensionsมีการใช้ปลั๊กอินในbuild.gradle การปัดสามารถปิดได้โดยการเขียนโค้ดด้านล่าง

view_pager.pagingEnabled = false

มิฉะนั้นเราสามารถปิดการใช้งานการรูดโดยใช้รหัสด้านล่าง:

val viewPager : ViewPager = findViewById(R.id.view_pager)
viewPager.pagingEnabled = false

การแทนที่จะonInterceptTouchEvent()ป้องกันมุมมองของเด็กเพื่อรับอินพุต ในกรณีส่วนใหญ่นี่ไม่ใช่พฤติกรรมที่ตั้งใจ
Alex Semeniuk

@AlexSemeniuk คุณสังเกตเห็นปัญหาใด ๆ หลังจากใช้งานหรือไม่ ฉันเปิดใช้งานการปัดรายการมุมมองรีไซเคิลเพื่อการดำเนินการบางอย่างและทำงานได้ดี ดังนั้นการติดตั้งใช้งานได้ดีในกรณีของฉัน
Sagar Chapagain

Sagar Chapagain: หรือแน่นอนฉันทำ หน้าเว็บของฉันแต่ละหน้ามีมุมมองที่กำหนดเองซึ่งกระบวนการจะสัมผัสในรูปแบบต่างๆ (รวมถึงการเลื่อน, การลาก, การแตะครั้งเดียวและการแตะยาว) ไม่เรียกsuper.onInterceptTouchEvent(event)ผลลัพธ์ในมุมมองเหล่านี้ไม่ได้รับการป้อนข้อมูลใด ๆ (ซึ่งเป็นวัตถุประสงค์ของonInterceptTouchEventวิธีการบันทึกไว้)
Alex Semeniuk

หากเป็นกรณีนี้คุณควรใช้ชิ้นส่วนย่อยของเด็กและเก็บไว้ข้างหลัง
Sagar Chapagain

สิ่งนี้เกี่ยวข้องกับคำถามปัจจุบันอย่างไร ชิ้นส่วนจะถูกวางไว้ภายในภาชนะบรรจุบางส่วน (ซึ่งเป็นผู้ชม ) และรูปแบบของตัวเองที่มีการเข้าชม ไม่ว่าฉันจะมีเนื้อหาใดใน ViewPager ฉันยังคงต้องเผชิญกับความจริงที่ว่าonInterceptTouchEvent()วิธีการแทนที่นั้นทำให้ไม่สามารถรับเนื้อหาได้
Alex Semeniuk

4

ลองลบล้างและคืนค่าจริงจากonInterceptTouchEvent ()และ / หรือonTouchEvent ()ซึ่งจะใช้เหตุการณ์การสัมผัสบนเพจเจอร์


1
เขาไม่ต้องการกลับtrueไปบอกเป็นนัยถึงเหตุการณ์การสัมผัสที่ได้รับการจัดการ
edthethird

1

อีกวิธีที่ง่ายในการปิดการรูดในหน้าใดหน้าหนึ่ง (ในตัวอย่างนี้หน้า 2):

int PAGE = 2;
viewPager.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
        if (viewPager.getCurrentItem() == PAGE) {
                viewPager.setCurrentItem(PAGE-1, false);
                viewPager.setCurrentItem(PAGE, false);
                return  true;
        }
        return false;
}

1
This worked for me

viewPager.setOnTouchListener(new View.OnTouchListener() {
                                         @Override
                                         public boolean onTouch(View v, MotionEvent event) {
                                             if (viewPager.getCurrentItem() == 0) {
                                                 viewPager.setCurrentItem(-1, false);
                                                 return true;
                                             }
                                             else if (viewPager.getCurrentItem() == 1) {
                                                 viewPager.setCurrentItem(1, false);
                                                 return true;
                                             }
                                             else if (viewPager.getCurrentItem() == 2) {
                                                 viewPager.setCurrentItem(2, false);
                                                 return true;
                                             }
                                             return true;
                                         }
                                     });

1

หากคุณเขียนแกลเลอรี่ภาพด้วยImageViews และViewPagerที่รองรับการซูมและแพนดูวิธีแก้ปัญหาง่ายๆที่อธิบายไว้ที่นี่: การใช้ ImageView ที่ซูมได้โดยการขยาย Default ViewPager ใน Phimpme Android (และตัวอย่าง Github - PhotoView ) วิธีนี้ไม่ได้ผลViewPagerเพียงอย่างเดียว

public class CustomViewPager extends ViewPager {
    public CustomViewPager(Context context) {
        super(context);
    }

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        try {
            return super.onInterceptTouchEvent(event);
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
}

0

ถ้าคุณต้องการที่จะใช้สิ่งเดียวกันสำหรับ Android ใน Xamarin นี่คือการแปลเป็น C #

ฉันเลือกที่จะตั้งชื่อแอตทริบิวต์ " ScrollEnabled " เพราะ iOS ใช้การตั้งชื่อแบบเดียวกันกับชื่อ excat ดังนั้นคุณมีการตั้งชื่อที่เท่าเทียมกันในทั้งสองแพลตฟอร์มทำให้ง่ายขึ้นสำหรับนักพัฒนา

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Android.Util;

namespace YourNameSpace.ViewPackage {

    // Need to disable swiping for ViewPager, if user performs Pre DSA and the dsa is not completed yet
    // http://stackoverflow.com/questions/9650265/how-do-disable-paging-by-swiping-with-finger-in-viewpager-but-still-be-able-to-s
    public class CustomViewPager: ViewPager {
        public bool ScrollEnabled;

        public CustomViewPager(Context context, IAttributeSet attrs) : base(context, attrs) {
            this.ScrollEnabled = true;
        }

        public override bool OnTouchEvent(MotionEvent e) {
            if (this.ScrollEnabled) {
                return base.OnTouchEvent(e);
            }
            return false;
        }

        public override bool OnInterceptTouchEvent(MotionEvent e) {
            if (this.ScrollEnabled) {
                return base.OnInterceptTouchEvent(e);
            }
            return false;
        }

        // For ViewPager inside another ViewPager
        public override bool CanScrollHorizontally(int direction) {
            return this.ScrollEnabled && base.CanScrollHorizontally(direction);
        }

        // Some devices like the Galaxy Tab 4 10' show swipe buttons where most devices never show them
        // So, you could still swipe through the ViewPager with your keyboard keys
        public override bool ExecuteKeyEvent(KeyEvent evt) {
            return this.ScrollEnabled ? base.ExecuteKeyEvent(evt) : false;
        }
    }
}

ในไฟล์ .axml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
  <YourNameSpace.ViewPackage.CustomViewPager
      android:id="@+id/pager"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@android:color/white"
      android:layout_alignParentTop="true" />
</LinearLayout>

0

ไม่มีรหัสข้างต้นทำงานได้อย่างราบรื่นฉันลองสิ่งนี้

<HorizontalScrollView
                    android:id="@+id/horizontalScrollView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fillViewport="true">

                    <android.support.v4.view.ViewPager
                        android:id="@+id/pager"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent" />
                </HorizontalScrollView>

0

นี่คือการใช้งานของฉัน
ว่าหากคุณต้องการปิดการใช้งานภาพเคลื่อนไหวแบบรูดคุณสามารถใช้ swipeListener ทางซ้ายและขวาและยังต้องการเลื่อนแบบทีละนิ้ว แต่ไม่มีภาพเคลื่อนไหว

1 แทนที่ViewpagerวิธีการonInterceptTouchEventและonTouchEvent

2- สร้างของคุณเอง GestureDetector

3- ตรวจจับการปัดนิ้วและใช้ setCurrentItem(item, false)

ViewPager

public class ViewPagerNoSwipe extends ViewPager {
    private final GestureDetector gestureDetector;
    private OnSwipeListener mOnSwipeListener;

    public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
        mOnSwipeListener = onSwipeListener;
    }

    public ViewPagerNoSwipe(@NonNull Context context) {
        super(context);
        gestureDetector = new GestureDetector(context, new GestureListener());

    }

    public ViewPagerNoSwipe(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        gestureDetector = new GestureDetector(context, new GestureListener());


    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        gestureDetector.onTouchEvent(ev);
        return false;
    }

    public class GestureListener extends GestureDetector.SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeRight();
                        } else {
                            if(mOnSwipeListener!=null)
                                mOnSwipeListener.onSwipeLeft();
                        }
                        result = true;
                    }
                } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeBottom();
                    } else {
                        if(mOnSwipeListener!=null)
                            mOnSwipeListener.onSwipeTop();
                    }
                    result = true;
                }
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }

    public interface OnSwipeListener {

         void onSwipeRight();

        void onSwipeLeft();

        void onSwipeTop();

        void onSwipeBottom();
    }
}

เมื่อคุณตั้งค่า ViewPager ตั้งค่า swipeListener

postsPager.setOnSwipeListener(new ViewPagerNoSwipe.OnSwipeListener() {
            @Override
            public void onSwipeRight() {

              postsPager.setCurrentItem(postsPager.getCurrentItem() + 1,false);

            }

            @Override
            public void onSwipeLeft() {

            postsPager.setCurrentItem(postsPager.getCurrentItem() - 1, false);

            }
             ...
           }

0

ฉันเพิ่งปรับแต่ง viewpager เล็กน้อยและปิดการรูดได้อย่างง่ายดาย

public class CustomViewPager extends ViewPager {

private boolean swipeLocked;

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

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

public boolean getSwipeLocked() {
    return swipeLocked;
}

public void setSwipeLocked(boolean swipeLocked) {
    this.swipeLocked = swipeLocked;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    return !swipeLocked && super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    return !swipeLocked && super.onInterceptTouchEvent(event);
}

@Override
public boolean canScrollHorizontally(int direction) {
    return !swipeLocked && super.canScrollHorizontally(direction);
}
}

0

หากคุณใช้ ViewPager2 คุณต้องใช้:

viewpager.setUserInputEnabled(false);

จากเอกสาร :

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

ขอบคุณที่: https://stackoverflow.com/a/61685871/9026710


-1
shareViewPager?.setOnTouchListener(object :View.OnTouchListener{
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                for (PAGE in 0..shareViewPager.adapter!!.count){
                    if (shareViewPager.currentItem==PAGE){
                        shareViewPager.setCurrentItem(PAGE-1,false)
                        shareViewPager.setCurrentItem(PAGE,false)
                    }}
                return true
            }

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