Kısıtlama değişikliklerini nasıl canlandırabilirim?


959

Eski bir uygulamayı bir ile güncelliyor AdBannerViewve hiçbir reklam olmadığında, ekrandan çıkar. Bir reklam olduğunda ekranda kayar. Temel şeyler.

Eski stil, kareyi bir animasyon bloğuna koydum. Yeni stil, konumu IBOutletbelirleyen otomatik düzen kısıtlamasına sahibim Y, bu durumda denetimin altından mesafedir ve sabiti değiştirir:

- (void)moveBannerOffScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = -32;
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = 0;
    }];
    bannerIsVisible = TRUE;
}

Ve banner tam olarak beklendiği gibi hareket ediyor, ancak animasyon yok .


GÜNCELLEME: Animasyonu kapsayan WWDC 12'nin Mastering Auto Layout için En İyi Yöntemler konusundaki konuşmasını yeniden izledim . CoreAnimation'ı kullanarak kısıtlamaların nasıl güncelleneceğini açıklar :

Aşağıdaki kod ile denedim, ama aynı sonuçları almak:

- (void)moveBannerOffScreen {
    _addBannerDistanceFromBottomConstraint.constant = -32;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    _addBannerDistanceFromBottomConstraint.constant = 0;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = TRUE;
}

Bir yan not, birçok kez kontrol ettim ve bu ana iş parçacığı üzerinde yürütülmektedir .


11
Daha önce SO hakkında bir yazım hatası için bir soru ve cevap için sunulan çok fazla oy görmedim
abbood

3
Yanıtta bir yazım hatası varsa, yanıtı düzenlemeniz gerekir. Bu yüzden düzenlenebilirler.
i_am_jorf

@jeffamaphone - Yazım hatası belirtmeniz daha yararlı olur, bu yüzden hatanın nerede olduğunu biliyordum. Cevabı kendiniz düzenleyebilir ve yazım hatalarını diğer herkese kazandırdık. Eğer sabitse animasyon bloğundan kaldırmak için düzenledim, eğer bahsettiğiniz şey buysa.
DBD

1
Yazım hatası nedir bilmiyorum. Yukarıdaki yorumlara yanıt veriyordum.
i_am_jorf

9
Sonra yazım hatası olduğu bir soru. Aptalca "layoutIfNeeded" yerine "setNeedsLayout" yazıyordum. Kodumu hata ve ekran görüntüleri doğru komutla kesip yapıştırdığımda sorum açıkça gösteriliyor. Yine de birisi onu işaret edene kadar bunu fark edemiyor gibiydi.
DBD

Yanıtlar:


1696

İki önemli not:

  1. layoutIfNeededAnimasyon bloğu içinde aramanız gerekir . Apple, beklemedeki tüm düzen işlemlerinin tamamlandığından emin olmak için animasyon bloğundan önce bir kez aramanızı önerir.

  2. Kısıtlamaların ekli olduğu alt görünümde değil, özellikle üst görünümde (ör. self.view) Çağırmanız gerekir. Bunu yaptığınızda , kısıtlamayı değiştirdiğiniz görünümle sınırlandırılabilecek diğer görünümleri canlandırma da dahil olmak üzere tüm kısıtlanmış görünümler güncellenir (örn. Görünüm B, Görünüm A'nın altına eklenir ve Görünüm A'nın üst göreli konumunu değiştirdiniz ve Görünüm B'yi istiyorsunuz canlandırmak için)

Bunu dene:

Objective-C

- (void)moveBannerOffScreen {
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = -32;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen { 
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = 0;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = TRUE;
}

Hızlı 3

UIView.animate(withDuration: 5) {
    self._addBannerDistanceFromBottomConstraint.constant = 0
    self.view.layoutIfNeeded()
}

199
Biliyor musun ... cevabın işe yarıyor. WWDC çalışıyor .... vizyonum başarısız oluyor. Nedense ben çağırıyordu anlamam için bir hafta sürdü setNeedsLayoutyerine layoutIfNeeded. Sadece yanlış yöntem adını yazdım fark etmeden kaç saat geçirdim biraz dehşete kapıldım.
DBD

23
Solüsyon çalışır ancak kısıt sabiti değiştirmek gerekmez içinde animasyon bloğu. Animasyonu başlatmadan önce kısıtlamayı bir kez ayarlamak tamamen iyidir. Cevabınızı düzenlemelisiniz.
Ortwin Gentz

74
Bu başlangıçta benim için işe yaramadı ve sonra PARI görünümünde layoutIfNeeded çağırmanız gerektiğini fark ettim, kısıtlamaların geçerli olduğu görünümü değil.
Oliver Pearmain

20
layoutIfNeeded kullanılması, yalnızca kısıtlama değişikliğini değil tüm alt görünüm yenilemelerini canlandıracaktır. sadece kısıtlama değişikliğini nasıl canlandırabilirsiniz?
ngb

11
"Apple, tüm bekleyen düzen işlemlerinin tamamlandığından emin olmak için animasyon bloğundan önce bir kez çağırmanızı önerir", teşekkür ederim, bunu hiç düşünmedim, ama mantıklı.
Rick van der Linde

109

Verilen cevabı takdir ediyorum, ama biraz daha ileri götürmenin güzel olacağını düşünüyorum.

Belgelerdeki temel blok animasyonu

[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
}];

ama gerçekten bu çok basit bir senaryodur. Alt görüntüleme kısıtlamalarını updateConstraintsyöntemle canlandırmak istersem ne olur ?

Alt görünümleri updateConstraints yöntemini çağıran bir animasyon bloğu

[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
    [self.view layoutIfNeeded];
} completion:nil];

