it-swarm-id.com

Pengenal Gerakan UIPageViewController

Saya sudah mengerjakan aplikasi untuk sementara waktu sekarang, tetapi saya tidak bisa mengajukan pertanyaan ini karena NDA. 

Saya memiliki beban UIPageViewController dengan Viewcontroller saya. Pengontrol tampilan memiliki tombol yang diganti oleh pengenal isyarat PageViewControllers. Misalnya saya memiliki tombol di sisi kanan viewcontroller dan ketika Anda menekan tombol, PageViewController mengambil alih dan mengubah halaman.

Bagaimana saya bisa membuat tombol menerima sentuhan dan membatalkan pengenal gesture di PageViewController?

Saya pikir PageViewController membuat ViewController saya menjadi subview dari pandangannya.

Saya tahu saya bisa mematikan semua Gestures, tetapi ini bukan efek yang saya cari.

Saya akan lebih suka tidak mensubclass PageViewController karena Apple mengatakan kelas ini tidak dimaksudkan untuk subkelas. 

54
Rich86man

Anda bisa mengganti 

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
 shouldReceiveTouch:(UITouch *)touch

untuk kontrol yang lebih baik ketika PageViewController harus menerima sentuhan dan tidak. Lihatlah "Mencegah Pengenalan Gerakan dari Menganalisis Sentuhan" di Dev Pengenal Gerakan Isyarat

Solusi saya terlihat seperti ini di RootViewController untuk UIPageViewController:

Di viewDidLoad:

//EDITED Need to take care of all gestureRecogizers. Got a bug when only setting the delegate for Tap
for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
    gR.delegate = self;
}

Timpa:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    //Touch gestures below top bar should not make the page turn.
    //EDITED Check for only Tap here instead.
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        CGPoint touchPoint = [touch locationInView:self.view];
        if (touchPoint.y > 40) {
            return NO;
        }
        else if (touchPoint.x > 50 && touchPoint.x < 430) {//Let the buttons in the middle of the top bar receive the touch
            return NO;
        }
    }
    return YES;
}

Dan jangan lupa untuk mengatur RootViewController sebagai UIGestureRecognizerDelegate.

(FYI, aku hanya dalam mode Lansekap.)

EDIT - Kode di atas diterjemahkan ke dalam Swift 2:

Di viewDidLoad:

for gr in self.view.gestureRecognizers! {
    gr.delegate = self
}

Buat pengontrol tampilan halaman mewarisi UIGestureRecognizerDelegate lalu tambahkan:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if let _ = gestureRecognizer as? UITapGestureRecognizer {
        let touchPoint = touch .locationInView(self.view)
        if (touchPoint.y > 40 ){
            return false
        }else{
            return true
        }
    }
    return true
}
50
jramer

Berikut ini adalah solusi lain, yang dapat ditambahkan di viewDidLoad template tepat setelah bagian self.view.gestureRecognizers = self.pageViewController.gestureRecognizers dari template Xcode. Itu menghindari mengacaukan nyali dari pengenal isyarat atau berurusan dengan delegasinya. Itu hanya menghapus pengenal isyarat tap dari tampilan, hanya menyisakan pengenal gesek. 

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

// Find the tap gesture recognizer so we can remove it!
UIGestureRecognizer* tapRecognizer = nil;    
for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) {
    if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
        tapRecognizer = recognizer;
        break;
    }
}

if ( tapRecognizer ) {
    [self.view removeGestureRecognizer:tapRecognizer];
    [self.pageViewController.view removeGestureRecognizer:tapRecognizer];
}

Sekarang untuk beralih antar halaman, Anda harus menggesek. Taps sekarang hanya bekerja pada kontrol Anda di atas tampilan halaman (yang saya cari).

54
Pat McG

Saya memiliki masalah yang sama. Sampel dan dokumentasi melakukan ini di loadView atau viewDidLoad:

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

