Çalışma zamanında kısıtlama önceliğini nasıl değiştirebilirim


87

Dinamik yüksekliği olan bir görünümüm var ve bu görünüm yüksekliği önceliğini çalışma zamanında değiştirmeye çalışıyorum.

İşte benim kod parçam;

if (index == 0) {

    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.priority = 1000;

} else if (index == 1) {

    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.priority = 500;

}

Bir düğme eylemiyle dizini değiştiriyorum. Bu kodu çalıştırdığımda şu hatayı alıyorum:

*** Assertion failure in -[NSLayoutConstraint setPriority:], /SourceCache/Foundation/Foundation-1141.1/Layout.subproj/NSLayoutConstraint.m:174

Benim buradaki hatam ne?

Yanıtlar:


174

NSLayoutConstraintSınıf referansında belirtildiği gibi :

Öncelikler, gerekli olmayandan gerekli olana veya gerekli olandan gereksiz olana değiştirilemez. NSLayoutPriorityRequiredOS X veya UILayoutPriorityRequirediOS'ta önceliği daha düşük bir önceliğe değiştirilirse veya kısıtlamalar bir görünüme eklendikten sonra daha düşük bir öncelik gerekli bir önceliğe değiştirilirse bir istisna atılır . Bir isteğe bağlı öncelikten diğer bir isteğe bağlı önceliğe geçiş, bir görünüme kısıtlama yüklendikten sonra bile izin verilir.

1000 yerine 999 önceliğini kullanın. Teknik olarak kesinlikle gerekli olmayacak, ancak her şeyden daha yüksek bir öncelik olacaktır.


4
Güzel cevabınız için teşekkürler, ancak 1000 yerine 999 kullanırsam, yükseklik sınırlamasına 0 atayarak görünümümü gizleyemem.
Le'Kirdok

Bu başka bir problem. Başka çelişkili kısıtlamalarınız olabilir. Kodunuz artık çökmüyorsa, ancak görünüm animasyonunuz hala yanlışsa, lütfen bu soruyu çözüldü olarak işaretleyin; sonra başka bir tane açın.
Cyrille

güzel bir, farklı değerler kullanmak sorun değil (999, 900, 500, vb.) :)
user924

7
Ciddi anlamda? İOS geliştirmede normal olarak çalışan bir şey var mı? Pek çok şeyin manuel olarak yapılması ve / veya sistem hataları veya desteklenmemesi nedeniyle tonlarca geçici çözüm kodu uygulanması gerekiyordu. Yapıcı yorum yapmadığım için özür dilerim.
Luten

7
Bu sınırlama Bir sınırlamasını değiştirerek denedim iOS 13. I'de kaldırıldı gibi görünüyor requirediçin defaultLowve işe yaradı.
İOS

53

Cyrille'in cevabına küçük bir ekleme yapmak istiyorum.

Kodda kısıtlama oluşturuyorsanız, etkinleştirmeden önce önceliğini ayarladığınızdan emin olun. Örneğin:

surveyViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self
                                               attribute:NSLayoutAttributeHeight
                                               relatedBy:NSLayoutRelationEqual
                                                  toItem:self.superview
                                               attribute:NSLayoutAttributeHeight
                                              multiplier:1
                                                constant:0];
surveyViewHeightConstraint.active = YES;
surveyViewHeightConstraint.priority = 999;

Bu, çalışma zamanı istisnasına neden olur.

Önceliğin kurulu bir kısıtlamada gerekenden (veya tam tersi) değişmesi desteklenmez.

Doğru sıra:

surveyViewHeightConstraint.priority = 999;
surveyViewHeightConstraint.active = YES;

Swift 4+ sürümü için

constraintName.priority = UILayoutPriority(rawValue: 999)

13

Swift versiyonu:

myContraint.priority = UILayoutPriority(999.0)

8

