Film şeridi, Kod, İpuçları ve birkaç Gotchas
Diğer cevaplar gayet iyi, ancak bu, son bir örnek kullanarak animasyon kısıtlamalarının birkaç önemli önemini vurgulamaktadır. Aşağıdakileri fark etmeden önce birçok varyasyondan geçtim:
Güçlü bir referans tutmak için Sınıf değişkenlerine hedeflemek istediğiniz kısıtlamaları yapın. Swift'te tembel değişkenler kullandım:
lazy var centerYInflection:NSLayoutConstraint = {
let temp = self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
return temp!
}()
Bazı deneylerden sonra, kısıtlamanın ÜST görünümden (yani denetim) akarak sınırlamanın tanımlandığı iki görünümden alınması GEREKİR . Aşağıdaki örnekte (hem MNGStarRating hem de UIWebView, arasında bir sınırlama oluşturduğum iki tür öğedir ve self.view içinde alt görünümlerdir).
Filtre Zinciri
Bükülme noktası olarak işlev görecek istenen kısıtlamayı ayırmak için Swift'in filtre yönteminden faydalanıyorum. Bir de çok daha karmaşık olabilir ama filtre burada güzel bir iş çıkarır.
Swift Kullanarak Kısıtlamaları Canlandırma
Nota Bene - Bu örnek, film şeridi / kod çözümüdür ve film şeridinde varsayılan kısıtlamalar yaptığını varsayar. Daha sonra kod kullanarak değişiklikleri canlandırabilirsiniz.
Doğru ölçütlerle filtrelemek ve animasyonunuz için belirli bir bükülme noktasına ulaşmak için bir özellik oluşturduğunuzu varsayarsak (elbette bir dizi için filtreleyebilir ve birden fazla kısıtlamaya ihtiyacınız varsa geçiş yapabilirsiniz):
lazy var centerYInflection:NSLayoutConstraint = {
let temp = self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
return temp!
}()
....
Bir süre sonra...
@IBAction func toggleRatingView (sender:AnyObject){
let aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)
self.view.layoutIfNeeded()
//Use any animation you want, I like the bounce in springVelocity...
UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.75, options: [.CurveEaseOut], animations: { () -> Void in
//I use the frames to determine if the view is on-screen
if CGRectContainsRect(self.view.frame, self.ratingView.frame) {
//in frame ~ animate away
//I play a sound to give the animation some life
self.centerYInflection.constant = aPointAboveScene
self.centerYInflection.priority = UILayoutPriority(950)
} else {
//I play a different sound just to keep the user engaged
//out of frame ~ animate into scene
self.centerYInflection.constant = 0
self.centerYInflection.priority = UILayoutPriority(950)
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}) { (success) -> Void in
//do something else
}
}
}
Birçok yanlış dönüş
Bu notlar gerçekten kendim için yazdığım bir dizi ipucudur. Tüm yoklukları kişisel ve acı verici bir şekilde yaptım. Umarım bu rehber başkalarını kurtarabilir.
ZPpozisyonuna dikkat edin. Bazen hiçbir şey görünmüyorsa, diğer görünümlerin bazılarını gizlemeli veya animasyonlu görünümünüzü bulmak için görünüm hata ayıklayıcısını kullanmalısınız. Bir Kullanıcı Tanımlı Çalışma Zamanı Özelliğinin bir storyboard'un xml'sinde kaybolduğu ve animasyonlu görünümün (çalışırken) kapsanmasına neden olduğu vakaları bile buldum.
Dokümanları (yeni ve eski), Hızlı Yardım'ı ve başlıkları okumak için her zaman bir dakikanızı ayırın. Apple, AutoLayout kısıtlamalarını daha iyi yönetmek için birçok değişiklik yapmaya devam ediyor (yığın görünümlerine bakın). Ya da en azından AutoLayout Yemek Tarifleri . Bazen en iyi çözümlerin eski belgelerde / videolarda olduğunu unutmayın.
Animasyondaki değerlerle oynayın ve diğer animateWithDuration değişkenlerini kullanmayı düşünün.
Belirli düzen değerlerini diğer sabitlerdeki değişiklikleri belirleme ölçütü olarak sabit kodlamayın, bunun yerine görünümün konumunu belirlemenize izin veren değerleri kullanın. CGRectContainsRect
bir örnek
- Gerekirse, kısıt tanımına katılan bir görünümle ilişkilendirilmiş düzen kenar boşluklarını kullanmaktan çekinmeyin
let viewMargins = self.webview.layoutMarginsGuide
: açık
- Yapmanız gerekmeyen işleri yapmayın, film şeridindeki kısıtlamalara sahip tüm görünümlerin self.viewName.constraints özelliğine bağlı kısıtlamaları vardır.
- Kısıtlamalar için önceliklerinizi 1000'den az olarak değiştirin. Film şeridini 250 (düşük) veya 750 (yüksek) olarak ayarladım; (1000 önceliği koddaki herhangi bir şeye değiştirmeye çalışırsanız, 1000 gerektiğinden uygulama kilitlenir)
- ActivConstraints'i ve devre dışı bırakmayı derhal kullanmaya çalışmayı düşünmeyin (kısıtlamaları vardır, ancak sadece öğrenirken veya bunları kullanarak bir storyboard kullanıyorsanız, muhtemelen çok fazla yaptığınız anlamına gelir ~ aşağıda görüldüğü gibi bir yeri vardır)
- Gerçekten kodda yeni bir kısıtlama eklemediğiniz sürece addConstraints / removeConstraints kullanmayın. Çoğu zaman film şeridindeki görünümleri istenen kısıtlamalarla (görünümün ekran dışına yerleştirerek) düzenlediğimi, sonra kodda, görünümü hareket ettirmek için film şeridinde daha önce oluşturulan kısıtlamaları canlandırdığımı buldum.
- Yeni NSAnchorLayout sınıfı ve alt sınıflarıyla kısıtlamalar oluşturmak için çok zaman harcadım. Bunlar gayet iyi çalışıyor, ancak ihtiyacım olan tüm kısıtlamaların film şeridinde zaten var olduğunu fark etmem biraz zaman aldı. Kodda kısıtlamalar oluşturursanız, kesinlikle kısıtlamalarınızı toplamak için bu yöntemi kullanın:
Storyboard'ları kullanırken KAÇININ Çözümlere Hızlı Örnek
private var _nc:[NSLayoutConstraint] = []
lazy var newConstraints:[NSLayoutConstraint] = {
if !(self._nc.isEmpty) {
return self._nc
}
let viewMargins = self.webview.layoutMarginsGuide
let minimumScreenWidth = min(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height)
let centerY = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.webview.centerYAnchor)
centerY.constant = -1000.0
centerY.priority = (950)
let centerX = self.ratingView.centerXAnchor.constraintEqualToAnchor(self.webview.centerXAnchor)
centerX.priority = (950)
if let buttonConstraints = self.originalRatingViewConstraints?.filter({
($0.firstItem is UIButton || $0.secondItem is UIButton )
}) {
self._nc.appendContentsOf(buttonConstraints)
}
self._nc.append( centerY)
self._nc.append( centerX)
self._nc.append (self.ratingView.leadingAnchor.constraintEqualToAnchor(viewMargins.leadingAnchor, constant: 10.0))
self._nc.append (self.ratingView.trailingAnchor.constraintEqualToAnchor(viewMargins.trailingAnchor, constant: 10.0))
self._nc.append (self.ratingView.widthAnchor.constraintEqualToConstant((minimumScreenWidth - 20.0)))
self._nc.append (self.ratingView.heightAnchor.constraintEqualToConstant(200.0))
return self._nc
}()
Bu ipuçlarından birini veya layoutIfNeeded'in nereye ekleneceği gibi daha basit ipuçlarını unutursanız, büyük olasılıkla hiçbir şey olmaz: Bu durumda, bunun gibi yarı pişmiş bir çözümünüz olabilir:
NB - Aşağıdaki Otomatik Yerleşim bölümünü ve orijinal kılavuzu okumak için bir dakikanızı ayırın. Dinamik Animatörlerinizi desteklemek için bu teknikleri kullanmanın bir yolu vardır.
UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1.0, options: [.CurveEaseOut], animations: { () -> Void in
//
if self.starTopInflectionPoint.constant < 0 {
//-3000
//offscreen
self.starTopInflectionPoint.constant = self.navigationController?.navigationBar.bounds.height ?? 0
self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)
} else {
self.starTopInflectionPoint.constant = -3000
self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)
}
}) { (success) -> Void in
//do something else
}
}
Otomatik Yerleşim Kılavuzu'ndan snippet (ikinci snippet'in OS X kullanmak için olduğunu unutmayın). BTW - Bu, artık görebildiğim kadarıyla mevcut kılavuzda değil. Tercih edilen teknikler gelişmeye devam ediyor.
Otomatik Mizanpaj Tarafından Yapılan Değişiklikleri Canlandırma
Otomatik Mizanpaj tarafından yapılan değişikliklerin canlandırılması üzerinde tam kontrole ihtiyacınız varsa, kısıtlama değişikliklerinizi programlı olarak yapmanız gerekir. Temel konsept hem iOS hem de OS X için aynıdır, ancak birkaç küçük fark vardır.
Bir iOS uygulamasında kodunuz aşağıdaki gibi görünecektir:
[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
// Make all constraint changes here
[containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];
OS X'te, katman destekli animasyonlar kullanırken aşağıdaki kodu kullanın:
[containterView layoutSubtreeIfNeeded];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[context setAllowsImplicitAnimation: YES];
// Make all constraint changes here
[containerView layoutSubtreeIfNeeded];
}];
Katman destekli animasyonlar kullanmadığınızda, kısıtlamanın animatörünü kullanarak sabiti hareketlendirmelisiniz:
[[constraint animator] setConstant:42];
Görsel olarak daha iyi öğrenenler için Apple'ın bu erken videosuna göz atın .
Yakın Dikkat
Genellikle dokümantasyonda daha büyük fikirlere yol açan küçük notlar veya kod parçaları vardır. Örneğin, dinamik animatörlere otomatik düzen kısıtlamaları eklemek büyük bir fikirdir.
İyi Şanslar ve Güç seninle olsun.