11

Nota: Ho già controllato i seguenti problemi di overflow dello stack:UIView.animateWithDuration Non Animazione Swift (di nuovo)

27907570, 32229252, 26118141, 31604300

Tutto quello che sto cercando di fare è animato dissolvenza in una vista (di alfa) quando viene chiamata da una IBAction associata a un pulsante. Quindi invertire quando viene colpito un pulsante sulla vista.

La mia ruga potrebbe essere che sto usando una vista secondaria che si trova sul ViewDock nella visualizzazione dello storyboard. La vista viene aggiunta alla sottoview al momento di viewDidLoad, dove i frame/bounds sono impostati come il superview (per un layover completo)

Il motivo viene eseguito come visualizzazione overlay poiché è un indicatore tutorial .

Il risultato (come molti altri che hanno elencato questo problema) è che la vista (e controlli contenuti) appare semplicemente all'istante e scompare immediatamente. Niente sbiadire

Ho provato animationWithDuration con ritardo, con e senza completamento, con transizione, e anche iniziato con il vecchio UIView.beginAnimations.

Niente funziona. Suggerimenti calorosamente accolti

Il codice è quanto di più semplice come posso farlo:
Edit: ampliato il codice per tutto rilevanti
Edit2: TL; DR Tutto funziona con l'eccezione di UIViewAnimateWithDuration che sembra ignorare la blocco e durata e basta eseguire il codice in linea come modifica immediata dell'interfaccia utente. Risolvere questo ottiene la grazia

@IBOutlet var infoDetailView: UIView! // Connected to the view in the SceneDock 

override func viewDidLoad() { 
    super.viewDidLoad() 

    // Cut other vDL code that isn't relevant 

    setupInfoView() 
} 

func setupInfoView() { 
    infoDetailView.alpha = 0.0 
    view.addSubview(infoDetailView) 
    updateInfoViewRect(infoDetailView.superview!.bounds.size) 
} 

func updateInfoViewRect(size:CGSize) { 
    let viewRect = CGRect(origin: CGPointZero, size: size) 

    infoDetailView.frame = viewRect 
    infoDetailView.bounds = viewRect 

    infoDetailView.layoutIfNeeded() 
    infoDetailView.setNeedsDisplay() 
} 

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 
    updateInfoViewRect(size) 
} 

func hideInfoView() { 
    AFLog.enter(thisClass) 
    UIView.animateWithDuration(
     2.0, 
     animations: 
     { 
      self.infoDetailView.alpha = 0.0 
     }, 
     completion: 
     { (finished) in 
      return true 
     } 
    ) 
    AFLog.exit(thisClass) 
} 

func showInfoView() { 
    AFLog.enter(thisClass) 
    UIView.animateWithDuration(
     2.0, 
     animations: 
     { 
      self.infoDetailView.alpha = 0.75 
     }, 
     completion: 
     { (finished) in 
      return true 
     } 
    ) 
    AFLog.exit(thisClass) 
} 

// MARK: - IBActions 

@IBAction func openInfoView(sender: UIButton) { 
    showInfoView() 
} 

@IBAction func closeInfoView(sender: UIButton) { 
    hideInfoView() 
} 

Si prega di notare, ho iniziato con il seguente:

func showInfoView() { 
    UIView.animateWithDuration(2.0, animations: {() -> Void in 
     self.infoDetailView.alpha = 0.75 
    }) 
} 

func hideInfoView() { 
    UIView.animateWithDuration(2.0, animations: {() -> Void in 
     self.infoDetailView.alpha = 0.00 
    }) 
} 
+0

"La vista viene aggiunta alla vista secondaria al momento di viewDidLoad" <- vediamo questo codice. –

+1

FWIW, puoi passare 'nil' come blocchi di completamento qui. Anche se hai blocchi, certamente non dovrebbero restituire nulla. Sono sorpreso che il compilatore Swift non lo abbia contrassegnato come un errore. –

+0

@GrahamPerks, ho aggiunto tutto il codice pertinente sopra. L'ho provato con e senza il ritorno come mostrato nel codice fallito originale pre-ottimizzato. –

risposta

1