UpdateConstraints yöntemi, UIView alt sınıfında geçersiz kılınır ve yöntemin sonunda super öğesini çağırmalıdır.

- (void)updateConstraints
{
    // Update some constraints

    [super updateConstraints];
}

AutoLayout Kılavuzu arzulanan çok şey bırakıyor, ancak okumaya değer. Ben kendimi bunu basit ve ince bir daraltma animasyon (0.2 saniye uzunluğunda) UISwitchile bir çift UITextFields ile bir alt görünüm arasında geçiş bir parçası olarak kullanıyorum . Alt görünümün kısıtlamaları, yukarıda açıklandığı gibi UIView alt sınıfları updateConstraints yöntemlerinde işlenmektedir.


Yukarıdaki tüm yöntemleri çağırırken self.view(ve bu görünümün bir alt görünümünde değil), çağrı updateConstraintsIfNeededgerekli değildir (çünkü bu görünümün setNeedsLayouttetikleyicileri updateConstraintsde). Çoğu için önemsiz olabilir, ama şimdiye kadar benim için değildi;)
anneblue

Özel durumunuzda Autolayout ve yaylar ve payandaların tam etkileşimini bilmeden yorum yapmak zordur. Tamamen saf bir otomatik senaryo hakkında konuşuyorum. LayoutSubviews yönteminizde tam olarak ne olduğunu merak ediyorum.
Cameron Lowell Palmer

translatesAutoresizingMaskIntoConstraints = NO; Saf otomatik düzenleme yapmak istiyorsanız, bunu kesinlikle devre dışı bırakmalısınız.
Cameron Lowell Palmer

Bunu görmedim, ama bazı kod olmadan konuyla gerçekten konuşamıyorum. Belki bir TableView ile alay edebilir ve GitHub'a yapıştırabilirsiniz?
Cameron Lowell Palmer

Üzgünüz,
gitHub

74

Genel olarak, kısıtlamaları güncellemeniz ve layoutIfNeededanimasyon bloğunun içinde arama yapmanız yeterlidir . Bu, ya bir .constantözelliğini değiştirme, NSLayoutConstraintkaldırma kısıtlamaları ekleme (iOS 7) ya da .activekısıtlamaların özelliğini değiştirme (iOS 8 ve 9) olabilir.

Basit kod:

[UIView animateWithDuration:0.3 animations:^{
    // Move to right
    self.leadingConstraint.active = false;
    self.trailingConstraint.active = true;

    // Move to bottom
    self.topConstraint.active = false;
    self.bottomConstraint.active = true;

    // Make the animation happen
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

Örnek Kurulum:

Xcode Project yani örnek animasyon projesi.

tartışma

Kısıtlamanın animasyon bloğundan önce mi yoksa içinde mi değiştirilmesi gerektiği hakkında bazı sorular vardır (önceki cevaplara bakın).

Aşağıda iOS'u öğreten Martin Pilkington ile Otomatik Mizanpaj yazan Ken Ferry arasında bir Twitter görüşmesi yer alıyor. Ken, animasyon bloğunun dışında sabitleri değiştirmenin şu anda işe yarayabileceğini, ancak bunun güvenli olmadığını ve animasyon bloğunun içinde gerçekten değiştirilmeleri gerektiğini açıklıyor . https://twitter.com/kongtomorrow/status/440627401018466305

Animasyon:

Örnek Proje

İşte bir görünümün nasıl canlandırılabileceğini gösteren basit bir proje. Objective C kullanıyor ve .activeçeşitli kısıtlamaların özelliklerini değiştirerek görünümü canlandırıyor . https://github.com/shepting/SampleAutoLayoutAnimation


Yeni etkin bayrağı kullanarak bir örnek göstermek için +1. Ayrıca, animasyon bloğunun dışındaki kısıtlamayı değiştirmek her zaman bana bir hack gibi hissetti
Korey Hinton

Github'da bir sorun oluşturdum çünkü bu çözüm, görünümü olduğu yere taşımak için işe yaramıyor. Aktif değiştirmenin doğru çözüm olmadığına inanıyorum ve bunun yerine önceliği değiştirmelisiniz. Üstü 750'ye ve altını 250'ye ayarlayın, daha sonra kodda UILayoutPriorityDefaultHigh ve UILayoutPriorityDefaultLow arasında dönüşümlü olarak ayarlayın.
malhal

Blok içinde güncelleme yapmanın bir başka nedeni de, layoutIfNeeded'i de çağırabilecek değişiklikleri arama kodundan izole etmesidir. (ve Twitter bağlantısı için teşekkürler)
Chris Conover

1
Mükemmel cevap. Özellikle Martin ve Ken'in bu konudaki konuşmalarından bahsettiğiniz için.
Jona

Ben güncelleme kısıtlamaları şekilde yaklaşık şaşkın ve yazdı ediyorum bu . Lütfen bir göz atabilir misiniz?
Bal

36
// Step 1, update your constraint
self.myOutletToConstraint.constant = 50; // New height (for example)

// Step 2, trigger animation
[UIView animateWithDuration:2.0 animations:^{

    // Step 3, call layoutIfNeeded on your animated view's parent
    [self.view layoutIfNeeded];
}];

29

Swift 4 çözümü

UIView.animate

Üç basit adım:

  1. Kısıtlamaları değiştirin, örneğin:

    heightAnchor.constant = 50
  2. viewİçindekilere mizanpajının kirli olduğunu ve otomatik yerleşimin mizanpajı yeniden hesaplaması gerektiğini söyleyin :

    self.view.setNeedsLayout()
  3. Animasyon bloğunda, düzene doğrudan kareleri ayarlamaya eşdeğer olan düzeni yeniden hesaplamasını söyleyin (bu durumda otomatik düzenleme kareleri ayarlayacaktır):

    UIView.animate(withDuration: 0.5) {
        self.view.layoutIfNeeded()
    }

En basit örneği tamamlayın:

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

Kenar notu

İsteğe bağlı bir 0. adım vardır - self.view.layoutIfNeeded()animasyonun başlangıç ​​noktasının eski kısıtlamaları uygulanmış durumdan olduğundan emin olmak için aramak isteyebileceğiniz kısıtlamaları değiştirmeden önce (animasyona dahil edilmemesi gereken bazı kısıtlama değişiklikleri olması durumunda) ):

otherConstraint.constant = 30
// this will make sure that otherConstraint won't be animated but will take effect immediately
self.view.layoutIfNeeded()

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

UIViewPropertyAnimator

İOS 10 ile yeni bir animasyon mekanizmasına sahip UIViewPropertyAnimatorolduğumuzdan - temel olarak aynı mekanizmanın bunun için geçerli olduğunu bilmeliyiz. Adımlar temel olarak aynıdır:

heightAnchor.constant = 50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}
animator.startAnimation()

Yana animatoranimasyonun kapsüllemesidir, biz buna referansı tutmak ve daha sonra diyebiliriz. Ancak, animasyon bloğunda otomatik düzenlemeye sadece kareleri yeniden hesaplamasını söylediğimizden, aramadan önce kısıtlamaları değiştirmemiz gerekir startAnimation. Bu nedenle böyle bir şey mümkündür:

// prepare the animator first and keep a reference to it
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}