Ini menggantikan pengenal gesture dari tampilan UIViewControllers dengan gestureRecognizers dari UIPageViewController. Sekarang ketika sentuhan terjadi, mereka pertama-tama dikirim melalui pengenal isyarat pageViewControllers - jika tidak cocok, mereka dikirim ke subview.

Batalkan komentar pada garis itu, dan semuanya berfungsi seperti yang diharapkan.

Phillip

4
Phillip

Mengatur delegasi gestureRecognizers ke viewController seperti di bawah ini tidak lagi berfungsi pada ios6

for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
    gR.delegate = self;
}

Di ios6, mengatur delegasi gestureRecognizers pageViewController Anda ke viewController menyebabkan kerusakan

3
noRema

Saya menggunakan 

for (UIScrollView *view in _pageViewController.view.subviews) {
    if ([view isKindOfClass:[UIScrollView class]]) {
        view.delaysContentTouches = NO;
    }
}

untuk memungkinkan klik melalui tombol di dalam UIPageViewController

2
Adam Johns

Jika Anda menggunakan tombol yang telah disubklasifikasikan, Anda dapat mengesampingkan sentuhan. Mulai, sentuh, Pindahkan, dan sentuh. Ujung, gunakan halaman programatik Anda sendiri jika perlu tetapi tidak memanggil super dan meneruskan sentuhan ke atas rantai notifikasi. 

0
isaac

Saya membuat pengontrol tampilan halaman secara teratur saat pengguna saya melompat, menggulung, dan menggeser ke berbagai tampilan halaman yang berbeda. Dalam rutin yang membuat pageviewcontroller baru, saya menggunakan versi yang lebih sederhana dari kode yang sangat baik seperti ditunjukkan di atas:

UIPageViewController *npVC = [[UIPageViewController alloc]
                       initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
                       navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
                       options: options];
...

// Find the pageView tap gesture recognizer so we can remove it!
for (UIGestureRecognizer* recognizer in npVC.gestureRecognizers) {
    if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
        UIGestureRecognizer* tapRecognizer = recognizer;
        [npVC.view removeGestureRecognizer:tapRecognizer];
       break;
    }
}

Sekarang keran bekerja seperti yang saya inginkan (dengan keran kiri dan kanan melompat halaman, dan ikal bekerja dengan baik.

0
Bill Cheswick

Dalam kasus saya, saya ingin menonaktifkan ketukan pada UIPageControl dan membiarkan ketukan diterima oleh tombol lain di layar. Gesek masih berfungsi. Saya telah mencoba berbagai cara dan saya percaya itu adalah solusi kerja yang paling sederhana:

for (UIPageControl *view in _pageController.view.subviews) {
    if ([view isKindOfClass:[UIPageControl class]]) {
        view.enabled = NO;
    }
}

Ini mendapatkan tampilan UIPageControl dari subview UIPageController dan menonaktifkan interaksi pengguna.

0
Leto Baxevanaki

Cukup buat subview (ditautkan dengan IBOutlet gesturesView baru) di RootViewController Anda dan tetapkan gerakan untuk tampilan baru ini. Tampilan ini mencakup bagian layar yang Anda inginkan untuk mengaktifkan gerakan.

dalam perubahan viewDidLoad:

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

untuk:

self.gesturesView.gestureRecognizers = self.pageViewController.gestureRecognizers;
0
tdf

Ekstensi Swift 3 untuk menghapus pengenalan keran:

    import UIKit

extension UIPageViewController {
    func removeTapRecognizer() {
        let gestureRecognizers = self.gestureRecognizers

        var tapGesture: UIGestureRecognizer?
        gestureRecognizers.forEach { recognizer in
            if recognizer.isKind(of: UITapGestureRecognizer.self) {
                tapGesture = recognizer
            }
        }
        if let tapGesture = tapGesture {
            self.view.removeGestureRecognizer(tapGesture)
        }
    }
}
0
Roman Barzyczak

Ini adalah solusi yang bekerja paling baik untuk saya. Saya mencoba jawaban JRAMER baik-baik saja kecuali saya akan mendapatkan Kesalahan ketika paging melampaui batas (halaman -1 atau halaman 23 untuk saya) 

Solusi PatMCG tidak memberi saya cukup fleksibilitas karena membatalkan semua taprecognizers, saya masih menginginkan keran tetapi tidak dalam label saya

Dalam UILabel saya, saya hanya mengesampingkan sebagai berikut, ketukan yang dibatalkan untuk label saya saja

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
 if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
     return NO;
 } else {
     return YES;
 }
}
0
Ryan Heitner