di questo codice:

UIView.animateWithDuration(0.3, animations: {() -> Void in 
    self.infoDetailView.alpha = 0.0 
}) 
+0

Questo era il punto in cui ho iniziato prima di apportare modifiche. Stesso effetto Non appare alcuna dissolvenza. –

1

ho replicato il codice e il lavoro bene, va tutto bene Probabilmente è necessario controllare i vincoli, le connessioni IBOutlet e IBActions. Prova a isolare questo codice in un nuovo progetto, se necessario.

Aggiornamento: my code e il mio storyboard e cartelle di progetto fotografico:

my storyboard and project folder photo

Ogni oggetto (vista e pulsanti) sono con le impostazioni predefinite.

enter image description here

Ho commentato tutte le linee AFLog (probabilmente è solo più "modalità dettagliata" per aiutarti a), il resto del codice è ok e fare ciò che si fa in aspetto da esso, se premi il pulsante di apertura per vedere la dissolvenza in apertura e quando tocchi il pulsante Chiudi la vista si dissolve.

PS Non rilevante, ma sto usando xCode 7.3, un nuovo progetto rapido 2.2.

+0

Alessandro, era il punto di vista che stai animando tratto dal dock della scena in cima alla scena dello storyboard? –

+0

La vista con sfondo verde è "infoDetailView", una vista aggiunta, nel mio esempio, al centro di una vista pulitaController e due pulsanti ... effettua tutte le connessioni (iboutlet e ibactions), imposta l'autolayout e funziona. –

+0

Ho aggiornato la mia risposta con il codice sorgente e lo storyboard, puoi iniziare un nuovo progetto e provarlo. –

8

Ci sono diverse cose strane che posso vedere,

prima, rimuovere:

infoDetailView.layoutIfNeeded() 
infoDetailView.setNeedsDisplay() 

Di solito non c'è bisogno di chiamare manualmente quei metodi se non si sa esattamente cosa si sta facendo.

Inoltre, quando si modifica la dimensione:

infoDetailView.frame = viewRect 
infoDetailView.bounds = viewRect 

hai mai bisogno di impostare sia bounds e frame. Basta impostare frame.

Inoltre, probabilmente si dovrebbe fare in modo che la vista in realtà non ignora il telaio impostando:

infoDetailView.translatesAutoresizingMaskIntoConstraints = true 

Invece di resettare il telaio, è sufficiente impostare AutoResize maschera:

infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] 

risultante in:

override func viewDidLoad() { 
    super.viewDidLoad() 

    // Cut other vDL code that isn't relevant 

    setupInfoView() 
} 

func setupInfoView() { 
    infoDetailView.alpha = 0.0 
    infoDetailView.translatesAutoresizingMaskIntoConstraints = true 
    infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] 
    infoDetailView.frame = view.bounds 
    view.addSubview(infoDetailView) 
} 

func hideInfoView() { 
    ... 
} 

Penso che questo dovrebbe effettivamente aiutare perché le animazioni immediate sono spesso collegato a problemi di dimensioni.

Se il problema persiste, è necessario verificare se lo dell'animazione è lo stesso dell'oggetto dello infoDetailView che si sta aggiungendo al controller.

+0

Sulthan, questo ha semplificato il codice in modo corretto, ma non ha influito sul problema di root dell'animazione. InfoDetailView viene dichiarato solo come mostrato sopra come IBOutlet per la vista che si trova sulla scena dock per la scena storyboard. Esistono potenziali alterni IB per la vista ancorata o la scena dello storyboard che potrebbe dover essere riparata? –

+0

@LordAndrei Non c'è nient'altro che non sia corretto con il tuo codice, quindi sono abbastanza sicuro che si tratti di qualche altro problema nascosto da qualche altra parte. Ci sono troppe opzioni. Se potessi riprodurre il problema in un progetto di esempio e condividere per noi, potremmo aiutarti. – Sulthan

1

Assicurarsi che opaqueinfoDetailView sia falso.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/opaque

