UIPageViewController'ın hızlıca kaydırma hareketini nasıl devre dışı bırakırım?


125

Benim durumumda ebeveyn UIViewController, UIPageViewControllerhangisini içeren UINavigationControlleriçerir UIViewController. Son görünüm denetleyicisine bir kaydırma hareketi eklemem gerekiyor, ancak kaydırmalar sayfa görüntüleme denetleyicisine aitmiş gibi işleniyor. Bunu hem programlı olarak hem de xib aracılığıyla yapmaya çalıştım ama sonuç alamadım.

Yani anladığım kadarıyla UIPageViewController, jestlerini yapmadan hedefime ulaşamam . bu sorunu nasıl çözeriz?


7
KullanımpageViewControllerObject.view.userInteractionEnabled = NO;
Srikanth

6
yanlış, çünkü tüm içeriğini de engelliyor. Ancak yalnızca hareketlerini engellemem gerekiyor
user2159978

Bunu neden yapıyorsun? Uygulamadan ne tür davranış bekliyorsunuz? Görünüşe göre mimariyi aşırı karmaşıklaştırıyorsun. Hangi davranışı hedeflediğinizi açıklayabilir misiniz?
Fogmeister

İçindeki sayfalardan UIPageViewControllerbiri UINavigationController. Müşteri, kaydırma hareketinde gezinme denetleyicisini açmak istiyor (mümkünse), ancak bunun yerine sayfa görüntüleme denetleyicisi kaydırmaları
işliyor

@Srikanth teşekkürler, tam da ihtiyacım olan şey bu! Bir sayfa değişikliğini programlı olarak tetiklediğimde ve birisi kaydırarak onu kesintiye uğrattığında sayfa görünümüm çöküyordu, bu yüzden sayfa değişikliği kodda her tetiklendiğinde kaydırmayı geçici olarak devre dışı bırakmak zorunda kaldım ...
Kuba Suder

Yanıtlar:


263

UIPageViewControllerKaydırmayı önlemenin belgelenmiş yolu , dataSourceözelliği atamamaktır. Veri kaynağını atarsanız, önlemeye çalıştığınız şey olan 'jest tabanlı' gezinme moduna geçecektir.

Bir veri kaynağı olmadan, istediğiniz zaman setViewControllers:direction:animated:completionyöntemle manuel olarak görünüm denetleyicileri sağlarsınız ve isteğe bağlı olarak görünüm denetleyicileri arasında hareket eder.

Yukarıdakiler, Apple'ın UIPageViewController belgelerinden çıkarılabilir (Genel Bakış, ikinci paragraf):

Hareket tabanlı gezinmeyi desteklemek için, bir veri kaynağı nesnesi kullanarak görünüm denetleyicilerinize sağlamanız gerekir.


1
Ben de bu çözümü tercih ediyorum. Eski veri kaynağını bir değişkende kaydedebilir, veri kaynağını sıfır olarak ayarlayabilir ve ardından kaydırmayı yeniden etkinleştirmek için eski veri kaynağını geri yükleyebilirsiniz. Hepsi o kadar temiz değil, ancak kaydırma görünümünü bulmak için temeldeki görünüm hiyerarşisini geçmekten çok daha iyi.
Matt R

3
Veri kaynağını devre dışı bırakmak, metin alanı alt görünümleri için klavye bildirimlerine yanıt olarak bunu yaparken sorunlara neden olur. UIScrollView'i bulmak için görünümün alt görünümlerini yinelemek daha güvenilir görünmektedir.
AR Younce

9
Bu, ekranın altındaki noktaları kaldırmaz mı? Kaydırma ve nokta yoksa, PageViewController kullanmanın pek bir anlamı yoktur. Soruyu soranın noktaları korumak istediğini tahmin ediyorum.
Leo Flaherty

