ฉันจะปิดใช้งานท่าทางการปัดของ UIPageViewController ได้อย่างไร


125

ในกรณีหลักของฉันUIViewControllerมีUIPageViewControllerซึ่งประกอบด้วยUINavigationControllerซึ่งประกอบด้วยUIViewController. ฉันต้องการเพิ่มท่าทางการปัดไปยังตัวควบคุมมุมมองสุดท้าย แต่การปัดจะถูกจัดการราวกับว่ามันเป็นของตัวควบคุมการดูหน้า ฉันพยายามทำสิ่งนี้ทั้งโดยทางโปรแกรมและผ่าน xib แต่ไม่มีผลลัพธ์

อย่างที่ฉันเข้าใจฉันไม่สามารถบรรลุเป้าหมายได้จนกว่าจะUIPageViewControllerจัดการกับท่าทางของมัน วิธีแก้ปัญหานี้?


7
ใช้pageViewControllerObject.view.userInteractionEnabled = NO;
Srikanth

6
ไม่ถูกต้องเนื่องจากบล็อกเนื้อหาทั้งหมดด้วย แต่ฉันต้องบล็อกท่าทางสัมผัสเท่านั้น
user2159978

ทำไมคุณทำเช่นนี้? คุณต้องการพฤติกรรมอะไรจากแอป ดูเหมือนว่าคุณกำลังทำสถาปัตยกรรมที่ซับซ้อนเกินไป คุณสามารถอธิบายพฤติกรรมที่คุณต้องการได้หรือไม่
Fogmeister

หนึ่งหน้าในมีUIPageViewController UINavigationControllerลูกค้าต้องการเปิดตัวควบคุมการนำทางด้วยท่าทางการปัด (ถ้าเป็นไปได้) แต่ตัวควบคุมมุมมองหน้าจัดการการ
ปัด

@Srikanth ขอบคุณนั่นคือสิ่งที่ฉันต้องการ! การดูหน้าเว็บของฉันขัดข้องเมื่อฉันทริกเกอร์การเปลี่ยนหน้าโดยทางโปรแกรมและมีคนขัดขวางด้วยการปัดดังนั้นฉันจึงต้องปิดการใช้งานการปัดชั่วคราวทุกครั้งที่มีการเรียกการเปลี่ยนหน้าในรหัส ...
Kuba Suder

คำตอบ:


263

วิธีที่เป็นเอกสารในการป้องกันไม่ให้UIPageViewControllerเลื่อนคือการไม่กำหนดdataSourceคุณสมบัติ หากคุณกำหนดแหล่งข้อมูลแหล่งข้อมูลจะย้ายเข้าสู่โหมดการนำทางแบบ "ตามท่าทาง" ซึ่งเป็นสิ่งที่คุณพยายามป้องกัน

หากไม่มีแหล่งข้อมูลคุณจะต้องจัดหาตัวควบคุมมุมมองด้วยตนเองเมื่อคุณต้องการด้วยsetViewControllers:direction:animated:completionวิธีการและจะย้ายไปมาระหว่างตัวควบคุมมุมมองตามความต้องการ

ข้างต้นสามารถอนุมานได้จากเอกสาร UIPageViewController ของ Apple (ภาพรวมย่อหน้าที่สอง):

ในการสนับสนุนการนำทางโดยใช้ท่าทางคุณต้องจัดเตรียมตัวควบคุมมุมมองของคุณโดยใช้ออบเจ็กต์แหล่งข้อมูล


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

3
การปิดใช้งานแหล่งข้อมูลทำให้เกิดปัญหาเมื่อทำเช่นนั้นเพื่อตอบสนองต่อการแจ้งเตือนของแป้นพิมพ์สำหรับมุมมองย่อยของช่องข้อความ การวนซ้ำในมุมมองย่อยของมุมมองเพื่อค้นหา UIScrollView ดูเหมือนจะน่าเชื่อถือกว่า
AR Younce

9
สิ่งนี้ไม่ลบจุดที่ด้านล่างของหน้าจอใช่หรือไม่ และหากคุณไม่มีการปัดและไม่มีจุดก็ไม่มีจุดสำคัญในการใช้ PageViewController เลย ฉันเดาว่าผู้ถามต้องการคงจุดไว้
Leo Flaherty

สิ่งนี้ช่วยแก้ปัญหาที่ฉันพบเมื่อโหลดหน้าเว็บแบบอะซิงโครนัสและผู้ใช้ทำท่าทางปัด Bravo :)
Ja͢ck

1
A. R Younce ถูกต้อง หากคุณปิดใช้งานแหล่งข้อมูลของ PageViewController เพื่อตอบสนองต่อการแจ้งเตือนทางแป้นพิมพ์ (เช่น: คุณไม่ต้องการให้ผู้ใช้เลื่อนในแนวนอนเมื่อแป้นพิมพ์ขึ้น) แป้นพิมพ์ของคุณจะหายไปทันทีเมื่อคุณไม่มีแหล่งข้อมูลของ PageViewController
micnguyen

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

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

        view.scrollEnabled = NO;
    }
}