Questa struttura fornisce un suggerimento per il sistema di disegno di come dovrebbe trattare la vista. Se impostato su true, il sistema di disegno considera la vista completamente opaca, consentendo al sistema di disegno di ottimizzare alcune operazioni di disegno e migliorare le prestazioni. Se impostato su false, il sistema di disegno compone la vista normalmente con altri contenuti. Il valore predefinito di questa proprietà è true.

1

Provare sotto il codice. Gioca solo con alpha e durata per perfezionarlo.

Nascondi func

func hideInfoView() { 
AFLog.enter(thisClass) 
UIView.animateWithDuration(
    2.0, 
    animations: 
    { 
     self.infoDetailView.alpha = 0.8 
    }, 
    completion: 
    { (finished) in 
     UIView.animateWithDuration(
    2.0, 
    animations: 
    { 
     self.infoDetailView.alpha = 0.4 
    }, 
    completion: 
    { (finished) in 
     self.infoDetailView.alpha = 0.0 
    } 
) 
    } 
) 
AFLog.exit(thisClass) 
} 

Visualizza func

func showInfoView() { 
AFLog.enter(thisClass) 
UIView.animateWithDuration(
    2.0, 
    animations: 
    { 
     self.infoDetailView.alpha = 0.3 
    }, 
    completion: 
    { (finished) in 
     UIView.animateWithDuration(
    2.0, 
    animations: 
    { 
     self.infoDetailView.alpha = 0.7 
    }, 
    completion: 
    { (finished) in 
     self.infoDetailView.alpha = 1.0 
    } 
) 
    } 
) 
AFLog.exit(thisClass) 
} 
2

Se l'animazione non sembra per eseguire quindi prendere in considerazione l'esame della situazione di ciascuno dei vostri punti di vista, prima di entrare nel blocco di animazione. Ad esempio, se l'alfa è già impostato su 0.4, l'animazione che regola la vista alfa, verrà completata quasi istantaneamente, senza alcun effetto apparente.

Prendere in considerazione l'utilizzo di un'animazione di fotogrammi chiave. Questo è l'aspetto di un'animazione shake nell'obiettivo c.

+(CAKeyframeAnimation*)shakeAnimation { 
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; 
    animation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-10.0, 0.0, 0.0)], 
         [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(10.0, 0.0, 0.0)]]; 
    animation.autoreverses = YES; 
    animation.repeatCount = 2; 
    animation.duration = 0.07; 
    return animation; 
} 

Ecco un post che mostra come regolare alfa con i fotogrammi chiave https://stackoverflow.com/a/18658081/1951992

25

Se infoDetailView è sotto i vincoli di layout di auto è necessario chiamare layoutIfNeeded sul genitore vista all'interno animateWithDuration:

func showInfoView() { 
    self.view.layoutIfNeeded() // call it also here to finish pending layout operations 
    UIView.animateWithDuration(2.0, animations: {() -> Void in 
     self.infoDetailView.alpha = 0.75 
     self.view.layoutIfNeeded() 
    }) 
} 

In teoria questo non dovrebbe essere necessario se si modifica solo il valore .alpha, ma forse questo potrebbe essere il problema in questo caso.

+0

Ha funzionato. Grazie. –

+0

È un suggerimento critico che devi chiamare il layout ** nella superview **, non nella vista in questione! – Fattie

+0

questo ha funzionato per me (stavo cambiando i valori costanti dei vincoli) – Setar

0

Hai provato a cambiare il tuo showInfoView() in qualcosa di più come toggleInfoView?

func toggleInfoView() { 
    let alpha = CGFloat(infoDetailView.alpha == 0 ? 1 : 0) 
    infoDetailView.alpha = alpha  //this is where the toggle happens 
} 

Si dice che se alpha del vostro punto di vista è 0, poi cambiare a 1. Altrimenti, lo rendono 0.

Se è necessario che ciò accada in un'animazione, provare

@IBAction func openInfoView(sender: UIButton) { 
    UIView.animate(withDuration: 2.0, animations: { 
     self.toggleInfoView()   //fade in/out infoDetailView when animating 
    }) 
} 
  • Continuerete a mantenere quello infoDetailView.alpha = 0.0 dove lo avete, proveniente dallo viewDidLoad.