Làm cách nào để vô hiệu hóa phân trang bằng cách vuốt bằng ngón tay trong ViewPager nhưng vẫn có thể vuốt theo chương trình?


550

Tôi có ViewPager và bên dưới nó tôi có 10 nút. Bằng cách nhấp vào nút, ví dụ # 4, máy nhắn tin sẽ chuyển ngay đến trang số 4 bằng cách mPager.setCurrentItem(3);. Nhưng, tôi muốn vô hiệu hóa phân trang bằng cách vuốt bằng ngón tay theo chiều ngang. Do đó, việc phân trang được thực hiện CHỈ bằng cách nhấp vào các nút. Vì vậy, làm thế nào tôi có thể vô hiệu hóa việc vuốt bằng ngón tay?


Làm thế nào về việc sử dụng ViewFlipper ở nơi đầu tiên? Nó sẽ giúp bạn tiết kiệm rất nhiều đau đầu.
Alex Semeniuk 17/07/19

Câu trả lời:


885

Bạn cần phải phân lớp ViewPager. onTouchEventcó rất nhiều điều hay trong đó mà bạn không muốn thay đổi như cho phép quan điểm của trẻ em được chạm vào. onInterceptTouchEventlà những gì bạn muốn thay đổi. Nếu bạn nhìn vào mã cho ViewPager, bạn sẽ thấy nhận xét:

    /*
     * 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.
     */

Đây là một giải pháp hoàn chỉnh:

Đầu tiên, thêm lớp này vào srcthư mục của bạn :

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

Tiếp theo, hãy đảm bảo sử dụng lớp này thay vì thông thường ViewPager, mà bạn có thể đã chỉ định là android.support.v4.view.ViewPager. Trong tệp bố cục của bạn, bạn sẽ muốn chỉ định nó với một cái gì đó như:

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

Ví dụ cụ thể này là trong một LinearLayoutvà có nghĩa là chiếm toàn bộ màn hình, đó là lý do tại sao layout_weightlà 1 và layout_heightlà 0dp.

setMyScroller();phương pháp là để chuyển tiếp suôn sẻ


3
@louielouie Trên một lưu ý phụ: có lý do cụ thể nào không, tại sao bạn chọn giải pháp 0dpchiều cao / 1cân nặng so với match_parentchiều cao để đạt được hiệu ứng toàn màn hình? Bạn có đạt được cải tiến hiệu suất bằng cách làm như vậy?
ubuntudroid

29
Câu trả lời này không ngăn việc vuốt trang khi sử dụng bàn phím phím trái / phải (thử trong trình giả lập). Có thể không phải là vấn đề đối với các thiết bị cảm ứng nhưng với TV và máy tính xách tay thì đó có thể là một vấn đề.
Vincent Mimoun-Prat

8
@MarvinLabs @Thorbear Cách chính xác để vô hiệu hóa cuộn trang bằng bàn phím là ghi đè lên executeKeyEvent(). Đây là phương pháp mà sau đó gọi allowScroll(). // Never allow swiping by keyboard LEFT, RIGHT, TAB and SHIFT+TAB keys @Override public boolean executeKeyEvent(KeyEvent event) { return false; }
araks

6
tốt, điều này cũng vô hiệu hóa cuộn dọc ... điều này thật tệ, nếu bạn đang sử dụng danh sách xem.
maysi

5
Tôi hy vọng google có thể vừa cung cấp một phương thức mà chúng tôi cung cấp phương thức giao diện của chúng tôi về cách xử lý chạm / vuốt vì tôi tin rằng nó sẽ không bị tổn thương?
Chiến tranh neon 14/11/2015

466

Phần mở rộng chung hơn ViewPagersẽ là tạo một SetPagingEnabledphương thức để chúng ta có thể kích hoạt và vô hiệu hóa phân trang khi đang bay. Để bật / tắt thao tác vuốt, chỉ cần ghi đè hai phương thức: onTouchEventonInterceptTouchEvent. Cả hai sẽ trả về "false" nếu phân trang bị vô hiệu hóa.

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

