Lembar tindakan overlay keyboard di iOS 13.1 di CNContactViewController


12

Ini tampaknya khusus untuk iOS 13.1, karena berfungsi seperti yang diharapkan pada iOS 13.0 dan versi sebelumnya untuk menambahkan kontak di CNContactViewController, jika saya 'Batal', lembar tindakan tumpang tindih dengan keyboard. Tidak ada tindakan yang dilakukan dan keyboard tidak menolak.

Jawaban:


5

Kudos to @GxocT untuk solusi hebatnya! Sangat membantu pengguna saya.
Tapi saya ingin membagikan kode saya berdasarkan solusi @GxocT dengan harapan itu akan membantu orang lain dalam skenario ini.

Saya perlu saya CNContactViewControllerDelegate contactViewController(_:didCompleteWith:)dipanggil batal (dan juga dilakukan).

Juga kode saya tidak dalam UIViewControllersehingga tidak adaself.navigationController

Saya juga tidak suka menggunakan kekuatan membuka ketika saya bisa membantu. Saya telah digigit di masa lalu jadi saya dirantai if letdi setup

Inilah yang saya lakukan:

  1. Perpanjang CNContactViewControllerdan letakkan fungsi swizzle di
    sana.

  2. Dalam kasus saya dalam fungsi swizzle panggil saja
    CNContactViewControllerDelegatedelegasi
    contactViewController(_:didCompleteWith:)dengan selfdan
    self.contactobjek dari pengontrol kontak

  3. Dalam kode pengaturan, pastikan panggilan swizzleMethod untuk class_getInstanceMethodmenentukan CNContactViewController kelas, bukanself

Dan kode Swift:

class MyClass: CNContactViewControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.changeImplementation()
    }

    func changeCancelImplementation() {

        let originalSelector = Selector(("editCancel:"))
        let swizzledSelector = #selector(CNContactViewController.cancelHack)

        if let originalMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), originalSelector),
           let swizzledMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), swizzledSelector) {

            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }

   func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
       // dismiss the contacts controller as usual
       viewController.dismiss(animated: true, completion: nil)
       // do other stuff when your contact is canceled or saved
       ...
    }
}

extension CNContactViewController {
    @objc func cancelHack()  {
        self.delegate?.contactViewController?(self, didCompleteWith: self.contact)
    }
}

Keyboard masih muncul sesaat tetapi turun tepat setelah pengontrol Kontak ditolak.
Mari berharap apel memperbaikinya


buka paksa digunakan untuk membuat kode kompak tentu saja Anda harus menghindarinya jika mungkin dan jika itu dapat menyebabkan crash. btw saya tidak yakin apakah itu benar untuk lulus self.contact untuk mendelegasikan, karena itu mungkin tidak dibuat jika Anda membatalkan aliran ps: mengubah implementasi saya untuk menghindari membuka paksa: D
GxocT

@GxocT - menyetujui kekuatan urwraps. Dan mereka tidak selalu mengerikan tetapi orang lain tidak seperti Anda dan mungkin selalu menggunakannya tanpa menyadari risikonya;). Saya suka jika biarkan saja! ketika saya tidak 100% yakin itu tidak akan menjadi nol. Tentang self.contact - sejatinya saya tidak tahu kode lib Apple yang biasanya dikirimkan ke delegasi secara internal tetapi self.contact memiliki data kontak dan dokumen CNContactViewController mengatakan ini adalah "kontak yang ditampilkan" sehingga sepertinya tidak masalah untuk digunakan. Kode saya tidak benar-benar menggunakan kontak yang diteruskan dalam delegasi penyelesaian jadi saya hanya bisa meneruskan nol di ekstensi.
Barrett

Konten (termasuk tampilan teks dan keyboard) di CNContactViewController harus dalam proses terpisah. Jika Anda dapat menggunakan 'Lihat Hierarki' di Xcode untuk pengontrol tampilan ini, Anda mungkin menemukan konten tidak dapat dilihat. Akibatnya, kami tidak dapat mengontrol keyboard atau tampilan teks.
WildCat

5

