Hoja de acción de superposición de teclado en iOS 13.1 en CNContactViewController
12
Esto parece ser específico para iOS 13.1, ya que funciona como se esperaba en iOS 13.0 y versiones anteriores para agregar un contacto en CNContactViewController, si 'Cancelar', la hoja de acción se superpone con el teclado. No se realizan acciones y el teclado no se descarta.
¡Felicitaciones a @GxocT por la gran solución! Ayudé a mis usuarios inmensamente.
Pero quería compartir mi código basado en la solución @GxocT con la esperanza de que ayude a otros en este escenario.
Necesitaba que me CNContactViewControllerDelegatecontactViewController(_:didCompleteWith:)llamaran para cancelar (y listo).
Además, mi código no estaba en un, UIViewControllerasí que no hayself.navigationController
Tampoco me gusta usar desenvolturas forzadas cuando puedo evitarlo. He sido mordido en el pasado, así que encadené if lets en la configuración
Esto es lo que hice:
Extienda CNContactViewControllery coloque la función swizzle
allí.
En mi caso, en la función swizzle simplemente llame al CNContactViewControllerDelegatedelegado contactViewController(_:didCompleteWith:)con selfy self.contactobjeto desde el controlador de contacto
En el código de configuración, asegúrese de que la llamada swizzleMethod
class_getInstanceMethodespecifique la CNContactViewController
clase en lugar deself
Y el código Swift:
classMyClass:CNContactViewControllerDelegate{overridefunc viewDidLoad(){super.viewDidLoad()self.changeImplementation()}func changeCancelImplementation(){let originalSelector =Selector(("editCancel:"))let swizzledSelector =#selector(CNContactViewController.cancelHack)iflet 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
...}}extensionCNContactViewController{@objc func cancelHack(){self.delegate?.contactViewController?(self, didCompleteWith:self.contact)}}
El teclado todavía se muestra momentáneamente pero se cae justo después de que el controlador de Contactos se desconecta.
Esperemos que Apple arregle esto
los desenvolvimientos forzados se utilizan para hacer el código compacto, por supuesto, debe evitarlos si es posible y si puede provocar un bloqueo. por cierto, no estoy seguro de si es correcto pasar self.contact para delegar, porque probablemente no se crea si cancela el flujo ps: cambió mi implementación para evitar desenredos
forzados
@GxocT - acordado en la fuerza urwraps. Y no siempre son terribles, pero otros no son como usted y siempre pueden usarlos sin darse cuenta del riesgo;). Me gusta si deja en lugar de! cuando no estoy 100% seguro de que no será nulo. Acerca de self.contact: es cierto. No sé qué código lib de Apple normalmente pasa al delegado internamente, pero self.contact tenía los datos de contacto y el documento CNContactViewController dice que es "el contacto que se muestra", por lo que parecía correcto usarlo. Mi código en realidad no usa el contacto pasado en el delegado de finalización, por lo que podría pasar cero en la extensión.
Barrett
El contenido (incluyendo vistas de texto y teclados) en CNContactViewController debe estar en un proceso separado. Si puede usar 'Ver jerarquía' en Xcode para este controlador de vista, puede encontrar que el contenido no se puede ver. Como resultado, no podemos controlar el teclado ni la vista de texto.
WildCat
5
No pude encontrar una manera de descartar el teclado. Pero al menos puedes hacer estallar ViewController usando mi método.
No sé por qué, pero es imposible descartar el teclado en CNContactViewController. Intenté endEditing :, hacer nuevo UITextField firstResponder y así sucesivamente. Nada funcionó.
Traté de alterar la acción para el botón "Cancelar". Puede encontrar este botón en la pila NavigationController, pero su acción cambia cada vez que escribe algo.
Finalmente utilicé el método swizzling. No pude encontrar una manera de descartar el teclado como mencioné anteriormente, pero al menos puede descartar CNContactViewController cuando se presiona el botón "Cancelar".
De hecho, el usuario puede deslizar hacia abajo para cerrar el teclado y luego tocar Cancelar y ver la hoja de acción. Por lo tanto, este problema es lamentable y definitivamente es un error (y he presentado un informe de error) pero no fatal (aunque, para estar seguro, la solución no es trivial para que el usuario la descubra).
Gracias @Gxoct por su excelente trabajo. Creo que esta es una pregunta y publicación muy útil para quienes están trabajando CNContactViewController. También tuve este problema (hasta ahora) pero en el objetivo c. Interpreto el código Swift anterior en el objetivo c.
-(void)viewDidLoad {[super viewDidLoad];Classclass=[CNContactViewControllerclass];
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);}}
Crear una CNContactViewControllercategoría para acceder al despido;
Gracias, @GxocT por su solución, sin embargo, la solución publicada aquí es diferente de la que publicó en Reddit.
El de Reddit funciona para mí, este no lo hace, así que quiero volver a publicarlo aquí. La diferencia está en la línea con swizzledMethod, que debería ser:
let swizzledMethod = class_getInstanceMethod(object_getClass(self), swizzledSelector){
Todo el código actualizado es:
classMyClass:CNContactViewControllerDelegate{overridefunc viewDidLoad(){super.viewDidLoad()self.changeImplementation()}func changeCancelImplementation(){let originalSelector =Selector(("editCancel:"))let swizzledSelector =#selector(CNContactViewController.cancelHack)iflet 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
...}}extensionCNContactViewController{@objc func cancelHack(){self.delegate?.contactViewController?(self, didCompleteWith:self.contact)}}
No pude encontrar una manera de descartar el teclado. Pero al menos puedes hacer estallar ViewController usando mi método.
PD: Puede encontrar información adicional sobre el tema de reddit: https://www.reddit.com/r/swift/comments/dc9n3a/bug_with_cnviewcontroller_ios_131/
fuente
De hecho, el usuario puede deslizar hacia abajo para cerrar el teclado y luego tocar Cancelar y ver la hoja de acción. Por lo tanto, este problema es lamentable y definitivamente es un error (y he presentado un informe de error) pero no fatal (aunque, para estar seguro, la solución no es trivial para que el usuario la descubra).
fuente
Corregido en iOS 13.4 Probado en Xcode Simulator
fuente
Gracias @Gxoct por su excelente trabajo. Creo que esta es una pregunta y publicación muy útil para quienes están trabajando
CNContactViewController
. También tuve este problema (hasta ahora) pero en el objetivo c. Interpreto el código Swift anterior en el objetivo c.Crear una
CNContactViewController
categoría para acceder al despido;Chicos que no están tan familiarizados con Swizzling, pueden probar esta publicación de matt
fuente
Gracias, @GxocT por su solución, sin embargo, la solución publicada aquí es diferente de la que publicó en Reddit.
El de Reddit funciona para mí, este no lo hace, así que quiero volver a publicarlo aquí. La diferencia está en la línea con swizzledMethod, que debería ser:
Todo el código actualizado es:
fuente