Bunu her zaman ele alma şeklimiz, kısıtlama sabitini değil, sadece önceliği değiştirmektir. Örneğin, sizin durumunuzda iki yükseklik sınırlaması vardır.

 heightConstraintOne (who's height is set in the storyboard at 150, and priority set at 750)
 heightConstraintTwo (who's height is set in the storyboard at 0, and priority set at 250)

görünümü gizlemek istiyorsanız, siz:

heightConstraintTwo.priority = 999;

aynı şekilde, görünümü göstermek istiyorsanız:

heightConstraintTwo.priority = 250;

5
Harika, anladım: 1000 yerine 999 kullanın. Teşekkürler
brainray

3

Umarım bu senaryo birine yardımcı olur: İki kısıtlamam vardı, birbirlerine zıttılar, yani aynı anda tatmin edilemezlerdi, arayüz oluşturucuda bunlardan birinin 1000 önceliği vardı ve diğerinin 1000'den az önceliği vardı. onları kodda değiştirdiğimde şu hatayı aldım:

Uygulamanın yakalanmamış istisna 'NSInternalInconsistencyException' nedeniyle sonlandırılması, nedeni: 'Önceliğin kurulu bir kısıtlamada gerekenden gerekenden değiştirilmesine (veya tam tersi) desteklenmemektedir. Öncelik 250'yi geçtiniz ve mevcut öncelik 1000'di. '

sonra onları .defaultHigh ve .defaultLow değerleriyle viewDidLoad işlevinde başlattım ve bu benim sorunumu çözdü.


1

NSLayoutConstraints classİçeriye göreUIKit Module

Bir kısıtlamanın öncelik seviyesi UILayoutPriorityRequired değerinin altındaysa, isteğe bağlıdır. Daha yüksek öncelikli kısıtlamalar, daha düşük öncelikli kısıtlamalardan önce karşılanır. Kısıt tatmini ya hepsi ya da hiç değildir. Bir 'a == b' kısıtlaması isteğe bağlıysa, bu, 'abs (ab)' yi en aza indirmeye çalışacağımız anlamına gelir. Bu özellik yalnızca ilk kurulumun bir parçası olarak veya isteğe bağlı olduğunda değiştirilebilir. Bir görünüme bir kısıtlama eklendikten sonra, öncelik NSLayoutPriorityRequired olarak değiştirilirse bir istisna atılır.

Örnek: - UIButtonçeşitli önceliklere sahip kısıtlamalar -

 func setConstraints() {
        buttonMessage.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: buttonMessage, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: -10).isActive = true

        let leading = NSLayoutConstraint(item: buttonMessage, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 10)

        leading.isActive = true


        let widthConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100)

        let heightConstraint = NSLayoutConstraint(item: buttonMessage, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 50)


        let trailingToSuperView = NSLayoutConstraint(item: buttonMessage, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)

        trailingToSuperView.priority = 999
        trailingToSuperView.isActive = true

        //leading.isActive = false//uncomment & check it will align to right of the View

        buttonMessage.addConstraints([widthConstraint,heightConstraint])

         }  

1
Hayır, içinde asla kısıtlama yaratmamalısınız viewDidLayoutSubviews. Bu yöntem birkaç kez çağrılabilir ve orada yinelenen kısıtlamalar oluşturursanız uygulamanızın çökmesine neden olabilir.
mil / sa

0

Ben de aynı sorunla karşı karşıyaydım. Yukarıda belirtilen cevaplardan bazıları iOS 13'te olduğu gibi önceliğin değişmesi iyi çalışacak, ancak iOS 12'de çökmeye neden olacak.

Bu sorunu, Storyboard'daki bu belirli kısıtlamaya IBOutlet NSLayoutConstraint oluşturarak, önceliğini 1000 olarak koruyarak çözebildim, aşağıdaki düzeltme kodu.

if (Condition) {
    surveyViewHeightConstraint.constant = 0;
    surveyViewHeightConstraint.isActive = false;
} else if (index == 1) {
    surveyViewHeightConstraint.constant = 163;
    surveyViewHeightConstraint.isActive = True;
}

Bu yardımcı olur umarım!!! Şerefe


-2

Şimdi, kısıtlamalarınız için IBOutlet bağlantısını alıp sonra bu kodu kullanabilirsiniz.

self.webviewHeight.priority = UILayoutPriority(rawValue: 1000)
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.