2016-05-13 31 views
7

Abbiamo riscontrato questo problema quando si implementa il licenziamento interattivo di un controller di visualizzazione modale (trascinando il modale verso il basso dovrebbe chiuderlo) tramite UIPercentDrivenInteractiveTransition.Errore durante la rimozione interattiva del modal

Setup:

  1. configurazione UIViewController incorporato in UINavigationController con almeno un pulsante nella UINavigationBar
  2. modale presentare un altro UIViewController incorporato in UINavigationController con almeno un pulsante nella UINavigationBar
  3. configurazione UIPanGestureRecognizer su modaly presentato UINavigationController per guidare UIPercentDrivenInteractiveTransition
  4. trascinamento modale wn "holding" che dal punto UINavigationBar

di Interesse:

  • mentre lentamente trascinando verso il basso, glitch animazione causando vista modale a saltare su e giù

  • problema tecnico appare solo quando:

    1. entrambi UINavigationBar s hanno almeno un pulsante su di essi
    2. si "Hold" modale il punto sulla UINavigationBar

Esempio minimo può essere scaricato dal github repo.

Qualcuno si è imbattuto in un problema simile? Ci sono soluzioni alternative? C'è qualche difetto nella nostra configurazione?

Aggiornamento

problema è stato simulato a correre progetto di cui sopra su iPhone 5 simulatore con iOS 9.3, OSX 10.11.4, compilato con Xcode 7.3.1.

Update 2

Ulteriori indagini hanno dimostrato, che il problema non è probabilmente in animazione: Per qualche motivo in data configurazione pan.translationInView(view) sta tornando valori imprevisti che fa sì che l'animazione per saltare.

soluzione parziale

da un'idea di Vladimir abbiamo parzialmente risolto il problema ridefinendo hitTest metodo UINavigationBar:

class DraggableNavigationBar: UINavigationBar { 

    override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 
     guard let view = super.hitTest(point, withEvent: event) else { return nil } 

     if view is UIControl || pointIsInsideNavigationButton(point) { 
      return view 
     } else { 
      return nil 
     } 
    } 

    private func pointIsInsideNavigationButton(point: CGPoint) -> Bool { 
     return subviews 
      .filter { $0.frame.contains(point) } 
      .filter { String($0.dynamicType) == "UINavigationItemButtonView" } 
      .isEmpty == false 
    } 
} 
+0

Lavori per me. Non riesco a vedere nessun problema sul mio iPhone 6 o su iOS Simulator per iPhone 6. –

+0

NESSUN problema nel codice precedente.lavoro come charms – iMHitesh

+0

può condividere il problema esatto con me.Quale tipo di OS e versione xCode e target di implementazione ecc. – iMHitesh

risposta

1

Glitch molto interessante. Ho trovato una soluzione parziale di questo problema pochi giorni fa, e poiché nessuno ha trovato una soluzione completa, pubblicherò questo, forse sarà utile.

In caso di superamento hitTest metodo UINavigationBar si può sbarazzarsi di questo problema quando si trascina modale aggrappandosi UINavigationBar:

extension UINavigationBar { 

    override public func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 

     guard let view = super.hitTest(point, withEvent: event) else { return nil } 

     if view.isKindOfClass(UIControl) { 
      return super.hitTest(point, withEvent: event) 
     } else { 
      return nil 
     } 
    } 
} 

Purtroppo se si trascina modale aggrappandosi UIBarButtonItem su UINavigationBar, impulso errato essere ancora presenti .

Puoi anche provare un altro approccio.

Come notato, pan.translationInView(view) restituisce valori errati che fanno saltare l'animazione. È necessario confrontare questo valore con la coordinata della vista modale durante il trascinamento. È possibile ottenere questo valore controllando presentazione strato di controller di vista modale:

... 

let translation = pan.translationInView(view) 

if let layer = view.layer.presentationLayer() { 
      print(layer.frame.origin.y) 
} 

... 

Si può vedere che quando pan.translationInView(view) inizia a mostrare un valore errato, layer.frame.origin.y ancora sarà corretto in quel momento. È possibile confrontare questi due valori e trovare il modello quando il valore non è corretto e modificarlo per correggere aggiungendo alcuni punti al valore translation.y.

+0

Grazie per l'idea! Ho finito col sovrascrivere 'hitTest', ma ho anche permesso di toccare i pulsanti indietro (sorprendentemente non sono' UIControl'). Reagire alla differenza di 'translation' e' presentationLayer' sarebbe abbastanza complicato, in quanto uno dovrebbe tenere conto di diverse velocità di trascinamento e cambi di direzione. –

0

Non ho una soluzione completa, ma sono stato in grado di ridurre la problema tecnico di una certa quantità.Ho potuto riprodurre il problema su iPhone 5s con iOS 9.3.2 [trascinando verso il basso dello schermo tenendo barra di navigazione]

Il problema sembra essere nel blocco di UIView.animateWithDurationDismissalAnimator. Commentando il ritardo e le opzioni per mantenerle ai valori predefiniti, è possibile ridurre il salto della vista. Si potrebbe anche provare a verificare per diffrent UIViewAnimationOptions per il quale si ottiene il salto minimo.

UIView.animateWithDuration(0.3, 
     animations: { 
      dismissedView.frame = finalFrame 
     }, 
     completion: { _ in 
      let didComplete = !transitionContext.transitionWasCancelled() 
      transitionContext.completeTransition(didComplete) 
     } 
    ) 

C'è a question che sembra avere a che fare con lo stesso problema che si trovano ad affrontare. E le risposte variano dalla disattivazione del layout automatico, mettendo layoutIfNeeded nel blocco di animazione [provato, entrambi non hanno funzionato].

+0

Grazie per il suggerimento. Tuttavia, la modifica di '.CurveLinear' fa sì che l'animazione si desincronizzi dal movimento delle dita. Inoltre, data la specificità del problema (pulsanti in "UINavigationBar", trascinamento per punto in "UINavigationBar") non penso che la domanda collegata sia correlata, ma la verificherò. –

Problemi correlati