2015-06-19 16 views
8

Al momento sto creando alcune transizioni e trasformo tramite CGAffineTransform per una panoramica panoramica e sono in esecuzione nei guai a causa delle prestazioni di trasformazione sotto iOS 7 e iPhone 4.Le prestazioni di CGAffineTransforms sono molto lente su iOS 7

Mi sono tuffato in Istrument e ho registrato la roba e il sollevamento pesante è stato fatto quando ho applicato le mie trasformazioni alla vista.

implementazione corrente

func handlePan(recognizer : UIPanGestureRecognizer) { 

     let drawerLocation = recognizer.locationInView(drawerView!) 
     let locationInView = recognizer.locationInView(containerView!) 
     let progressMax = containerView!.frame.height - 40 - 20 

     if(recognizer.state == .Changed) { 

      let offsetDrag = dragStartPosition.y - locationInView.y 
      let progress = Float(offsetDrag/progressMax) 

      if(offsetDrag >= 0) { 

       let positionTransform = CGAffineTransformMakeTranslation(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(normalizedProgress))) 
       viewWithTransform.transform = positionTransform // really bad performance here 
      } else { 
       // reset the transition 
      }  
    } 
} 

Soluzione per iOS 7

func handlePan(recognizer : UIPanGestureRecognizer) { 

     let drawerLocation = recognizer.locationInView(drawerView!) 
     let locationInView = recognizer.locationInView(containerView!) 
     let progressMax = containerView!.frame.height - 40 - 20 

     if(recognizer.state == .Changed) { 

      let offsetDrag = dragStartPosition.y - locationInView.y 
      let progress = Float(offsetDrag/progressMax) 

      if(offsetDrag >= 0) { 
       if UIDevice.currentDevice().systemMajorVersion() > 7 { 
        let positionTransform = CGAffineTransformMakeTranslation(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(progress))) 
        viewWithTransform.transform = positionTransform // really bad performance here 
       } else { 
        viewWithTransform.frame = CGRectMake(0, -((containerView!.bounds.height - 40 - 20) * CGFloat(progress)), drawerView!.frame.size.width, drawerView!.frame.size.height); // works like a charm on iOS 7 
       } 

      } else { 
       // reset the transition 
      }  
    } 
} 

Domanda

Perché le prestazioni così male su iOS 7 e il mio iPhone 4 con CGAffineTransforms ? Perché sta facendo la stessa cosa con l'offset, quindi l'impostazione del frame nella soluzione alternativa. Quando uso lo UIView.animateWithDuration() con la trasformazione, si sta eseguendo su 60fps. Cosa posso fare per non riscrivere l'intera implementazione sulla base di iOS 7?

UPDATE 28 luglio Scoperto che AutoLayout è possibile partecipare a questo problema. Ecco un TimeProfiler Pila dalle mie chiamate correnti:

Time Profiler

Ora sto di fronte a un grosso problema nel mio attuale implementazione, perché mi baso su layout automatico. Qual è la soluzione più semplice per risolvere questo problema su iOS 7?

+0

'viewWithTransform.translate =' qualcosa di personalizzato o si suppone che sia 'viewWithTransform.transform ='? Stai (intenzionalmente o meno intenzionalmente) usando Auto Layout? Stai profilando usando build di rilascio? –

risposta

4

Mentre hai ragione a fare la stessa cosa, sotto il cofano, non è così facile - ci sono moltiplicazioni di matrice che vanno dappertutto. More on that can be found here.

È strano che se si sta facendo solo questo, influisce sulle prestazioni, ma immagino che il layout sia complicato e quindi il re-rendering richiede molto tempo; Io in realtà avuto lo stesso problema, come una settimana fa, ecco quello che mi ha aiutato:

  • rimozione layout automatico da quel particolare vista per qualche ragione aiuta molto
  • manipolazione con telaio dovrebbe essere usato quando non si ruotando/visualizzazione in scala. Diventa davvero necessario quando si utilizzano quelli.
  • rimozione ombre e viste semitrasparenti, soprattutto se v'è più di essi una dietro l'altra, gocce davvero FPS quando transform viene utilizzato

Inoltre, è possibile tentare di assegnare che trasformano in chiamata asincrona e vedere se questo aiuta:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {() -> Void in 
     dispatch_async(dispatch_get_main_queue(), {() -> Void in 
      // Transform view 
     }) 
    }) 

E se si vuole veramente essere di fantasia, usare POP Framework from Facebook. E 'grande per quello che vuoi, e ti permette di fare alcune cose di fantasia come rimbalzo, elasticità ecc Ecco come si può utilizzare:

// Create spring animation (there are more types, if you want) 
let animation = POPSpringAnimation(propertyNamed: kPOPViewCenter) 

// Configure it properly 
animation.autoreverses = false 
animation.removedOnCompletion = true 
animation.fromValue = view.center 
animation.toValue = finalPositionPoint 

// Add new animation to your view - animation key can be whatever you like, serves as reference 
view.pop_addAnimation(animation, forKey: "YourAnimationKey") 

Edit: Se ci si sposta vista in giro, l'uso .proprietà centrale, non la cornice. Ti consente di definire nuovamente altezza/larghezza e dare un'idea più chiara delle tue intenzioni.

+0

Provo la cosa di dispatch_async. È davvero facile Sono sul main_queue e invio la trasformazione al successivo runloop sulla coda principale. Sembra semplice. Conosco POP da Facebook, ma c'è la possibilità di usarlo per gestire un gesto di pan? Voglio dire che si chiama molto;) – mariusLAN

+0

Per il gesto di panoramica, ti suggerisco di creare un'animazione a molla per il tuo elemento e impostare la proprietà removedOnCompletion = false. In questo modo, funzionerà indefinitamente, anche dopo aver raggiunto il valore "toValue". Quando fai una panoramica, modifica .toValue e ricomincia l'animazione. –

+0

@mariusLAN sei riuscito a risolvere il tuo problema usando la mia soluzione? –

Problemi correlati