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.
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
Sì, vincolo0 sarebbe il vincolo per l'allineamento in basso. Vincolo1 sarebbe il vincolo verticale centrale. @Pangu –
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