5
อันนี้ช่วยควบคุมเพจซึ่งดี
Marcus Adams

1
นี่เป็นแนวทางที่ยอดเยี่ยมเนื่องจากช่วยควบคุมหน้าเว็บ (จุดเล็ก ๆ ) คุณจะต้องอัปเดตเมื่อทำการเปลี่ยนแปลงเพจด้วยตนเอง ฉันใช้คำตอบนี้สำหรับstackoverflow.com/a/28356383/1071899
Simon Bøgh

1
ทำไมไม่for (UIView *view in self.pageViewController.view.subviews) {
dengApro

โปรดทราบว่าผู้ใช้จะยังคงสามารถนำทางไปมาระหว่างหน้าต่างๆได้โดยการแตะตัวควบคุมหน้าในครึ่งซ้ายและขวา
MasterCarl

57

ฉันแปลคำตอบของuser2159978เป็นSwift 5.1

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

30

การนำโซลูชันของ @ lee (@ user2159978's) มาใช้เป็นส่วนขยาย:

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

การใช้งาน: (ในUIPageViewController)

self.isPagingEnabled = false

เพื่อให้ดูหรูหรายิ่งขึ้นคุณสามารถเพิ่มสิ่งนั้น: var scrollView: UIScrollView? { for view in view.subviews { if let subView = view as? UIScrollView { return subView } } return nil }
Wagner Sales

getter ที่นี่จะคืนค่าสถานะที่เปิดใช้งานของ subview ล่าสุดเท่านั้น
Andrew Duncan

8

ฉันต่อสู้เรื่องนี้มาระยะหนึ่งแล้วและคิดว่าฉันควรโพสต์วิธีแก้ปัญหาของฉันตามคำตอบของ Jessedc การลบแหล่งข้อมูลของ PageViewController

ฉันเพิ่มสิ่งนี้ลงในคลาส PgeViewController ของฉัน (เชื่อมโยงกับตัวควบคุมการดูเพจของฉันในสตอรีบอร์ดสืบทอดทั้งสองอย่างUIPageViewControllerและUIPageViewControllerDataSource):

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

จากนั้นสามารถเรียกได้เมื่อแต่ละมุมมองย่อยปรากฏขึ้น (ในกรณีนี้คือปิดใช้งาน)

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

ฉันหวังว่านี่จะช่วยใครบางคนได้มันไม่สะอาดเท่าที่ฉันต้องการ แต่ไม่รู้สึกแฮ็คเกินไปเป็นต้น

แก้ไข: หากมีใครต้องการแปลสิ่งนี้เป็น Objective-C โปรดทำ :)


8

แก้ไข : คำตอบนี้ใช้ได้กับสไตล์การม้วนหน้าเท่านั้น คำตอบของ Jessedcนั้นดีกว่ามาก: ทำงานได้โดยไม่คำนึงถึงรูปแบบและอาศัยพฤติกรรมที่บันทึกไว้

UIPageViewController แสดงอาร์เรย์ของตัวจดจำท่าทางซึ่งคุณสามารถใช้เพื่อปิดใช้งานได้:

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

8
คุณทดสอบรหัสของคุณแล้วหรือยัง? myPageViewController.gestureRecognizers ว่างเปล่าเสมอ
user2159978

11
ดูเหมือนว่าโซลูชันของคุณใช้ได้กับสไตล์การม้วนหน้า แต่ในแอปของฉันฉันใช้สไตล์มุมมองแบบเลื่อน
user2159978

8
ไม่ทำงานสำหรับการเลื่อนในแนวนอน ค่าที่ส่งคืนจะเป็นอาร์เรย์ว่างเสมอ
Khanh Nguyen

พวกคุณคิดออกสำหรับรูปแบบการเลื่อนหรือไม่?
Esqarrouth

4

หากคุณต้องการUIPageViewControllerรักษาความสามารถในการปัดในขณะที่อนุญาตให้ส่วนควบคุมเนื้อหาของคุณใช้คุณสมบัติต่างๆได้ (ปัดเพื่อลบ ฯลฯ ) เพียงแค่ปิดcanCancelContentTouchesในไฟล์UIPageViewController.

ใส่ในของคุณUIPageViewController's viewDidLoadfunc (Swift)

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

UIPageViewControllerมี subview สร้างขึ้นโดยอัตโนมัติที่จัดการท่าทาง เราสามารถป้องกันไม่ให้มุมมองย่อยเหล่านี้ยกเลิกท่าทางสัมผัสของเนื้อหาได้

จาก...

ปัดเพื่อลบบน tableView ที่อยู่ภายใน pageViewController


ขอบคุณคาร์เตอร์ ฉันได้ลองวิธีแก้ปัญหาของคุณแล้ว อย่างไรก็ตามยังมีบางครั้งที่ pageViewController ใช้การปัดในแนวนอนมากเกินไปจากมุมมองตารางลูก ฉันจะแน่ใจได้อย่างไรว่าเมื่อผู้ใช้เลื่อนไปที่มุมมองตารางรองมุมมองตารางจะได้รับการจัดลำดับความสำคัญเพื่อให้ได้ท่าทางก่อนเสมอ
David Liu

3

ส่วนขยายที่มีประโยชน์ในUIPageViewControllerการเปิดและปิดการใช้งานรูด

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

ฉันแก้ไขแบบนี้ (Swift 4.1)

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

3

วิธีที่รวดเร็วสำหรับคำตอบ@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

คล้ายกับ @ user3568340 answer

สวิฟต์ 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

ขอบคุณคำตอบของ @ user2159978

ฉันทำให้มันเข้าใจมากขึ้นเล็กน้อย

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

0

คำตอบที่ฉันพบนั้นดูสับสนหรือไม่สมบูรณ์สำหรับฉันดังนั้นนี่คือโซลูชันที่สมบูรณ์และกำหนดค่าได้:

ขั้นตอนที่ 1:

ให้องค์ประกอบ PVC แต่ละชิ้นของคุณมีความรับผิดชอบในการบอกว่ามีการเปิดใช้งานการเลื่อนซ้ายและขวาหรือไม่

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

ตัวควบคุมมุมมอง PVC แต่ละตัวของคุณควรใช้โปรโตคอลข้างต้น

ขั้นตอนที่ 2:

ในตัวควบคุม PVC ของคุณให้ปิดการใช้งานการเลื่อนหากจำเป็น:

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

class SomeViewController: UIViewController {
    // ...    
}

ขั้นตอนที่ 3:

เพิ่มวิธีการล็อคแบบเลื่อนที่มีประสิทธิภาพให้กับ PVC ของคุณ:

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

ขั้นตอนที่ 4:

อัปเดตแอตทริบิวต์ที่เกี่ยวข้องกับการเลื่อนเมื่อถึงหน้าจอใหม่ (หากคุณเปลี่ยนไปใช้บางหน้าจอด้วยตนเองอย่าลืมเรียกใช้เมธอด 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

มีวิธีการที่ง่ายกว่าคำตอบส่วนใหญ่ที่นี่แนะนำซึ่งก็คือการส่งคืนnilในการเรียกกลับviewControllerBeforeและviewControllerAfterdataSource

สิ่งนี้จะปิดใช้งานท่าทางการเลื่อนบนอุปกรณ์ iOS 11+ ในขณะที่ยังคงความเป็นไปได้ในการใช้dataSource(สำหรับสิ่งต่างๆเช่นpresentationIndex/presentationCountใช้สำหรับตัวบ่งชี้หน้า)

นอกจากนี้ยังปิดการนำทางผ่านไฟล์. pageControl(จุดในด้านล่าง)

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


-1

การแปลคำตอบของ @ user2159978 ต่อ C #:

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

-1

(Swift 4) คุณสามารถลบ GestureRecognizers ของ pageViewController ของคุณ:

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

หากคุณต้องการขยาย:

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

และ pageViewController.removeGestureRecognizers


-1

ประกาศดังนี้

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

จากนั้นใช้ดังนี้:

scrollView?.isScrollEnabled = true //false

-1

การแจกแจงมุมมองย่อยเพื่อค้นหา scrollView ของ a UIPageViewControllerไม่ได้ผลสำหรับฉันเนื่องจากฉันไม่พบ scrollView ในคลาสย่อยของตัวควบคุมเพจของฉัน ดังนั้นสิ่งที่ฉันคิดจะทำคือปิดการใช้งานตัวจดจำท่าทาง แต่ระวังพอที่จะไม่ปิดการใช้งานที่จำเป็น

ดังนั้นฉันจึงคิดสิ่งนี้:

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

ใส่สิ่งนั้นไว้ข้างในviewDidLoad()และคุณก็พร้อมแล้ว!


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

    }
}

เพิ่มสิ่งนี้ในคลาส pageviewcontroller ของคุณ ทำงานได้ 100%


โปรดแสดงความคิดเห็นว่าปัญหาใดที่คุณพบรหัสนี้ทำงานได้อย่างสมบูรณ์: /
ap00724

-1

เพียงเพิ่มคุณสมบัติการควบคุมนี้ที่คลาสย่อยUIPageViewControllerของคุณ:

var isScrollEnabled = true {
    didSet {
        for case let scrollView as UIScrollView in view.subviews {
            scrollView.isScrollEnabled = isScrollEnabled
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.