Bu, sayfalar eşzamansız olarak yüklendiğinde ve kullanıcı bir kaydırma hareketi yaptığında karşılaştığım bir sorunu çözmeye yardımcı oldu. Bravo :)
Ja͢ck

1
A. R Younce doğru. Bir klavye bildirimine yanıt olarak PageViewController veri kaynağını devre dışı bırakıyorsanız (yani: klavye yukarıdayken kullanıcının yatay olarak kaydırmasını istemiyorsanız), PageViewController veri kaynağını sıfırladığınızda klavyeniz hemen kaybolacaktır.
micnguyen

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

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

        view.scrollEnabled = NO;
    }
}

5
Bu, güzel olan sayfa kontrolünü korur.
Marcus Adams

1
Bu, sayfa kontrolünü (küçük noktalar) koruduğu için harika bir yaklaşımdır. Sayfayı manuel olarak değiştirirken bunları güncellemek isteyeceksiniz. Bu yanıtı bu stackoverflow.com/a/28356383/1071899
Simon Bøgh

1
Neden olmasınfor (UIView *view in self.pageViewController.view.subviews) {
deng

Lütfen, kullanıcıların sol ve sağ yarıdaki sayfa kontrolüne dokunarak sayfalar arasında gezinmeye devam edebileceklerini unutmayın.
MasterCarl

57

Ben cevabını tercüme user2159978 için Swift 5.1

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

30

@ Lee's (@ user2159978'in) çözümünü bir uzantı olarak uygulamak:

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

Kullanım: (içinde UIPageViewController)

self.isPagingEnabled = false

Daha şık olmak için şunu ekleyebilirsiniz: var scrollView: UIScrollView? { for view in view.subviews { if let subView = view as? UIScrollView { return subView } } return nil }
Wagner Satışları

Buradaki alıcı yalnızca son alt görüntünün etkin durumunu döndürür.
Andrew Duncan

8

Bununla bir süredir savaşıyorum ve Jessedc'in cevabını takiben çözümümü yayınlamam gerektiğini düşündüm; PageViewController veri kaynağını kaldırma.

Bunu PgeViewController sınıfıma ekledim (film şeridindeki sayfa görüntüleme denetleyicime bağlı, her ikisini de devralır UIPageViewControllerve 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
    }
}

Bu daha sonra her alt görünüm göründüğünde çağrılabilir (bu durumda devre dışı bırakmak için);

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

Umarım bu birinin dışarı çıkmasına yardımcı olur, istediğim kadar temiz değil ama çok huysuz hissetmiyor vb.

DÜZENLEME: Biri bunu Objective-C'ye çevirmek istiyorsa lütfen yapın :)


8

Düzenleme : bu cevap yalnızca sayfa kıvrım stili için geçerlidir. Jessedc'in cevabı çok daha iyi: Tarzdan bağımsız olarak işe yarıyor ve belgelenmiş davranışa dayanıyor .

UIPageViewController onları devre dışı bırakmak için kullanabileceğiniz hareket tanıyıcı dizisini gösterir:

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

8
Kodunuzu test ettiniz mi? myPageViewController.gestureRecognizers her zaman boştur
user2159978

11
çözümünüz sayfa kıvrım stili için çalışıyor gibi görünüyor, ancak uygulamamda kaydırma görünümü stilini kullanıyorum
user2159978

8
Yatay kaydırma için çalışmıyor. Döndürülen değer her zaman boş bir dizidir.
Khanh Nguyen

Bunu kaydırma stili için çözdünüz mü?
Esqarrouth

4

İsterseniz sizin UIPageViewControlleriçerik kontrolleri bunların özelliklerini (kaydırın silmek, vs) kullanmak için izin verirken, tokatlamak için bu yeteneği korumak sadece kapatmak için canCancelContentTouchesde UIPageViewController.

Senin bu koy UIPageViewControllerbireyin viewDidLoadfonk. (Swift)

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

