2014-12-22 11 views
7

questo è quello che mi piace di ottenere: enter image description hereCome animare slide up UIView con AutoLayout?

voglio eseguire una diapositiva di animazione in cui un utente può scorrere un UIView2, e l'UIView2 si fermerà a metà strada sullo schermo.

so come presentare un UIViewControler modale tramite un'azione UIButton in questo modo:

[self presentViewController:newController animated:NO completion:nil]; 

So che hai bisogno anche di questo tipo di codice per le animazioni:

[UIView animateWithDuration:0.5f animations:^{ 
    [self.customView layoutIfNeeded]; 
} completion:^(BOOL finished) { 

}]; 

Tuttavia, sono Non sono sicuro di come ottenere questo risultato con UIViews, soprattutto perché utilizzo AutoLayout per il mio progetto e utilizzo i vincoli per supportare facilmente più dimensioni dello schermo.

Come posso ottenere questo risultato senza interrompere AutoLayout e i vincoli che ho impostato?

Grazie

risposta

16

Quello che faccio di solito in questa situazione è il seguente.

Aggiungi due vincoli alla scena. Uno in cui UIView2 è allineato alla fine di UIView1. Il secondo, in cui è allineato al centro di UIView1 (ti consigliamo di ctrl + trascinare tra le visualizzazioni per aggiungere i vincoli in modo appropriato). Questi vincoli inizialmente saranno in conflitto tra loro, e va bene.

Aggiungi IBOutlet s al controller di visualizzazione per il NSLayoutConstraints e assegna i due vincoli che abbiamo creato a quelli IBOutlet s.

