Làm cách nào để vô hiệu hóa cử chỉ vuốt của UIPageViewControll?


125

Trong trường hợp của tôi, cha mẹ UIViewControllerchứa UIPageViewControllercái UINavigationControllernào chứa UIViewController. Tôi cần thêm một cử chỉ vuốt vào bộ điều khiển xem cuối cùng, nhưng các thao tác vuốt được xử lý như thể chúng thuộc về bộ điều khiển xem trang. Tôi đã cố gắng làm điều này cả lập trình và qua xib nhưng không có kết quả.

Vì vậy, theo tôi hiểu, tôi không thể đạt được mục tiêu của mình cho đến khi UIPageViewControllerxử lý cử chỉ của nó. Làm thế nào để giải quyết vấn đề này?


7
Sử dụngpageViewControllerObject.view.userInteractionEnabled = NO;
Srikanth

6
không chính xác, bởi vì nó chặn tất cả nội dung của nó quá. Nhưng tôi chỉ cần chặn cử chỉ của nó
user2159978

Tại sao anh làm điều này? Những hành vi nào bạn muốn từ ứng dụng? Có vẻ như bạn đang quá phức tạp về kiến ​​trúc. Bạn có thể giải thích những hành vi bạn đang hướng tới.
Fogmeister

Một trong những trang trong UIPageViewControllerUINavigationController. Khách hàng muốn bật bộ điều khiển điều hướng bằng cử chỉ vuốt (nếu có thể), nhưng thay vào đó, bộ điều khiển xem trang xử lý các thao tác vuốt
user2159978

@Srikanth cảm ơn, đó chính xác là những gì tôi cần! Lượt xem trang của tôi bị sập khi tôi kích hoạt thay đổi trang theo chương trình và ai đó đã ngắt nó bằng cách vuốt, vì vậy tôi phải vô hiệu hóa thao tác vuốt tạm thời mỗi khi thay đổi trang được kích hoạt trong mã ...
Kuba Suder

Câu trả lời:


262

Cách tài liệu để ngăn chặn UIPageViewControllercuộn từ là không gán thuộc dataSourcetính. Nếu bạn chỉ định nguồn dữ liệu, nó sẽ chuyển sang chế độ điều hướng 'dựa trên cử chỉ', đó là điều bạn đang cố gắng ngăn chặn.

Nếu không có nguồn dữ liệu, bạn cung cấp thủ công bộ điều khiển xem khi bạn muốn với setViewControllers:direction:animated:completionphương thức và nó sẽ di chuyển giữa các bộ điều khiển xem theo yêu cầu.

Những điều trên có thể được suy ra từ tài liệu của UIPageViewControll của Apple (Tổng quan, đoạn thứ hai):

Để hỗ trợ điều hướng dựa trên cử chỉ, bạn phải cung cấp bộ điều khiển xem của mình bằng cách sử dụng đối tượng nguồn dữ liệu.


1
Tôi thích giải pháp này là tốt. Bạn có thể lưu nguồn dữ liệu cũ trong một biến, đặt nguồn dữ liệu thành 0 và sau đó khôi phục nguồn dữ liệu cũ để bật lại cuộn. Không hoàn toàn sạch sẽ, nhưng tốt hơn nhiều so với việc phân cấp cấu trúc khung nhìn bên dưới để tìm chế độ xem cuộn.
Matt R

3
Vô hiệu hóa nguồn dữ liệu gây ra vấn đề khi làm như vậy để đáp ứng với thông báo bàn phím cho các cuộc phỏng vấn trường văn bản. Lặp lại các lượt xem của chế độ xem để tìm UIScrollView có vẻ đáng tin cậy hơn.
AR Younce

9
Điều này không xóa các chấm ở dưới cùng của màn hình? Và nếu bạn không có thao tác vuốt và không có dấu chấm, thì không có nhiều điểm trong việc sử dụng PageViewControll cả. Tôi đoán người hỏi muốn giữ lại các dấu chấm.
Leo Flaherty

Điều này giúp giải quyết vấn đề tôi gặp phải khi các trang được tải không đồng bộ và người dùng thực hiện thao tác vuốt. Bravo :)
Ja͢ck 11/03/2015

1
A. R Younce đúng. Nếu bạn đang vô hiệu hóa nguồn dữ liệu của PageViewControll để phản hồi thông báo bàn phím (nghĩa là: bạn không muốn người dùng cuộn theo chiều ngang khi bàn phím lên) thì bàn phím của bạn sẽ biến mất ngay lập tức khi bạn rút nguồn dữ liệu của PageViewContoder.
micnguyen

82
for (UIScrollView *view in self.pageViewController.view.subviews) {

    if ([view isKindOfClass:[UIScrollView class]]) {

        view.scrollEnabled = NO;
    }
}