Sau đó chọn mục này thay vì trình xem được tích hợp sẵn trong XML

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

Bạn chỉ cần gọi setPagingEnabledphương thức với falsevà người dùng sẽ không thể vuốt để phân trang.


3
Hoạt động hoàn hảo cho chế độ xem có nhiều lượt xem trong đó một chế độ sử dụng cuộn ngang (ví dụ: biểu đồ AChartEngine). Trong đoạn của tôi, tôi sử dụng một cuộc gọi lại cho hoạt động của mình để bảo nó tắt hoặc tắt phân trang tùy thuộc vào việc người dùng có chạm vào (ACTION_MOVE) biểu đồ hay để lại nó (ACTION_CANCEL). Cảm ơn rất nhiều!
riper

32
Bạn có thể đơn giản hóa onTouchEventonInterceptTouchEventphương thức của mình vớireturn enabled && super.onTouchEvent(event);
nbarraille

2
@nbarraille đó chỉ là vấn đề về phong cách. Bạn có thể sử dụng bất cứ phong cách nào có vẻ dễ đọc hơn đối với bạn.
Rajul

7
Tôi cũng sẽ khuyên bạn nên thay đổi tên của trường từ "đã bật" thành "swipePageChangeEnables" hoặc đại loại như thế. Một tháng sau khi viết mã, bạn sẽ khó nhớ "bật" nghĩa là gì, đặc biệt là khi lớp của bạn được gọi là "CustomViewPager", trong đó không rõ tùy chỉnh là gì. Đó cũng là một vấn đề về phong cách, nhưng phong cách là vấn đề nếu bạn không muốn kết thúc với dự án không được hỗ trợ, việc viết lại hoàn toàn dễ dàng hơn là sửa nó.
bytefu

4
Tôi gọi setPagingEnables ở đâu? ._.
Ntikki

107

Cách đơn giản nhất là setOnTouchListenervà trả lại truecho ViewPager.

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

53
Đôi khi không hoạt động. Tôi đang sử dụng ViewPager với FragmentPagerAd CHƯƠNG và một vài Fragment. Sau khi đặt OnTouchListener thành máy nhắn tin, nếu tôi bỏ sang trái, giao diện người dùng vẫn sẽ di chuyển sang trái một chút.
Chris.Zou

16
Nó hoạt động khi bạn thêm pager.setCurrentItem(pager.getCurrentItem());trước khi trở về true.
dng

1
nó làm việc cho tôi trước đây. không biết tại sao nó không hoạt động tốt nữa.
nhà phát triển Android

Dường như làm việc cho tôi. Để giải quyết một số trục trặc về bố cục, tôi có public int getItemPosition(Object object) { return POSITION_NONE; }trong bộ điều hợp, điều này buộc phải giải trí các trang và có thể giải quyết các vấn đề khác.
r-giữ

6
Đây là một giải pháp làm việc THAM GIA. Vuốt ngang được xử lý theo một cách kỳ lạ. Tôi đã thử nghiệm điều này với Grid'n Drop Gridview như một phần của ViewPager. Khi kéo bằng giải pháp này, kéo từ trái sang phải và phải sang trái không thành công. Cá nhân tôi thấy cách tiếp cận của Rajul là tốt nhất.
Ton Snoei

58

Tốt hơn là khai báo nó có thể tạo kiểu, vì vậy bạn có thể thay đổi thuộc tính của nó từ 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;
}

Và trong các giá trị / attr.xml của bạn:

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

để bạn có thể sử dụng nó trong bố cục 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" />

Tất nhiên, bạn vẫn có thể có một thuộc tính get / set.


58

Chỉ ghi đè onTouchEventonInterceptTouchEvent không đủ trong trường hợp bạn có chính ViewPager bên trong một ViewPager khác. ViewPager con sẽ đánh cắp các sự kiện chạm cuộn ngang từ cha mẹ ViewPager trừ khi nó được định vị trên trang đầu tiên / cuối cùng của nó.

Để thiết lập này hoạt động chính xác, bạn cần ghi đè lên canScrollHorizontallyphương thức.