Saya tidak dapat menemukan cara untuk mengabaikan keyboard. Tapi setidaknya Anda bisa memunculkan ViewController menggunakan metode saya.

  1. Tidak tahu mengapa tetapi tidak mungkin untuk mengabaikan keyboard di CNContactViewController. Saya mencoba endEditing :, buat UITextField baru firstResponder dan sebagainya. Tidak ada yang berhasil.
  2. Saya mencoba mengubah tindakan untuk tombol "Batal". Anda dapat menemukan tombol ini di tumpukan NavigationController, Tapi tindakannya berubah setiap kali Anda mengetik sesuatu.
  3. Akhirnya saya menggunakan metode swizzling. Saya tidak dapat menemukan cara untuk mengabaikan keyboard seperti yang saya sebutkan sebelumnya, tetapi setidaknya Anda dapat mengabaikan CNContactViewController ketika tombol "Cancel" ditekan.
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        changeImplementation()
    }

    @IBAction func userPressedButton(_ sender: Any) {
        let controller = CNContactViewController(forNewContact: nil)
        controller.delegate = self
        navigationController?.pushViewController(controller, animated: true)
    }

    @objc func popController() {
        self.navigationController?.popViewController(animated: true)
    }

    func changeImplementation() {
        let originalSelector = Selector("editCancel:")
        let swizzledSelector = #selector(self.popController)

        if let originalMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), originalSelector),
            let swizzledMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), swizzledSelector) {

            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
}

PS: Anda dapat menemukan info tambahan tentang topik reddit: https://www.reddit.com/r/swift/comments/dc9n3a/bug_with_cnviewcontroller_ios_131/


2

Pengguna sebenarnya dapat menggesek ke bawah untuk mengabaikan keyboard dan kemudian ketuk Batalkan dan lihat lembar tindakan. Jadi masalah ini disesalkan dan jelas merupakan bug (dan saya telah mengajukan laporan bug) tetapi tidak berakibat fatal (meskipun, untuk memastikan, solusi tidak sepele bagi pengguna untuk menemukan).

masukkan deskripsi gambar di sini


Bisakah Anda menautkan ke laporan bug yang Anda ajukan?
Paaske


1

Terima kasih @Gxoct untuk pekerjaannya yang luar biasa. Saya pikir ini adalah pertanyaan & posting yang sangat berguna bagi mereka yang bekerja dengannya CNContactViewController. Saya juga punya masalah ini (sampai sekarang) tetapi dalam tujuan c. Saya mengartikan kode Swift di atas menjadi objektif c.

- (void)viewDidLoad {
    [super viewDidLoad];
    Class class = [CNContactViewController class];

    SEL originalSelector = @selector(editCancel:);
    SEL swizzledSelector = @selector(dismiss); // we will gonna access this method & redirect the delegate via this method

    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

    BOOL didAddMethod =
        class_addMethod(class,
            originalSelector,
            method_getImplementation(swizzledMethod),
            method_getTypeEncoding(swizzledMethod));

    if (didAddMethod) {
        class_replaceMethod(class,
            swizzledSelector,
            method_getImplementation(originalMethod),
            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

Membuat CNContactViewControllerkategori untuk mengakses pemberhentian;

@implementation CNContactViewController (Test)

- (void) dismiss{
    [self.delegate contactViewController:self didCompleteWithContact:self.contact];
}

@end

Orang-orang yang tidak begitu terbiasa dengan Swizzling, Anda dapat mencoba posting ini oleh matt


0

Terima kasih, @GxocT atas solusi Anda, namun, solusi yang diposting di sini berbeda dari yang Anda posting di Reddit.

Yang ada di Reddit bekerja untuk saya, yang ini tidak jadi saya ingin memposting ulang di sini. Perbedaannya ada pada baris dengan metode swizzled yang seharusnya:

   let swizzledMethod = class_getInstanceMethod(object_getClass(self), swizzledSelector) {

Seluruh kode yang diperbarui adalah:

class MyClass: CNContactViewControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.changeImplementation()
    }

    func changeCancelImplementation() {

        let originalSelector = Selector(("editCancel:"))
        let swizzledSelector = #selector(CNContactViewController.cancelHack)

        if let originalMethod = class_getInstanceMethod(object_getClass(CNContactViewController()), originalSelector),
           let swizzledMethod = class_getInstanceMethod(object_getClass(self), swizzledSelector) {

            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }

   func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) {
       // dismiss the contacts controller as usual
       viewController.dismiss(animated: true, completion: nil)
       // do other stuff when your contact is canceled or saved
       ...
    }
}

extension CNContactViewController {
    @objc func cancelHack()  {
        self.delegate?.contactViewController?(self, didCompleteWith: self.contact)
    }
}
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.