Bagaimana cara saya Nonaktifkan isyarat usap dari UIPageViewController?


125

Dalam kasus saya, induk UIViewControllerberisi UIPageViewControlleryang berisi UINavigationControlleryang berisi UIViewController. Saya perlu menambahkan gerakan menggesek ke pengontrol tampilan terakhir, tetapi gesekan ditangani seolah-olah milik pengontrol tampilan halaman. Saya mencoba melakukan ini secara terprogram dan via xib tetapi tanpa hasil.

Jadi, seperti yang saya pahami, saya tidak dapat mencapai tujuan saya sampai UIPageViewControllermenangani gerakannya. Bagaimana cara mengatasi masalah ini?


7
GunakanpageViewControllerObject.view.userInteractionEnabled = NO;
Srikanth

6
salah, karena memblokir semua kontennya juga. Tapi saya hanya perlu memblokir
gerakannya

Mengapa kau melakukan ini? Perilaku apa yang Anda inginkan dari aplikasi? Sepertinya Anda membuat arsitektur terlalu rumit. Bisakah Anda menjelaskan perilaku apa yang Anda tuju.
Fogmeister

Salah satu halaman di UIPageViewControllermiliki UINavigationController. Pelanggan ingin memunculkan pengontrol navigasi pada gerakan menggesek (jika memungkinkan), tetapi pengontrol tampilan halaman menangani gesekan
user2159978

@Santanth terima kasih, itulah yang saya butuhkan! Tampilan halaman saya mogok ketika saya memicu perubahan halaman secara programatik dan seseorang menghentikannya dengan menggesek, jadi saya harus menonaktifkan menggesek sementara setiap kali perubahan halaman dipicu dalam kode ...
Kuba Suder

Jawaban:


262

Cara terdokumentasi untuk mencegah UIPageViewControllerpengguliran adalah dengan tidak menetapkan dataSourceproperti. Jika Anda menetapkan sumber data, itu akan pindah ke mode navigasi 'berbasis gesture' yang merupakan apa yang ingin Anda cegah.

Tanpa sumber data, Anda secara manual menyediakan pengontrol tampilan saat Anda ingin menggunakan setViewControllers:direction:animated:completionmetode dan itu akan berpindah di antara pengontrol tampilan sesuai permintaan.

Hal di atas dapat disimpulkan dari dokumentasi Apple tentang UIPageViewController (Tinjauan umum, paragraf kedua):

Untuk mendukung navigasi berbasis gesture, Anda harus menyediakan pengontrol tampilan menggunakan objek sumber data.


1
Saya lebih suka solusi ini juga. Anda dapat menyimpan sumber data lama dalam suatu variabel, mengatur sumber data menjadi nihil, dan kemudian mengembalikan sumber data lama untuk mengaktifkan kembali pengguliran. Tidak semua yang bersih, tetapi jauh lebih baik daripada melintasi hierarki tampilan yang mendasarinya untuk menemukan tampilan gulir.
Matt R

3
Menonaktifkan sumber data menyebabkan masalah saat melakukannya sebagai respons terhadap notifikasi keyboard untuk subview bidang teks. Mengulangi tampilan tampilan untuk menemukan UIScrollView tampaknya lebih dapat diandalkan.
AR Younce

9
Tidakkah ini menghilangkan titik-titik di bagian bawah layar? Dan jika Anda tidak memiliki swiping dan tidak ada titik, tidak ada gunanya menggunakan PageViewController sama sekali. Saya kira si penanya ingin mempertahankan titik-titiknya.
Leo Flaherty

Ini membantu menyelesaikan masalah yang saya hadapi ketika halaman dimuat secara tidak sinkron dan pengguna membuat gerakan menggesek. Bravo :)
Ikuti

1
A. R Younce benar. Jika Anda menonaktifkan sumber data PageViewController sebagai respons terhadap notifikasi keyboard (yaitu: Anda tidak ingin pengguna menggulir secara horizontal saat keyboard berada di atas) maka keyboard Anda akan segera menghilang ketika Anda mencari sumber data PageViewController.
micnguyen

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

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

        view.scrollEnabled = NO;
    }
}

5
Yang ini menjaga kontrol halaman, yang bagus.
Marcus Adams

1
Ini adalah pendekatan yang bagus karena menjaga kontrol halaman (titik-titik kecil). Anda akan ingin memperbaruinya ketika membuat perubahan halaman secara manual. Saya menggunakan jawaban ini untuk stackoverflow.com/a/28356383/1071899
Simon Bøgh

1
Kenapa tidakfor (UIView *view in self.pageViewController.view.subviews) {
dengApro

Harap perhatikan bahwa pengguna masih dapat menavigasi antar halaman dengan mengetuk kontrol halaman di bagian kiri dan kanan.
MasterCarl

57

Saya menerjemahkan jawaban dari user2159978 ke Swift 5.1

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

30

Menerapkan solusi @ lee (@ user2159978's) sebagai ekstensi:

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

Penggunaan: (dalam UIPageViewController)

self.isPagingEnabled = false

Untuk menjadi lebih elegan, Anda dapat menambahkan bahwa: var scrollView: UIScrollView? { for view in view.subviews { if let subView = view as? UIScrollView { return subView } } return nil }
Wagner Sales

Sang pengambil di sini hanya mengembalikan status yang diaktifkan dari subview terakhir.
Andrew Duncan

8

Saya telah berjuang untuk sementara waktu sekarang dan berpikir saya harus memposting solusi saya, sebagai lanjutan dari jawaban Jessedc; menghapus sumber data PageViewController.

Saya menambahkan ini ke kelas PgeViewController saya (ditautkan ke pengontrol tampilan halaman di storyboard, mewarisi keduanya UIPageViewControllerdan 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
    }
}

Ini kemudian dapat dipanggil ketika setiap sub tampilan muncul (dalam hal ini untuk menonaktifkannya);

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

Saya harap ini membantu seseorang, itu tidak sebersih yang saya inginkan tetapi tidak merasa terlalu berantakan dll

EDIT: Jika seseorang ingin menerjemahkan ini ke dalam Objective-C, mohon lakukan :)