UIPageViewControllerHareketlerini işleyen bir otomatik oluşturulan subview sahiptir. Bu alt görünümlerin içerik hareketlerini iptal etmesini önleyebiliriz.

Gönderen ...

Bir pageViewController içindeki tableView üzerinde silmek için kaydırın


Teşekkürler Carter. Çözümünüzü denedim. Bununla birlikte, pageViewController'ın alt tablo görünümünden yatay kaydırma eylemini aştığı zamanlar vardır. Kullanıcı alt tablo görünümünde kaydırdığında, önce hareketi almak için tablo görünümüne her zaman öncelik verilmesini nasıl sağlayabilirim?
David Liu

3

UIPageViewControllerKaydırmayı etkinleştirmek ve devre dışı bırakmak için kullanışlı bir uzantı .

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

Bunu böyle çözdüm (Swift 4.1)

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

3

@Lee cevabının hızlı yolu

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 benzer

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

@ User2159978'in cevabı sayesinde.

Bunu biraz daha anlaşılır hale getiriyorum.

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

0

Bulduğum cevaplar bana çok kafa karıştırıcı veya eksik görünüyor, bu yüzden işte eksiksiz ve yapılandırılabilir bir çözüm:

Aşama 1:

PVC öğelerinizin her birine, sola ve sağa kaydırmanın etkin olup olmadığını anlatma sorumluluğunu verin.

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 görüntü denetleyicilerinizin her biri yukarıdaki protokolü uygulamalıdır.

Adım 2:

PVC denetleyicilerinizde, gerekirse kaydırmayı devre dışı bırakın:

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

class SomeViewController: UIViewController {
    // ...    
}

Aşama 3:

PVC'nize etkili kaydırma kilidi yöntemlerini ekleyin:

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. Adım:

Yeni bir ekrana ulaşırken kaydırmayla ilgili öznitelikleri güncelleyin (bir ekrana manuel olarak geçiş yaparsanız, enableScroll yöntemini çağırmayı unutmayın):

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

Döndürmektir en cevapları burada önermek çok daha basit bir yaklaşım var, niliçinde viewControllerBeforeve viewControllerAfterdataSource geri aramaları.

Bu, iOS 11+ cihazlarda kaydırma hareketini devre dışı bırakırken, dataSource( sayfa göstergesi için kullanılan presentationIndex/ gibi şeyler için) kullanma olasılığını korurkenpresentationCount

Ayrıca, üzerinden navigasyonu devre dışı bırakır. pageControl(alt noktalar)

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

@ User2159978'in C # yanıtını çeviriyor:

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

-1

(Swift 4) pageViewController cihazınızın jestRecognizer'larını kaldırabilirsiniz:

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

Uzantıyı tercih ederseniz:

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

ve pageViewController.removeGestureRecognizers


-1

Bunu şu şekilde ilan edin:

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

O zaman şu şekilde kullanın:

scrollView?.isScrollEnabled = true //false

-1

UIPageViewControllerSayfa denetleyicisi alt sınıfımda herhangi bir scrollView bulamadığım için, bir scrollView öğesini bulmak için alt görünümleri numaralandırmak işe yaramadı. Bu yüzden yapmayı düşündüğüm şey, hareket tanıyıcıları devre dışı bırakmak, ancak gerekli olanları devre dışı bırakmamak için yeterince dikkatli olmaktı.

Ben de şunu buldum:

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

Bunu içine koyun viewDidLoad()ve hazırsınız!


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

    }
}

Bunu, pageviewcontroller sınıfınıza ekleyin. % 100 çalışıyor


lütfen bu kodun mükemmel çalıştığı sorunu
açıklayın

-1

sadece bu kontrol özelliğini UIPageViewController alt sınıfınıza ekleyin :

var isScrollEnabled = true {
    didSet {
        for case let scrollView as UIScrollView in view.subviews {
            scrollView.isScrollEnabled = isScrollEnabled
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.