setNeedsLayout ve setNeedsUpdateKonstrüksiyonlar ve düzenIfNeeded vs updateConstraintsIfNeeded


227

Otomatik düzen zincirinin temel olarak 3 farklı süreç içerdiğini biliyorum.

  1. kısıtlamaları güncelleme
  2. mizanpaj görünümleri (burada karelerin hesaplandığı yer)
  3. Görüntüle

Ne tamamen bana temizlemek değil mi arasındaki iç farktır -setNeedsLayoutve -setNeedsUpdateConstraints. Apple Dokümanlar'dan:

setNeedsLayout

Bir görünümün alt görünümlerinin düzenini ayarlamak istediğinizde, uygulamanızın ana iş parçacığında bu yöntemi çağırın. Bu yöntem isteği not eder ve hemen geri döner. Bu yöntem hemen bir güncelleştirmeyi zorlamadığından, ancak bir sonraki güncelleme döngüsünü beklediğinden, bu görünümlerden herhangi biri güncellenmeden önce birden çok görünümün düzenini geçersiz kılmak için kullanabilirsiniz. Bu davranış, tüm düzen güncellemelerinizi genellikle performans için daha iyi olan bir güncelleştirme döngüsünde birleştirmenize olanak tanır.

setNeedsUpdateConstraints

Özel bir görüş özelliği kısıtlarını etkileyecek şekilde değiştirdiğinde, kısıtlamaları gelecekte bir noktada güncellenmesi gerektiğini belirtmek için bu yöntemi çağırabilirsiniz. Sistem daha sonra normal düzen geçişinin bir parçası olarak updateConstraints öğesini çağırır. Kısıtlamaların gerekmeden hemen önce bir kerede güncellenmesi, düzen geçişleri arasında görünümünüzde birden çok değişiklik yapıldığında kısıtlamaları gereksiz yere yeniden hesaplamamanızı sağlar.

Bir kısıtlamayı değiştirdikten sonra bir görünüm animasyon ve genellikle örneğin çağrı değişiklikleri animasyon istediğinizde:

[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.modifConstrView setNeedsUpdateConstraints];
        [self.modifConstrView layoutIfNeeded];
    } completion:NULL];

Kendi sonucumu yapmaya çalıştım:-setNeedsLayout-setNeedsUpdateConstraints-layoutIfNeeded-updateConstraintsIfNeeded

  • -updateConstraintsIfNeeded yalnızca kısıtlamaları güncelleyin, ancak düzeni işleme girmeye zorlamaz, bu nedenle orijinal kareler korunur
  • -setNeedsLayout-updateContraintsyöntemi de çağırır

Öyleyse diğeri yerine birini kullanmak ne zaman uygun? ve düzen yöntemleri hakkında, bunları bir kısıtlama değişikliği olan görünümde veya üst görünümde çağırmam gerekir mi?


27
İnsanları küçümsüyor anlamıyorum ... gerçekten. Yani bu konuda bir şey yapmalısın, zorunlu olarak bir neden sormak gibi ya da tamamen anlamsızlar
Andrea

7
Belki de sadece Eleştirel rozeti edinmeleri gerekir (İlk aşağı oy)
fujianjin6471

1
Burada görmenizi tavsiye ederim . Cevap gerçek bir soruna daha çok çözüm. Ayrıca bu videoyu izleyin
Honey

Yanıtlar:


258

Sonuçlarınız doğru. Temel şema:

  • setNeedsUpdateConstraintsgelecekteki updateConstraintsIfNeededçağrıları aramasını sağlar updateConstraints.
  • setNeedsLayoutgelecekteki layoutIfNeededçağrıları aramasını sağlar layoutSubviews.

Ne zaman layoutSubviewsdenir, o da çağırır updateConstraintsIfNeededyüzden elle nadiren benim durumumda gereklidir çağıran. Aslında, düzenleri hata ayıklama dışında hiç aramadım.

Kısıtlamaları kullanarak güncelleme setNeedsUpdateConstraintsde oldukça nadirdir, objc.io –a autolayouts hakkında okunması gerekir– diyor :

Daha sonra kısıtlamalarınızdan birini geçersiz kılan bir şey değişirse, kısıtlamayı derhal kaldırmalı ve setNeedsUpdateConstraints'i çağırmalısınız. Aslında, bir kısıtlama güncelleme geçişini tetiklemeniz gereken tek durum budur.

Buna ek olarak, tecrübelerime göre, kısıtlamaları geçersiz kılmak zorunda kalmadım setNeedsLayoutve kodun bir sonraki satırında ayarlamamıştım , çünkü yeni kısıtlamalar hemen hemen yeni bir düzen istiyor.