8

Sunting : jawaban ini hanya berfungsi untuk gaya keriting halaman. Jawaban Jessedc jauh lebih baik: bekerja terlepas dari gaya dan bergantung pada perilaku yang didokumentasikan .

UIPageViewController memperlihatkan susunan pengenal isyarat, yang dapat Anda gunakan untuk menonaktifkannya:

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

8
Sudahkah Anda menguji kode Anda? myPageViewController.gestureRecognizers selalu kosong
user2159978

11
tampaknya solusi Anda berfungsi untuk gaya keriting halaman, tetapi dalam aplikasi saya, saya menggunakan gaya tampilan gulir
user2159978

8
Tidak berfungsi untuk pengguliran horizontal. Nilai yang dikembalikan selalu berupa array kosong.
Khanh Nguyen

apakah kalian mencari tahu ini untuk gaya gulir?
Esqarrouth

4

Jika Anda ingin UIPageViewControllermempertahankan kemampuannya untuk menggesek, sambil memungkinkan kontrol konten Anda untuk menggunakan fitur-fiturnya (Geser untuk menghapus, dll), matikan saja canCancelContentTouchesdi UIPageViewController.

Menempatkan ini dalam Anda UIPageViewController's viewDidLoadfunc. (Cepat)

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

The UIPageViewControllermemiliki subview yang dihasilkan otomatis yang menangani gerakan. Kami dapat mencegah subview ini dari membatalkan isyarat konten.

Dari...

Geser untuk menghapus pada tableView yang ada di dalam pageViewController


Terima kasih Carter. Saya sudah mencoba solusi Anda. Namun, masih ada beberapa kali pageViewController mengambil-alih tindakan gesekan horizontal menjauh dari tampilan tabel anak. Bagaimana saya bisa memastikan bahwa ketika pengguna menggesek pada tampilan tabel anak, tampilan tabel selalu diprioritaskan untuk mendapatkan gerakan terlebih dahulu?
David Liu

3

Ekstensi berguna UIPageViewControlleruntuk mengaktifkan dan menonaktifkan gesek.

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

Saya menyelesaikannya seperti ini (Swift 4.1)

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

3

Cara cepat untuk jawaban @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

Mirip dengan jawaban @ user3568340

Cepat 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

Terima kasih atas jawaban @ user2159978.

Saya membuatnya sedikit lebih dimengerti.

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

0

Jawaban yang saya temukan terlihat sangat membingungkan atau tidak lengkap bagi saya jadi di sini adalah solusi yang lengkap dan dapat dikonfigurasi:

Langkah 1:

Berikan masing-masing elemen PVC Anda tanggung jawab untuk mengetahui apakah gulir kiri dan kanan diaktifkan atau tidak.

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

Setiap pengontrol tampilan PVC Anda harus menerapkan protokol di atas.

Langkah 2:

Di pengontrol PVC Anda, nonaktifkan gulir jika perlu:

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

class SomeViewController: UIViewController {
    // ...    
}

Langkah 3:

Tambahkan metode kunci gulir yang efektif ke PVC Anda:

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

Langkah 4:

Perbarui atribut terkait gulir saat mencapai layar baru (jika Anda beralih ke beberapa layar secara manual jangan lupa memanggil metode 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

Ada pendekatan yang jauh lebih sederhana daripada kebanyakan jawaban di sini menyarankan, yaitu untuk kembali nildalam viewControllerBeforedan viewControllerAfterpanggilan balik dataSource.

Ini menonaktifkan gerakan gulir pada perangkat iOS 11+, sambil menjaga kemungkinan untuk menggunakan dataSource(untuk hal-hal seperti presentationIndex/ presentationCountdigunakan untuk indikator halaman)

Ini juga menonaktifkan navigasi via. yang pageControl(titik-titik di bawah)

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

Menerjemahkan tanggapan @ user2159978 ke C #:

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

-1

(Swift 4) Anda dapat menghapus gestureRecognizers dari halaman Anda ViewController:

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

Jika Anda lebih suka dalam ekstensi:

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

dan pageViewController.removeGestureRecognizers


-1

Nyatakan seperti ini:

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

Kemudian gunakan seperti ini:

scrollView?.isScrollEnabled = true //false

-1

Menghitung subview untuk menemukan scrollView dari sebuah UIPageViewControllertidak berfungsi untuk saya, karena saya tidak dapat menemukan scrollView di subkelas pengontrol halaman saya. Jadi yang saya pikirkan lakukan adalah menonaktifkan pengenal isyarat, tapi cukup hati-hati untuk tidak menonaktifkan yang diperlukan.

Jadi saya datang dengan ini:

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

Masukkan itu ke dalam viewDidLoad()dan Anda siap!


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

    }
}

Tambahkan ini di kelas halaman viewcontroller Anda. 100% berfungsi


tolong beri komentar masalah apa yang Anda hadapi kode ini berfungsi dengan baik: /
ap00724

-1

cukup tambahkan properti kontrol ini di subkelas UIPageViewController Anda :

var isScrollEnabled = true {
    didSet {
        for case let scrollView as UIScrollView in view.subviews {
            scrollView.isScrollEnabled = isScrollEnabled
        }
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.