[DÜZENLEME: Uyarı: Sonraki tartışmanın tamamı, muhtemelen bir görünüm dönüşümü uygulandığında düzeni tetikleme hatası yapamayan iOS 8 tarafından modası geçmiş veya en azından hafifletilecek.]
Otomatik Yerleşim ve Görüntüleme Dönüşümleri
Otomatik dönüşüm, görünüm dönüşümleriyle hiç iyi oynamıyor. Bunun nedeni, görebildiğim kadarıyla, dönüşümü olan (varsayılan kimlik dönüşümü dışında) bir görünümün çerçevesiyle uğraşmamanızdır - ancak tam olarak otomatik yerleşim budur. Otomatik layoutSubviews
yerleşimin çalışma şekli, çalışma zamanında tüm kısıtlamalardan kaçınması ve tüm görünümlerin çerçevelerini buna göre ayarlamasıdır.
Başka bir deyişle, kısıtlamalar sihir değildir; bunlar sadece yapılacaklar listesidir. layoutSubviews
yapılacaklar listesinin yapıldığı yerdir. Ve bunu çerçeveler ayarlayarak yapar.
Bir hata olarak bu konuda yardımcı olamaz. Bu dönüşümü bir görünüme uygularsam:
v.transform = CGAffineTransformMakeScale(0.5,0.5);
Görünüm merkezi ile önce ve yarısı boyutunda aynı yerde görünmesini bekliyoruz. Ancak kısıtlamalarına bağlı olarak, gördüğüm şey olmayabilir.
[Aslında burada ikinci bir sürpriz daha var: bir görünüme dönüşüm uygulamak derhal düzeni tetikliyor. Bu bana başka bir hata gibi geliyor. Ya da belki de ilk böceğin kalbidir. Beklediğim şey, en azından düzen süresine kadar bir dönüşümden kurtulabilmektir, örneğin cihaz döndürülür - tıpkı düzen süresine kadar bir kare animasyonundan kurtulabildiğim gibi. Ama aslında düzen zamanı hemen doğru, bu sadece yanlış görünüyor.]
Çözüm 1: Kısıtlama Yok
Geçerli bir çözüm, bir görünüme yarı kalıcı bir dönüşüm uygulayacaksam (ve yalnızca bir şekilde geçici olarak sallamıyorsa), onu etkileyen tüm kısıtlamaları kaldırmak için. Ne yazık ki, bu genellikle görünümün ekrandan kaybolmasına neden olur, çünkü otomatik düzenleme hala gerçekleşir ve şimdi bize görüntüyü nereye koyacağımızı söyleyecek herhangi bir kısıtlama yoktur. Kısıtlamaları kaldırmanın yanı sıra, görünümü translatesAutoresizingMaskIntoConstraints
EVET olarak ayarladım . Görünüm artık eski şekilde çalışıyor ve otomatik düzenlemeden etkili bir şekilde etkilenmiyor. (O olduğu besbelli, Otomatik mizanpaj etkilenen, ancak örtük otomatik yeniden boyutlandırma maskesi kısıtlamaları onun davranışı Otomatik mizanpaj eskisi gibi olmasına neden.)
Çözüm 2: Yalnızca Uygun Kısıtlamaları Kullanın
Bu biraz sert görünüyorsa, başka bir çözüm, kısıtlamaları amaçlanan bir dönüşümle doğru çalışacak şekilde ayarlamaktır. Bir görünüm yalnızca dahili sabit genişliği ve yüksekliği ile boyutlandırılırsa ve yalnızca merkezi tarafından konumlandırılırsa, örneğin, ölçek dönüşümüm beklediğim gibi çalışır. Bu kodda, bir alt görünümdeki mevcut kısıtlamaları kaldırıyorum ( otherView
) ve bunları sabit bir genişlik ve yükseklik vererek dört merkezi ile değiştiriyorum ve tamamen merkez tarafından sabitledim. Bundan sonra, ölçek dönüşümüm işe yarıyor:
NSMutableArray* cons = [NSMutableArray array];
for (NSLayoutConstraint* con in self.view.constraints)
if (con.firstItem == self.otherView || con.secondItem == self.otherView)
[cons addObject:con];
[self.view removeConstraints:cons];
[self.otherView removeConstraints:self.otherView.constraints];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.otherView.center.x]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:self.otherView.center.y]];
[self.otherView addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeWidth relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.width]];
[self.otherView addConstraint:
[NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.height]];
Sonuç olarak, bir görünümün çerçevesini etkileyen herhangi bir kısıtlamanız yoksa, otomatik düzenleme görünümün çerçevesine dokunmaz - bu da bir dönüşüm söz konusu olduğunda arkanızda olan şeydir.
Çözüm 3: Bir Alt Görünüm Kullanın
Her iki çözümün de sorunu, görüşümüzü konumlandırmak için kısıtlamaların faydalarını kaybetmemizdir. İşte bunu çözen bir çözüm. İşi yalnızca ana bilgisayar gibi davranmak olan görünmez bir görünümle başlayın ve konumlandırmak için kısıtlamalar kullanın. Bunun içinde, gerçek görünümü bir alt görünüm olarak yerleştirin. Alt görünümü ana bilgisayar görünümünde konumlandırmak için kısıtlamaları kullanın, ancak bu kısıtlamaları, bir dönüşüm uyguladığımızda geri dönmeyecek kısıtlamalarla sınırlandırın.
İşte bir örnek:
Beyaz görünüm ana bilgisayar görünümüdür; bunun şeffaf ve dolayısıyla görünmez olduğunu iddia etmeniz gerekiyor. Kırmızı görünüm, merkezini ana bilgisayar görünümünün merkezine sabitleyerek konumlandırılan alt görünümüdür. Şimdi kırmızı görünümü herhangi bir sorun yaşamadan merkezi etrafında ölçeklendirebilir ve döndürebiliriz ve aslında çizim bunu yaptığımızı göstermektedir:
self.otherView.transform = CGAffineTransformScale(self.otherView.transform, 0.5, 0.5);
self.otherView.transform = CGAffineTransformRotate(self.otherView.transform, M_PI/8.0);
Bu arada, ana bilgisayar görünümündeki kısıtlamalar, cihazı döndürürken doğru yerde tutar.
Çözüm 4: Bunun yerine Katman Dönüşümlerini Kullanın
Görünüm dönüşümleri yerine, düzeni tetiklemeyen ve dolayısıyla kısıtlamalarla anında çakışmaya neden olmayan katman dönüşümleri kullanın.
Örneğin, bu basit "zonklama" görüntüleme animasyonu otomatik düzenleme altında iyi kırılabilir:
[UIView animateWithDuration:0.3 delay:0
options:UIViewAnimationOptionAutoreverse
animations:^{
v.transform = CGAffineTransformMakeScale(1.1, 1.1);
} completion:^(BOOL finished) {
v.transform = CGAffineTransformIdentity;
}];
Sonunda, görünümün boyutunda bir değişiklik olmamasına rağmen, yalnızca transform
düzeninin gerçekleşmesine neden olur ve kısıtlamalar, görünümün atlamasını sağlayabilir. (Bu bir hata veya neye benziyor mu?) Ancak Çekirdek Animasyon ile aynı şeyi yaparsak (CABasicAnimation kullanarak ve animasyonu görünümün katmanına uygularsak), düzen gerçekleşmez ve iyi çalışır:
CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.autoreverses = YES;
ba.duration = 0.3;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
[v.layer addAnimation:ba forKey:nil];
layerView
Genişliğini nasıl biliyor? Sağ tarafını başka bir şeye mi yapıştırıyor?