Xem LockableViewPagerthực hiện dưới đây.

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
Cảm ơn bạn, điều này hoạt động rất tốt trên ViewPager bên trong một ViewPager khác.
Fernanda Bari

1
Điều này hoạt động với tôi, cũng cho một ViewPager bên trong một ViewPager khác. Giải pháp chính xác đã không làm việc cho tôi trong trường hợp đó.
Rafael Ruiz Muñoz

dừng hoạt hình quá khi được sử dụng trong các tab.
Rishabh Srivastava

Nếu tôi vô hiệu hóa nó và giả sử tôi muốn kích hoạt nó thì tôi có thể lấy sự kiện ở đâu để gọi setSwipeLocked (false)?
Ravi Yadav

57

Bây giờ chúng tôi không cần phải tạo tùy chỉnh ViewPager

Một ViewPager2 tên mới Xem có sẵn trong Android

Hỗ trợ định hướng dọc

  • ViewPager2hỗ trợ phân trang dọc ngoài phân trang ngang truyền thống. Bạn có thể bật phân trang dọc cho một ViewPager2phần tử bằng cách đặt android:orientationthuộc tính của nó

Sử dụng XML

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

Sử dụng mã

Để swiping vô hiệu hóa trong viewpager2sử dụng

viewPager2.setUserInputEnabled(false);

Để cho phép vuốt trong viewpager2Sử dụng

viewPager2.setUserInputEnabled(true);

để biết thêm thông tin kiểm tra này

CẬP NHẬT


3
Thật tuyệt, nhưng trông vẫn chưa hoàn thiện. Tôi đã thử nó ra với 5 mảnh vỡ khác nhau và sau khi chuyển đổi giữa các trang một trong những mảnh vỡ là loại mất, xem tức là đã không không phục hồi hay tái thổi phồng
Toochka

@Toochka rất tiếc khi biết rằng với tôi nó hoạt động tốt, bạn có thể tìm mã làm việc mẫu từ đây stackoverflow.com/a/54643817/7666442 nếu có thể xin vui lòng chia sẻ mã của bạn
Nilesh Rathod

1
Tôi có thể vô hiệu hóa thành công việc vuốt trên ViewPager2 bằng phương pháp này
voghDev 16/12/19

1
@voghDev rất vui khi biết điều đó
Nilesh Rathod

1
@PhaniRithvij vui lòng kiểm tra câu trả lời này stackoverflow.com/a/54643817/7666442 tôi đã thêm tất cả các chi tiết về cách sử dụng viewpager2vớiRecyclerView.Adapter
Nilesh Rathod

35

Nếu bạn đang mở rộng từ ViewPager, bạn cũng phải ghi đèexecuteKeyEvent như được chỉ định trước đây bởi @araks

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

Bởi vì một số thiết bị như Galaxy Tab 4 10 'hiển thị các nút này trong đó hầu hết các thiết bị không bao giờ hiển thị chúng:

Nút bàn phím


50
Samsung luôn làm hỏng mọi thứ cho các nhà phát triển Android.
toobsco42

2
@ toobsco42 Samsung không đơn độc trong trường hợp này. SwiftKey (ứng dụng bàn phím phổ biến) cho phép người dùng đặt mũi tên trên bàn phím của họ.
Sufian

1
Đây cũng là cách khắc phục nếu bạn muốn ngăn ai đó sử dụng bàn phím / bi xoay để phân trang máy nhắn tin của bạn.
se22as

28

Để tắt tính năng vuốt

mViewPager.beginFakeDrag();

Để bật vuốt

mViewPager.endFakeDrag();

22
Đây không phải là một giải pháp tốt vì nó cho phép các phần chuyển động nhỏ, ít nhất là trong ứng dụng của tôi.
koras

Hoạt động tốt cho tôi. Những bất lợi so với các giải pháp khác được cung cấp là gì?
userM1433372

13

Tôi cần phải vô hiệu hóa thao tác vuốt trên một trang cụ thể và cung cấp cho nó một hình ảnh động cao su đẹp mắt, dưới đây là:

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