Impostare la priorità del vincolo sulla condizione iniziale su 999 (vale a dire la priorità del vincolo sull'allineamento sul fondo deve essere 999). Impostare la priorità del vincolo sul vincolo di destinazione su 998 (vale a dire la priorità del vincolo sul centro di allineamento è 998). Vedrai ora che questi vincoli non saranno più in conflitto. Questo perché la priorità su un vincolo ha la priorità sull'altro.

Si può vedere dove questo è diretto ora. Quindi, quando vuoi animare UIView2 tra i vincoli, scambia le priorità e anima!

Codice:

@interface MyViewController() 
    @property (nonatomic, weak) IBOutlet NSLayoutConstraint* constraint0; 
    @property (nonatomic, weak) IBOutlet NSLayoutConstraint* constraint1; 
@end 

- (void)someMethodWhereIWantToAnimate 
{ 
    NSInteger temp = self.constraint0.priority; 
    self.constraint0.priority = self.constraint1.priority; 
    self.constraint1.priority = temp; 

    [UIView animateWithDuration:0.3 animations:^{ 
     // Simplest is to use the main ViewController's view 
     [self.view layoutIfNeeded]; 
    }]; 
} 

Per consentire panning e l'utilizzo che per avviare l'animazione aggiungere un Recognizer Gesture Pan al controller della vista. Ctrl + trascina da UIView2 a Pan Gesture Recognizer e impostalo come gestureRecognizer. Ora quando trascini il UIView2, sarai in grado di ricevere gli eventi pan.

Aggiungi un IBAction per gestire la padella:

- (IBAction)onPan:(id)sender 
{ 
} 

Ctrl + trascinate dal sistema di riconoscimento gesto padella per il controller della vista e impostare onPan: come l'azione inviato.

sender è in realtà il riconoscimento pan gesture stesso. Quindi saremo in grado di compilare questo metodo per gestire un pan e fare seguire UIView2 sotto il dito dell'utente e quindi avviare l'animazione quando lasciano andare.

Cominciamo compilando il codice:

- (IBAction)onPan:(id)sender 
{ 
    UIPanGestureRecognizer* recognizer = (UIPanGestureRecognizer*)sender; 
    CGPoint translation = [recognizer translationInView:self.view]; 
    NSLog(@"State: (%d) Translation in view: (%f, %f)", recognizer.state, translation.x, translation.y); 
} 

Se si esegue con questo codice, e trascinare il dito sopra UIView2, vedrete output come questo:

State: (1) Translation in view: (0.000000, -2.500000) 
State: (2) Translation in view: (0.500000, -7.500000) 
State: (2) Translation in view: (0.500000, -7.500000) 
State: (2) Translation in view: (1.500000, -12.000000) 
State: (2) Translation in view: (2.500000, -16.500000) 
State: (2) Translation in view: (2.500000, -19.500000) 
State: (2) Translation in view: (2.500000, -24.500000) 
State: (2) Translation in view: (2.500000, -25.000000) 
State: (2) Translation in view: (2.500000, -25.500000) 
State: (2) Translation in view: (2.500000, -27.000000) 
State: (2) Translation in view: (2.500000, -29.500000) 
State: (2) Translation in view: (2.500000, -31.000000) 
State: (2) Translation in view: (2.500000, -31.500000) 
State: (3) Translation in view: (2.500000, -31.500000) 

Si noti che il i valori sono in costante aumento Vogliamo l'importo incrementale. Si noti lo stato nel registro. Stato (1) è trascinamento iniziale. Stato (2) è trascinato modificato. Stato (3) è trascinato. Usando queste informazioni, possiamo calcolare il delta.

aggiunge una proprietà CGPoint al controller visualizzare e aggiungere UIView2 come IBOutlet così:

@property (nonatomic) CGPoint lastTranslation; 
@property (nonatomic, weak) IBOutlet UIView* uiView2; 

Infine, cerchiamo di compilare il modulo finale del nostro metodo di pan:

- (IBAction)onPan:(id)sender 
{ 
    UIPanGestureRecognizer* recognizer = (UIPanGestureRecognizer*)sender; 
    CGPoint delta; 
    switch(recognizer.state) { 
     case UIGestureRecognizerStateBegan: 
      // On state begin: delta is the translation. Store it in our member for later user. 
      self.lastTranslation = delta = [recognizer translationInView:self.view]; 
      break; 
     case UIGestureRecognizerStateChanged: 
      // On state changed: calculate the difference between the translation and our 
      // previous translation. 
      delta = CGPointApplyAffineTransform([recognizer translationInView:self.view], CGAffineTransformMakeTranslation(-self.lastTranslation.x, -self.lastTranslation.y)); 
      self.lastTranslation = [recognizer translationInView:self.view]; 
      break; 
     case UIGestureRecognizerStateEnded: 
      // On state ended: Let's just do the constraint animation. 
      [self someMethodWhereIWantToAnimate]; 
      break; 
     default: 
      break; 
    } 
    delta.x = 0; // Forces only vertical drag on the UIView2. 
    self.uiView2.center = CGPointApplyAffineTransform(self.uiView2.center, CGAffineTransformMakeTranslation(delta.x, delta.y)); // Move our uiView2 based on the delta. 
    NSLog(@"State: (%d) Translation in view: (%f, %f)", recognizer.state, delta.x, delta.y); 
} 

Questo dovrebbe farti stare bene sulla tua strada. Si consiglia di esaminare l'animazione UIView sui vincoli un po 'in base al metodo velocityInView: del movimento pan, ma che lascerò come esercizio.

+0

Sto assumendo che il vincolo1 sia il vincolo del centro verticale? ... forse ho mancato la lettura, ma a quale vincolo corrisponde il vincolo? ... in basso? – Pangu

+0

Sì, vincolo0 sarebbe il vincolo per l'allineamento in basso. Vincolo1 sarebbe il vincolo verticale centrale. @Pangu –

+0

e il fatto che UIView2 sia parzialmente fuori dalla finestra di UIView1 all'interno di UIView1? ... non creerebbe di per sé il proprio conflitto di vincoli? – Pangu

Problemi correlati