Temel kurallar:

  • Kısıtlamaları doğrudan değiştirdiyseniz arayın setNeedsLayout.
  • Eğer (sapmalar veya Tavsiyen gibi) bazı koşullar değiştirdiyseniz olur senin geçersiz kılınan içinde kısıtlamaları değiştirmek updateConstraints(Btw, değişim kısıtlamaları için önerilen bir yolu) yöntemiyle, çağrı setNeedsUpdateConstraintsve çoğu zaman, setNeedsLayoutbundan sonra.
  • Anında etkili olmak için yukarıdaki eylemlerden herhangi birine ihtiyacınız varsa (örneğin, bir düzen geçişinden sonra yeni kare yüksekliği öğrenmeniz gerektiğinde), a ile ekleyin layoutIfNeeded.

Ayrıca, animasyon kodunuzda, setNeedsUpdateConstraintsanimasyonun manuel olarak kısıtlamalardan önce güncellendiğinden ve animasyon yalnızca eski ve yeni arasındaki farklara göre görünümü yeniden düzenlediğinden, gereksiz olduğuna inanıyorum .


@coverback, yani objc.io, "Daha sonra kısıtlamalarınızdan birini geçersiz kılan bir şey değişirse, derhal kısıtlamayı kaldırmalı ve setNeedsUpdateConstraints'i çağırmalısınız. Aslında, bir kısıtlama güncellemesi geçişini tetiklemeniz gereken tek durum budur." Ve sonra Animasyon bloğunda constraint.contant'ı kaldırdığımda, eklediğimde veya değiştirdiğimde setNeedsLayout'u çağırmam gerektiğini söylüyor. Fark ne? Kendimi aptal hissediyorum :(
pash3r

3
@ pash3r Fark güncelleme sabiti "geçersiz kılma" olarak nitelendirilmez. Geçersiz kılma, artık başka bir görünüme eklenmesi veya tamamen kaldırılması gerektiği için artık alakalı olmadığı zamandır. Constant sadece bir görüşü daha yakına veya daha uzağa yerleştirir veya boyutunu değiştirir, böylece ihtiyaç duyulur setNeedsLayout.
coverback

@coverback setNeedsLayoutemin yapar layoutSubviewssonraki güncelleme döngüsünde adı verilecek, ama belki bununla hiçbir şey yapmak gelmez layoutIfNeeded?
fujianjin6471

2
@coverback Doğrudan kısıtlamaları değiştirirseniz, layoutSubviewsotomatik olarak çağrılır, aramanıza gerek yoktursetNeedsLayout
fujianjin6471

Evet, bir kısıtlamanın özelliklerini doğrudan değiştirmek tetikleyiciyi layoutSubviewsmanüel olarak yapmaya gerek yoktur. Bununla birlikte, layoutIfNeededdeğişikliklerin bir sonraki düzen döngüsü yerine hemen geçerli olması için aramanız gerekir
Charlie Martin

89

Coverback tarafından cevap oldukça doğrudur. Ancak, bazı ek ayrıntılar eklemek istiyorum.

Aşağıda, diğer davranışları açıklayan tipik bir UIView döngüsünün diyagramı verilmiştir:

UIView'in Yaşam Döngüsü

  1. Ben kullanırsanız öğrendim ettik -setNeedsLayoutyerine -setNeedsUpdateConstraintsher şeyi çalışması beklendiği gibi ama değiştirirseniz -layoutIfNeededile -updateConstraintsIfNeeded, animasyon olmayacak.

updateConstraintsgenellikle hiçbir şey yapmaz. Sadece çağrılıncaya kadar uygulamadığı kısıtlamaları giderir layoutSubviews. Bu yüzden animasyon bir çağrı gerektirir layoutSubviews.

  1. setNeedsLayout ayrıca -updateContraints yöntemini çağırır

Hayır, bu gerekli değildir. Senin kısıtlamaları modifiye edilmemiş ise UIView çağrısı atlayacak updateConstraints. Açıkça araman gerekiyor setNeedsUpdateConstraintsürecinde kısıtlamaları değiştirmek için.

Aramak updateConstraintsiçin aşağıdakileri yapmanız gerekir:

[view setNeedsUpdateConstraints];
[view setNeedsLayout]; 
[view layoutIfNeeded];

Teşekkürler, bu sorunumu çözdü. Ben bir animasyon önce LayoutIfNeeded () çağrıldığında üzerine eklenen geçici kısıtlamaları vardı hiçbir üst UIView bir UIWindow vardı. UIWindow'a bir alt görünüm sarmalayıcısı eklemek ve bu üç yöntemi çağırmak sorunumu çözdü.
masterwok

SetNeedsLayout hemen sonra layoutIfNeeded çağırma doğru olduğunu düşünmüyorum. Çünkü yöntem, düzenin hemen yeniden çizilmesine ve ikincisinin bir sonraki güncelleme döngüsünde yeniden çizilmesine neden olmasına rağmen aynı şeyi yapar.
fillky
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.