Nó chờ cho đến khi trang tiếp theo được hiển thị một phần. Một mã cho trang tiếp theo onPageSelectedsẽ được thực thi. Ngay cả trang tiếp theo cũng sẽ chuyển. Vì vậy, mã này không cần thiết.
CoolMind

13

Tôi biết sẽ rất muộn để đăng bài này nhưng đây là một bản hack nhỏ để đạt được kết quả của bạn;)

Chỉ cần thêm chế độ xem giả bên dưới chế độ xem của bạn:

<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>

Sau đó thêm một OnClickListenervào của bạn RelativeLayout.

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

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

Hãy sáng tạo một chút với bố cục, vị trí và hành vi của họ và bạn sẽ học cách tìm ra cách hoàn toàn làm bất cứ điều gì bạn tưởng tượng :)

Chúc may mắn!


Một cách dễ dàng hơn là sử dụng setClickablethay vì setOnClickListener, nếu bạn không cần xử lý onClicksự kiện.
Hỗn loạn

Điều này cũng sẽ chặn các liên lạc trong chế độ xem?
nhà phát triển Android

Nó sẽ được thôi. Đó là hành vi dự kiến ​​được yêu cầu bởi OP @androiddeveloper
Dinuka Jay

@RickGrimesTheCoder Tôi không nghĩ bạn hiểu câu hỏi của tôi. Tôi có nghĩa là quan điểm trong các mảnh của người xem. Họ sẽ vẫn có thể chạm vào?
nhà phát triển Android

Không, họ sẽ không vì trình xem chính nó có trình nghe nhấp chuột. Điều này chỉ phù hợp với những trường hợp bạn không có các yếu tố tương tác trong các đoạn. Ví dụ: ViewPager chào mừng thay đổi động các đoạn của nó một cách linh hoạt @androiddeveloper
Dinuka Jay

12

Tôi đã viết một CustomViewPagervới một điều khiển vuốt:

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

Nếu bạn đặt canScrollthành true, điều này ViewPagercó thể được vuốt bằng ngón tay, falsengược lại.

Tôi sử dụng điều này trong dự án của tôi, và nó hoạt động rất tốt cho đến bây giờ.


1
Nếu tôi có một nút bên trong ViewPager và tôi muốn nhấp thì sao? giải pháp này dừng mọi thứ bên dưới viewpager để được nhấp ..
aimiliano

6

Tôi đã sử dụng lớp học này với thành công. Ghi đè execKeyEvent là bắt buộc để tránh vuốt bằng cách sử dụng mũi tên trong một số thiết bị hoặc để truy cập:

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

}

Và trong xml gọi nó như thế này:

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

Nó hoạt động. Chỉ vuốt được tắt và nhấp vào một tab được kích hoạt. AS cảnh báo rằng performClick()phương pháp này không được ghi đè.
CoolMind

5

Trong Kotlin, giải pháp của tôi, kết hợp các câu trả lời ở trên.

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

Ghi đè onInterceptTouchEvent()sẽ ngăn các lượt xem con nhận đầu vào. Trong hầu hết các trường hợp, đây không phải là hành vi dự định.
Alex Semeniuk 17/07/19

Tôi đã có thể tương tác với các quan điểm trẻ em của từng mảnh. Không chắc chắn những gì bạn đang đề cập đến.
Jeff Padgett

5

Trong kotlin, chúng ta có thể giải quyết điều này bằng cách tạo một tiện ích tùy chỉnh kế thừa lớp ViewPager và thêm giá trị cờ để kiểm soát hành vi vuốt.

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

Trong 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" />

Vô hiệu hóa vuốt theo chương trình. Nếu kotlin-android-extensionsplugin được áp dụng trong build.gradle , việc vuốt có thể bị vô hiệu hóa bằng cách viết mã bên dưới.

view_pager.pagingEnabled = false

Nếu không, chúng ta có thể vô hiệu hóa thao tác vuốt bằng mã bên dưới:

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

Ghi đè onInterceptTouchEvent()sẽ ngăn các lượt xem con nhận đầu vào. Trong hầu hết các trường hợp, đây không phải là hành vi dự định.
Alex Semeniuk

