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?

pengguna2159978
sumber
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.

Jessedc
sumber
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;
    }
}
pengguna2159978
sumber
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
        }
    }
}
lee
sumber
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
LinusGeffarth
sumber
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 :)

Jamie Robinson
sumber
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;
}
Austin
sumber
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

Carter Medlin
sumber
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
            }
        }
    }
}
jbustamante
sumber
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
}
Darko
sumber
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
    }
}
Szymon W
sumber
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
        }
    }
Emmanouil Nicolas
sumber
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;
        }
    }
}
dengApro
sumber
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")
    }
}
michael-martinez
sumber
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
    }
}
Claus Jørgensen
sumber
0

pageViewController.view.isUserInteractionEnabled = false

usus
sumber
-1

Menerjemahkan tanggapan @ user2159978 ke C #:

foreach (var view in pageViewController.View.Subviews){
   var subView = view as UIScrollView;
   if (subView != null){
     subView.ScrollEnabled = enabled;
   }
}
gtrujillo
sumber
-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

Miguel
sumber
-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
Bartłomiej Semańczyk
sumber
-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!

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

ap00724
sumber
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
        }
    }
}
Stanislau Baranouski
sumber