// at some other point in time we change the constraints and call the animator
heightAnchor.constant = 50
self.view.setNeedsLayout()
animator.startAnimation()

Kısıtlamaları değiştirme ve bir animatör başlatma sırası önemlidir - eğer sadece kısıtlamaları değiştirir ve animatörümüzü daha sonraki bir noktaya bırakırsak, bir sonraki yeniden çizim döngüsü otomatik tekrar hesaplamayı tetikleyebilir ve değişiklik canlandırılmaz.

Ayrıca, tek bir animatörün tekrar kullanılamayacağını unutmayın. Bir kez çalıştırdığınızda "tekrar çalıştıramazsınız". Etkileşimli bir animasyonu kontrol etmek için kullanmazsak, animatörü çevrede tutmak için gerçekten iyi bir neden yok sanırım.


5 hızlı 5 de harika çalışıyor
spnkr

layoutIfNeeded () anahtardır
Medhi

15

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.

  1. 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.

  2. 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.

  3. Animasyondaki değerlerle oynayın ve diğer animateWithDuration değişkenlerini kullanmayı düşünün.

  4. 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. CGRectContainsRectbir örnek

  5. 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
  6. 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.
  7. 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)
  8. 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)
  9. 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.
  10. 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.


11

Hızlı çözüm:

yourConstraint.constant = 50
UIView.animate(withDuration: 1.0, animations: {
    yourView.layoutIfNeeded
})

6

Çalışma Çözümü 100% Swift 3.1

Tüm cevapları okudum ve tüm uygulamalarımda bunları doğru bir şekilde canlandırmak için kullandığım kodları ve hiyerarşisini paylaşmak istiyorum, Burada bazı çözümler çalışmıyor, örneğin şu anda iPhone 5 gibi daha yavaş cihazlarda kontrol etmelisiniz.

self.view.layoutIfNeeded() // Force lays of all subviews on root view
UIView.animate(withDuration: 0.5) { [weak self] in // allowing to ARC to deallocate it properly
       self?.tbConstraint.constant = 158 // my constraint constant change
       self?.view.layoutIfNeeded() // Force lays of all subviews on root view again.
}

4

Kısıtlamaları canlandırmaya çalışıyordum ve iyi bir açıklama bulmak gerçekten kolay değildi.

Diğer cevapların söyledikleri tamamen doğrudur: [self.view layoutIfNeeded];içeriden aramanız gerekir animateWithDuration: animations:. Bununla birlikte, diğer önemli nokta, NSLayoutConstraintcanlandırmak istediğiniz her şey için işaretçiler bulundurmaktır .

GitHub'da bir örnek oluşturdum .


4

Xcode 8.3.3 ile Swift 3 için çalışan ve yeni test edilmiş çözüm:

self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0

UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)

Self.calendarViewHeight öğesinin customView (CalendarView) ile ilgili bir kısıtlama olduğunu unutmayın. Ben self.view üzerinde .layoutIfNeeded () çağırdı ve self.calendarView değil

Umarım bu yardım.


3

Bununla ilgili bir makale var: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

Hangi şekilde kodladı:

- (void)handleTapFrom:(UIGestureRecognizer *)gesture {
    if (_isVisible) {
        _isVisible = NO;
        self.topConstraint.constant = -44.;    // 1
        [self.navbar setNeedsUpdateConstraints];  // 2
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded]; // 3
        }];
    } else {
        _isVisible = YES;
        self.topConstraint.constant = 0.;
        [self.navbar setNeedsUpdateConstraints];
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded];
        }];
    }
}

Umarım yardımcı olur.


1

Kısıtlama animasyonu bağlamında, bir keyboard_opened bildirimi içinde hemen bir kısıtlamayı canlandırdığım belirli bir durumdan bahsetmek istiyorum.

Kısıtlama, bir metin alanından kabın üstüne kadar bir üst boşluk tanımladı. Klavye açıldığında, sabiti 2'ye bölerim.

Doğrudan klavye bildirimi içinde tutarlı bir kısıtlama animasyonu başaramadım. Yaklaşık yarım kez görünüm, animasyon olmadan yeni konumuna atlar.

Bana klavye açılışının sonucu olarak bazı ek düzenler olabilir. 10ms gecikmeli basit bir dispatch_after bloğu eklemek, animasyonun her seferinde çalışmasını sağladı - atlama yok.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.