@AlexSemeniuk Bạn đã quan sát thấy bất kỳ vấn đề sau khi thực hiện điều này? Tôi đã kích hoạt thao tác vuốt trên các mục xem tái chế cho một số hành động và nó hoạt động tốt. Vì vậy, việc thực hiện là làm việc tốt trong trường hợp của tôi.
Sagar Chapagain 17/07/19

Sagar Chapagain: hoặc tất nhiên, tôi đã làm. Mỗi trang của tôi chứa chế độ xem tùy chỉnh, quá trình này chạm theo nhiều cách khác nhau (bao gồm cuộn, kéo, vòi đơn và vòi dài). Không gọi super.onInterceptTouchEvent(event)kết quả trong các khung nhìn này không nhận được bất kỳ đầu vào nào (đó là mục đích được ghi lại của onInterceptTouchEventphương thức).
Alex Semeniuk

Nếu đó là trường hợp bạn nên sử dụng phân đoạn con và duy trì backstack.
Sagar Chapagain 17/07/19

Làm thế nào điều này có liên quan đến câu hỏi hiện tại? Các mảnh được đặt bên trong một số thùng chứa (là Chế độ xem ) và bố cục riêng của chúng chứa Chế độ xem . Bất kể nội dung nào tôi có trong ViewPager, tôi vẫn đang xử lý thực tế là onInterceptTouchEvent()phương thức ghi đè ngăn không cho nó (nội dung) nhận đầu vào.
Alex Semeniuk 17/07/19


1

Một giải pháp dễ dàng khác để vô hiệu hóa thao tác vuốt tại trang cụ thể (trong ví dụ này, trang 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

Nếu bạn viết một bộ sưu tập hình ảnh với ImageViews và ViewPager, hỗ trợ thu phóng và xoay, hãy xem một giải pháp đơn giản được mô tả ở đây: Triển khai ImageView có thể thu phóng bằng cách mở rộng ViewPager mặc định trong Phimpme Android (và mẫu Github - PhotoView ). Giải pháp này không hoạt động với ViewPagermột mình.

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

1

Nếu bạn đang sử dụng ViewPager2, bạn chỉ cần sử dụng:

viewpager.setUserInputEnabled(false);

Từ các tài liệu :

Kích hoạt hoặc vô hiệu hóa cuộn do người dùng bắt đầu. Điều này bao gồm đầu vào cảm ứng (cử chỉ cuộn và ném) và đầu vào khả năng truy cập. Vô hiệu hóa đầu vào bàn phím chưa được hỗ trợ. Khi cuộn do người dùng khởi tạo bị vô hiệu hóa, cuộn chương trình thông qua setCienItem vẫn hoạt động. Theo mặc định, cuộn do người dùng bắt đầu được bật.

Cảm ơn: https://stackoverflow.com/a/61685871/9026710


0

Nếu bạn muốn triển khai tương tự cho Android trong Xamarin, đây là bản dịch sang C #

Tôi đã chọn đặt tên thuộc tính " ScrollEnables ". Bởi vì iOS chỉ sử dụng cách đặt tên tương tự. Vì vậy, bạn có cách đặt tên bằng nhau trên cả hai nền tảng, giúp nhà phát triển dễ dàng hơn.

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

Trong tệp .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

Không có đoạn mã nào ở trên hoạt động trơn tru. Tôi đã thử điều này

<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

đây là sự thực hiện của tôi
, nếu bạn muốn tắt hoạt hình vuốt, bạn có thể sử dụng swipeListener trái và phải và vẫn muốn cuộn bằng ngón tay nhưng không có hoạt hình

ViewpagerPhương pháp ghi đè 1 onInterceptTouchEventonTouchEvent

2- tạo của riêng bạn GestureDetector

3- phát hiện cử chỉ vuốt và sử dụng 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();
    }
}

khi bạn được thiết lập ViewPager, hãy đặt 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

Tôi chỉ tùy chỉnh chế độ xem một chút và vô hiệu hóa thao tác vuốt dễ dàng.

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

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

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