5
Điều này giữ cho điều khiển trang, đó là tốt đẹp.
Marcus Adams

1
Đây là một cách tiếp cận tuyệt vời vì nó giữ cho điều khiển trang (các chấm nhỏ). Bạn sẽ muốn cập nhật chúng khi thực hiện thay đổi trang theo cách thủ công. Tôi đã sử dụng câu trả lời này cho stackoverflow.com/a/28356383/1071899
Simon Bøgh

1
Tại sao khôngfor (UIView *view in self.pageViewController.view.subviews) {
dengApro

Xin lưu ý rằng người dùng vẫn có thể điều hướng giữa các trang bằng cách nhấn vào điều khiển trang ở nửa bên trái và bên phải.
MasterCarl

57

Tôi dịch câu trả lời của user2159978 sang Swift 5.1

func removeSwipeGesture(){
    for view in self.pageViewController!.view.subviews {
        if let subView = view as? UIScrollView {
            subView.isScrollEnabled = false
        }
    }
}

30

Triển khai giải pháp @ lee's (@ user2159978) như một phần mở rộng:

extension UIPageViewController {
    var isPagingEnabled: Bool {
        get {
            var isEnabled: Bool = true
            for view in view.subviews {
                if let subView = view as? UIScrollView {
                    isEnabled = subView.isScrollEnabled
                }
            }
            return isEnabled
        }
        set {
            for view in view.subviews {
                if let subView = view as? UIScrollView {
                    subView.isScrollEnabled = newValue
                }
            }
        }
    }
}

Cách sử dụng: (trong UIPageViewController)

self.isPagingEnabled = false

Để thanh lịch hơn, bạn có thể thêm rằng: var scrollView: UIScrollView? { for view in view.subviews { if let subView = view as? UIScrollView { return subView } } return nil }
Bán hàng Wagner

Getter ở đây chỉ trả về trạng thái kích hoạt của lần xem trước.
Andrew Duncan

8

Tôi đã chiến đấu với điều này một thời gian và nghĩ rằng tôi nên đăng giải pháp của mình, tiếp theo câu trả lời của Jessedc; xóa nguồn dữ liệu của PageViewControll.

Tôi đã thêm nó vào lớp PgeViewContaptor của mình (được liên kết với trình điều khiển xem trang của tôi trong bảng phân cảnh, kế thừa cả hai UIPageViewControllerUIPageViewControllerDataSource):

static func enable(enable: Bool){
    let appDelegate  = UIApplication.sharedApplication().delegate as! AppDelegate
    let pageViewController = appDelegate.window!.rootViewController as! PgeViewController
    if (enable){
        pageViewController.dataSource = pageViewController
    }else{
        pageViewController.dataSource = nil
    }
}

Điều này sau đó có thể được gọi khi mỗi chế độ xem phụ xuất hiện (trong trường hợp này để vô hiệu hóa nó);

override func viewDidAppear(animated: Bool) {
    PgeViewController.enable(false)
}

Tôi hy vọng điều này sẽ giúp được ai đó, nó không sạch như tôi mong muốn nhưng không cảm thấy quá hack, v.v.

EDIT: Nếu ai đó muốn dịch cái này sang Objective-C, vui lòng làm :)


8

Chỉnh sửa : câu trả lời này chỉ hoạt động cho kiểu cuộn trang. Câu trả lời của Jessedc tốt hơn nhiều: hoạt động bất kể phong cách và dựa vào hành vi được ghi lại .

UIPageViewController hiển thị một loạt các nhận dạng cử chỉ mà bạn có thể sử dụng để vô hiệu hóa chúng:

// myPageViewController is your UIPageViewController instance
for (UIGestureRecognizer *recognizer in myPageViewController.gestureRecognizers) {
    recognizer.enabled = NO;
}

8
Bạn đã kiểm tra mã của bạn? myPageViewControll.gestureRecognators luôn trống
user2159978

11
có vẻ như giải pháp của bạn hoạt động theo kiểu cuộn trang, nhưng trong ứng dụng của tôi, tôi sử dụng kiểu xem cuộn
user2159978

8
Không làm việc cho cuộn ngang. Giá trị trả về luôn là một mảng trống.
Khánh Nguyễn

Các bạn đã tìm ra điều này cho phong cách cuộn?
Esqarrouth

4

Nếu bạn muốn UIPageViewControllerduy trì khả năng vuốt của mình, đồng thời cho phép các điều khiển nội dung của bạn sử dụng các tính năng của chúng (Vuốt để xóa, v.v.), chỉ cần tắt canCancelContentTouchestrong UIPageViewController.

Đặt này trong thư mục UIPageViewController's viewDidLoadfunc. (Nhanh)