Saya mencari solusi yang berhasil. Tambahkan UIGestureRecognizer lain ke UIPageViewController dan terapkan metode pendelegasian yang disediakan di bawah ini ... Pada setiap saat Anda harus menyelesaikan gerakan mana yang harus dikunci atau diteruskan lebih jauh, metode ini akan dipanggil. Ingatlah untuk memberikan referensi ke confictingView, yang dalam kasus saya ini adalah UITableView, yang juga mengenali gerakan pan. Tampilan ini ditempatkan di dalam UIPageViewController, sehingga gerakan pan dikenali dua kali atau hanya secara acak. Sekarang dalam metode ini, saya memeriksa apakah gerakan pan ada di dalam UITableView dan UIPageViewController saya, dan saya memutuskan bahwa UIPanGestureRecognizer adalah yang utama.

Pendekatan ini tidak mengesampingkan langsung salah satu dari pengenal isyarat lain sehingga kami tidak perlu khawatir tentang 'NSInvalidArgumentException' yang disebutkan. 

Perlu diingat bahwa pola sebenarnya tidak disetujui oleh Apple :)

 var conflictingView:UIView?
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if otherGestureRecognizer.view === pageViewController?.view {

            if let view = conflictingView {
                var point = otherGestureRecognizer.location(in: self.view)
                if view.frame.contains(point) {
                    print("Touch in conflicting view")
                    return false
                }
            }
            print("Touch outside conficting view")
            return true
        }
        print("Another view passed out")
        return true
    }

Saya berakhir di sini sambil mencari cara sederhana dan mudah untuk merespons ketukan pada pengontrol tampilan anak saya di dalam UIPageViewController. Inti dari solusi saya (Swift 4, Xcode 9) akhirnya menjadi sesederhana ini, di RootViewController.Swift saya (struktur yang sama dengan templat "Aplikasi Berbasis Halaman" Xcode):

override func viewDidLoad() {
    super.viewDidLoad()

    ...

    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(pageTapped(sender:)))
    self.pageViewController?.view.subviews[0].addGestureRecognizer(tapGesture)
}

...

@objc func pageTapped(sender: UITapGestureRecognizer) {
    print("pageTapped")
}

(Saya juga memanfaatkan jawaban ini untuk membiarkan saya melacak halaman mana yang benar-benar disadap, yaitu yang saat ini.)

0
brookinc

Juga dapat menggunakan ini (terima kasih atas bantuannya, dengan mengatakan tentang delegasi):

// add UIGestureRecognizerDelegate

NSPredicate *tp = [NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [UITapGestureRecognizer class]];
UITapGestureRecognizer *tgr = (UITapGestureRecognizer *)[self.pageViewController.view.gestureRecognizers filteredArrayUsingPredicate:tp][0];
tgr.delegate = self; // tap delegating

NSPredicate *pp = [NSPredicate predicateWithFormat:@"self isKindOfClass: %@", [UIPanGestureRecognizer class]];
UIPanGestureRecognizer *pgr = (UIPanGestureRecognizer *)[self.pageViewController.view.gestureRecognizers filteredArrayUsingPredicate:pp][0];
pgr.delegate = self; // pan delegating

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
{
    CGPoint touchPoint = [touch locationInView:self.view];

    if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) && touchPoint.y > 915 ) {
        return NO; // if y > 915 px in portrait mode
    }

    if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) && touchPoint.y > 680 ) {
        return NO; // if y > 680 px in landscape mode
    }

    return YES;
}

Bekerja dengan baik untuk saya :)

0
iTux