CNContactViewController'da iOS 13.1'de klavye yer paylaşımlı eylem sayfası


12

CNContactViewController'da kişi eklemek için iOS 13.0 ve önceki sürümlerde beklendiği gibi çalıştığı için bu iOS 13.1'e özgü gibi görünüyor, eğer 'İptal' yaparsam, eylem sayfası klavye ile çakışıyor. Hiçbir eylem gerçekleştirilmez ve klavye işten çıkarılmaz.

Yanıtlar:


5

Kudos @GxocT için büyük bir geçici çözüm! Kullanıcılarıma son derece yardımcı oldu.
Ama bu senaryoda başkalarına yardımcı olacağını umarak kodumu @GxocT çözümüne dayalı olarak paylaşmak istedim.

Benim CNContactViewControllerDelegate contactViewController(_:didCompleteWith:)iptal çağrılması gerekiyordu (hem de yapılır).

Ayrıca benim kod bir değildi UIViewControllerbu yüzden hiçbirself.navigationController

Ben de yardımcı olabilir zaman kuvvet çözme kullanmak gibi değil. Ben geçmişte ısırıldı bu yüzden if letkurulumda zincirleme

İşte yaptım:

  1. CNContactViewControllerSwizzle fonksiyonunu uzatın ve
    oraya yerleştirin.

  2. Swizzle işlevinde Benim durumumda sadece aramak
    CNContactViewControllerDelegatetemsilci
    contactViewController(_:didCompleteWith:)ile selfve
    self.contactkontak kontrolörü nesneyi

  3. Kurulum kodunda, sınıfı class_getInstanceMethodbelirtmek için swizzleMethod çağrısının CNContactViewControllerself

Ve Swift kodu:

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

Klavye hala kısa bir süre için görüntüleniyor ancak Kişiler denetleyicisi kapatıldıktan hemen sonra düşüyor.
Umarım elma bunu düzeltir


zorlama kodları kompakt yapmak için kullanılır elbette eğer mümkünse kaçınmalısınız ve çökmeye neden olabilir. btw delege için self.contact iletmenin doğru olup olmadığından emin değilim, çünkü akışı iptal ederseniz muhtemelen oluşturulmaz çünkü ps: kuvvet
açılmaları

@GxocT - kuvvet urwraps üzerinde anlaştı. Ve her zaman korkunç değiller ama diğerleri sizin gibi değil ve riski fark etmeden her zaman kullanabilirler;). Yerine izin verirseniz seviyorum! % 100 olmadığımda nil olmayacağından emin değilim. Self.contact hakkında - onun gerçek Ben Apple'ın lib kodu normalde delege dahili olarak ne geçti bilmiyorum ama self.contact iletişim verileri vardı ve CNContactViewController doc "iletişim görüntüleniyor" olduğunu söylüyor, bu yüzden kullanmak için Tamam görünüyordu. Benim kod aslında tamamlama temsilci geçti iletiyi kullanmaz, bu yüzden sadece uzantı nil geçebilir.
Barrett

CNContactViewController'daki içerikler (metin görünümleri ve klavyeler dahil) ayrı bir işlemde olmalıdır. Bu görünüm denetleyicisi için Xcode'da 'Hiyerarşiyi Görüntüle' seçeneğini kullanabiliyorsanız, içeriklerin görülemediğini görebilirsiniz. Sonuç olarak, klavyeyi veya metin görünümünü kontrol edemiyoruz.
WildCat

5

Klavyeyi kapatmanın bir yolunu bulamadım. Ama en azından benim yöntemini kullanarak ViewController pop.

  1. Neden bilmiyorum ama CNContactViewController klavyeyi kapatmak imkansız. Ben endEditing denedim :, yeni UITextField firstResponder ve benzeri yapmak. Hiçbir şey işe yaramadı.
  2. "İptal" düğmesi için işlemi değiştirmeye çalıştım. Bu düğmeyi NavigationController yığınında bulabilirsiniz, ancak her şey yazışınızda eylem değiştirilir.
  3. Sonunda yöntem swizzling kullandım. Daha önce de belirttiğim gibi klavyeyi kapatmanın bir yolunu bulamadım, ancak en azından "Cancel" (İptal) düğmesine basıldığında CNContactViewController'ı kapatabilirsiniz.
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)
        }
    }
}

Not: Reddit konusunda ek bilgi bulabilirsiniz: https://www.reddit.com/r/swift/comments/dc9n3a/bug_with_cnviewcontroller_ios_131/


2

Kullanıcı aslında klavyeyi kapatmak için aşağı hızlıca kaydırabilir ve ardından İptal'e dokunup işlem sayfasını görebilir. Yani bu sorun üzücü ve kesinlikle bir hata (ve bir hata raporu dosyaladım) ama ölümcül değil (emin olmak için, geçici çözüm kullanıcının keşfetmesi için önemsiz değildir).

resim açıklamasını buraya girin


Dosyaladığınız hata raporuna bağlantı verebilir misiniz?
Paaske


1

@Gxoct'a mükemmel çalışması için teşekkürler . Bu çalışanlar için çok yararlı bir soru ve yazı olduğunu düşünüyorum CNContactViewController. Ben de (şimdiye kadar) bu sorunu yaşadım ama hedef c. Yukarıdaki Swift kodunu objektif c olarak yorumluyorum.

- (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);
    }
}

CNContactViewControllerİşten çıkarmaya erişmek için bir kategori oluşturma ;

@implementation CNContactViewController (Test)

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

@end

Swizzling çok aşina olmayan adamlar bunu deneyebilirsiniz yazı mat tarafından


0

Geçici çözümünüz için teşekkürler, @GxocT, burada yayınlanan çözüm Reddit'te yayınladığınız çözümden farklıdır.

Reddit'teki benim için çalışıyor, bu öyle değil, burada yeniden yayınlamak istiyorum. Fark, olması gereken swizzledMethod ile doğrudur:

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

Güncellenen kodun tamamı:

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