if let myView = view?.subviews.first as? UIScrollView {
    myView.canCancelContentTouches = false
}

UIPageViewControllermột subview được tạo tự động xử lý các cử chỉ. Chúng tôi có thể ngăn những cuộc phỏng vấn này hủy bỏ cử chỉ nội dung.

Từ...

Vuốt để xóa trên một bảng Xem trong trangViewControll


Cảm ơn Carter. Tôi đã thử giải pháp của bạn. Tuy nhiên, vẫn có lần pageViewControll thực hiện hành động vuốt ngang ra khỏi chế độ xem bảng con. Làm cách nào tôi có thể đảm bảo rằng khi người dùng vuốt trên chế độ xem bảng con, chế độ xem bảng luôn được ưu tiên để có được cử chỉ trước?
David Liu

3

Một phần mở rộng hữu ích UIPageViewControllerđể kích hoạt và vô hiệu hóa vuốt.

extension UIPageViewController {

    func enableSwipeGesture() {
        for view in self.view.subviews {
            if let subView = view as? UIScrollView {
                subView.isScrollEnabled = true
            }
        }
    }

    func disableSwipeGesture() {
        for view in self.view.subviews {
            if let subView = view as? UIScrollView {
                subView.isScrollEnabled = false
            }
        }
    }
}

3

Tôi đã giải quyết nó như thế này (Swift 4.1)

if let scrollView = self.view.subviews.filter({$0.isKind(of: UIScrollView.self)}).first as? UIScrollView {
             scrollView.isScrollEnabled = false
}

3

Cách khéo léo cho câu trả lời @lee

extension UIPageViewController {
    var isPagingEnabled: Bool {
        get {
            return scrollView?.isScrollEnabled ?? false
        }
        set {
            scrollView?.isScrollEnabled = newValue
        }
    }

    var scrollView: UIScrollView? {
        return view.subviews.first(where: { $0 is UIScrollView }) as? UIScrollView
    }
}

0

Tương tự như câu trả lời @ user3568340

Swift 4

private var _enabled = true
    public var enabled:Bool {
        set {
            if _enabled != newValue {
                _enabled = newValue
                if _enabled {
                    dataSource = self
                }
                else{
                    dataSource = nil
                }
            }
        }
        get {
            return _enabled
        }
    }

0

Cảm ơn câu trả lời của @ user2159978.

Tôi làm cho nó dễ hiểu hơn một chút.

- (void)disableScroll{
    for (UIView *view in self.pageViewController.view.subviews) {
        if ([view isKindOfClass:[UIScrollView class]]) {
            UIScrollView * aView = (UIScrollView *)view;
            aView.scrollEnabled = NO;
        }
    }
}

0

Các câu trả lời tôi thấy có vẻ rất khó hiểu hoặc không đầy đủ đối với tôi vì vậy đây là một giải pháp hoàn chỉnh và có thể định cấu hình:

Bước 1:

Cung cấp cho mỗi thành phần PVC của bạn trách nhiệm cho biết liệu cuộn trái và phải có được bật hay không.

protocol PageViewControllerElement: class {
    var isLeftScrollEnabled: Bool { get }
    var isRightScrollEnabled: Bool { get }
}
extension PageViewControllerElement {
    // scroll is enabled in both directions by default
    var isLeftScrollEnabled: Bool {
        get {
            return true
        }
    }

    var isRightScrollEnabled: Bool {
        get {
            return true
        }
    }
}

Mỗi bộ điều khiển xem PVC của bạn nên thực hiện giao thức trên.

Bước 2:

Trong bộ điều khiển PVC của bạn, vô hiệu hóa cuộn nếu cần:

extension SomeViewController: PageViewControllerElement {
    var isRightScrollEnabled: Bool {
        get {
            return false
        }
    }
}

class SomeViewController: UIViewController {
    // ...    
}

Bước 3:

Thêm các phương pháp khóa cuộn hiệu quả vào PVC của bạn:

class PVC: UIPageViewController, UIPageViewDelegate {
    private var isLeftScrollEnabled = true
    private var isRightScrollEnabled = true
    // ...

    override func viewDidLoad() {
        super.viewDidLoad()
        // ...
        self.delegate = self
        self.scrollView?.delegate = self
    }
} 

extension PVC: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("contentOffset = \(scrollView.contentOffset.x)")

        if !self.isLeftScrollEnabled {
            disableLeftScroll(scrollView)
        }
        if !self.isRightScrollEnabled {
            disableRightScroll(scrollView)
        }
    }

    private func disableLeftScroll(_ scrollView: UIScrollView) {
        let screenWidth = UIScreen.main.bounds.width
        if scrollView.contentOffset.x < screenWidth {
            scrollView.setContentOffset(CGPoint(x: screenWidth, y: 0), animated: false)
        }
    }

    private func disableRightScroll(_ scrollView: UIScrollView) {
        let screenWidth = UIScreen.main.bounds.width
        if scrollView.contentOffset.x > screenWidth {
            scrollView.setContentOffset(CGPoint(x: screenWidth, y: 0), animated: false)
        }
    }
}

extension UIPageViewController {
    var scrollView: UIScrollView? {
        return view.subviews.filter { $0 is UIScrollView }.first as? UIScrollView
    }
}

Bước 4:

Cập nhật các thuộc tính liên quan đến cuộn khi đến một màn hình mới (nếu bạn chuyển sang một số màn hình theo cách thủ công, đừng quên gọi phương thức enableScroll):

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    let pageContentViewController = pageViewController.viewControllers![0]
    // ...

    self.enableScroll(for: pageContentViewController)
}

private func enableScroll(for viewController: UIViewController) {
    guard let viewController = viewController as? PageViewControllerElement else {
        self.isLeftScrollEnabled = true
        self.isRightScrollEnabled = true
        return
    }

    self.isLeftScrollEnabled = viewController.isLeftScrollEnabled
    self.isRightScrollEnabled = viewController.isRightScrollEnabled

    if !self.isLeftScrollEnabled {
        print("Left Scroll Disabled")
    }
    if !self.isRightScrollEnabled {
        print("Right Scroll Disabled")
    }
}

0

Có một cách tiếp cận đơn giản hơn nhiều so với hầu hết các câu trả lời ở đây gợi ý, đó là trả về nilcác cuộc gọi lại viewControllerBeforeviewControllerAfterdataSource.

Điều này vô hiệu hóa cử chỉ cuộn trên thiết bị iOS 11+, trong khi vẫn giữ khả năng sử dụng dataSource(đối với những thứ như presentationIndex/ presentationCountđược sử dụng cho chỉ báo trang)

Nó cũng vô hiệu hóa điều hướng thông qua. các pageControl(các dấu chấm ở phía dưới)

extension MyPageViewController: UIPageViewControllerDataSource {
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
        return nil
    }
    
    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
        return nil
    }
}

0

pageViewController.view.isUserInteractionEnabled = false


-1

Dịch phản hồi của @ user2159978 sang C #:

foreach (var view in pageViewController.View.Subviews){
   var subView = view as UIScrollView;
   if (subView != null){
     subView.ScrollEnabled = enabled;
   }
}

-1

(Swift 4) Bạn có thể xóa cử chỉ Nhận dạng trang của mìnhViewControll:

pageViewController.view.gestureRecognizers?.forEach({ (gesture) in
            pageViewController.view.removeGestureRecognizer(gesture)
        })

Nếu bạn thích trong phần mở rộng:

extension UIViewController{
    func removeGestureRecognizers(){
        view.gestureRecognizers?.forEach({ (gesture) in
            view.removeGestureRecognizer(gesture)
        })
    }
}

pageViewController.removeGestureRecognizers


-1

Khai báo nó như thế này:

private var scrollView: UIScrollView? {
    return pageViewController.view.subviews.compactMap { $0 as? UIScrollView }.first
}

Sau đó sử dụng nó như thế này:

scrollView?.isScrollEnabled = true //false

-1

Việc liệt kê các mục phỏng vấn để tìm scrollView của một UIPageViewControllercông việc không phù hợp với tôi, vì tôi không thể tìm thấy bất kỳ scrollView nào trong lớp con của trình điều khiển trang của tôi. Vì vậy, những gì tôi nghĩ làm là vô hiệu hóa các nhận dạng cử chỉ, nhưng đủ cẩn thận để không vô hiệu hóa những cái cần thiết.

Vì vậy, tôi đã đưa ra điều này:

if let panGesture = self.gestureRecognizers.filter({$0.isKind(of: UIPanGestureRecognizer.self)}).first           
    panGesture.isEnabled = false        
}

Đặt nó bên trong viewDidLoad()và bạn đã hoàn tất!


-1
 override func viewDidLayoutSubviews() {
    for View in self.view.subviews{
        if View.isKind(of: UIScrollView.self){
            let ScrollV = View as! UIScrollView
            ScrollV.isScrollEnabled = false
        }

    }
}

Thêm điều này trong lớp trình điều khiển lượt xem trang của bạn. Làm việc 100%


vui lòng nhận xét vấn đề bạn đang đối mặt với mã này hoạt động hoàn hảo: /
ap00724

-1

chỉ cần thêm thuộc tính điều khiển này vào lớp con UIPageViewControll của bạn :

var isScrollEnabled = true {
    didSet {
        for case let scrollView as UIScrollView in view.subviews {
            scrollView.isScrollEnabled = isScrollEnabled
        }
    }
}
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.