Bir görünümü Visual Format Dili'ni kullanarak denetiminde ortalama


160

İOS için AutoLayout öğrenmeye başladım ve Visual Format Language'a bir göz attım.

Tek bir şey dışında her şey iyi çalışıyor: Ben onun gözetiminde ortalamak için bir görüş elde edemiyorum.
Bu VFL ile mümkün mü yoksa manuel olarak kendim bir kısıtlama oluşturmam gerekiyor mu?

Yanıtlar:


232

Şu anda, hayır, sadece VFL kullanarak denetimde bir görünüm ortalamak mümkün görünmüyor . Bununla birlikte, tek bir VFL dizesi ve tek bir ekstra kısıtlama (eksen başına) kullanarak bunu yapmak zor değildir:

VFL: "|-(>=20)-[view]-(>=20)-|"

[NSLayoutConstraint constraintWithItem:view
                             attribute:NSLayoutAttributeCenterX
                             relatedBy:NSLayoutRelationEqual
                                toItem:view.superview
                             attribute:NSLayoutAttributeCenterX
                            multiplier:1.f constant:0.f];

Biri bunu yapabileceğinizi düşünür (bu soruyu gördüğümde başlangıçta düşündüğüm ve denediğim şey):

[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=20)-[view(==200)]-(>=20)-|"
                                 options: NSLayoutFormatAlignAllCenterX | NSLayoutFormatAlignAllCenterY
                                 metrics:nil
                                   views:@{@"view" : view}];

Yukarıdakilerin birçok farklı varyasyonunu kendi isteğime bükmeye çalıştım, ancak bu, her iki eksen ( H:|V:) için açıkça iki ayrı VFL dizesine sahip olsa bile denetim için geçerli görünmüyor . Sonra denemek için başladı ve seçenekleri tam olarak ne zaman izole do VFL uygulanmıyor. Onlar gibi görünen değil VFL içinde Superview için geçerlidir ve sadece (bazı durumlarda hayal kırıklığı yaratıyor) VFL dizede belirtilen herhangi açık görünümleri için geçerli olacaktır.

Umarım Apple, VFL'nin denetiminin yanında sadece tek bir açık görünüm olsa bile, VFL seçeneklerinin denetimin dikkate alınmasını sağlamak için bir tür yeni seçenek ekler. Başka bir çözüm gibi bir şey diyor VFL geçirilen başka bir seçenek olabilir: NSLayoutFormatOptionIncludeSuperview.

Söylemeye gerek yok, bu soruyu cevaplamaya çalışırken VFL hakkında çok şey öğrendim.


2
Bu ayrıntılı cevap için teşekkür ederim. Ancak VFL'yi kullanmamın tek nedeni bu çirkin kısıtlama parçalarından kurtulmak. Çok kötü Apple henüz bunu desteklemiyor ...
Christian Schnorr

@larsacus Aşağıdaki cevabın neden işe yaradığını yorumlayabilir misiniz? Beni çok üzdü.
Matt G

8
Autolayout motoru davranır çünkü işler aşağıda Evgeny cevabı |ve [superview]ayrı iç varlıklar olarak olsa bile aynı anlamsal nesneyi temsil eder. Bunu kullanarak [superview], autolayout denetim nesnesini hizalama metriklerine dahil eder (github bağlantısındaki cevabında NSLayoutFormatAlignAllCenterY/ Xmetriğinde).
larsacus

@larsacus Harika, Teşekkürler!
Matt G

Sınırlamanın hala mevcut iOS 7.x ile birlikte gelen VFL sürümü için geçerli olup olmadığını biliyor muyuz?
Drux

138

Evet, bir görünümü kendi denetiminde Visual Format Language ile ortalamak mümkündür. Hem dikey hem de yatay olarak. İşte demo:

https://github.com/evgenyneu/center-vfl


15
Bu harika, sizce bu konuya genişleyebilir ve neden işe yaradığını açıklayabilirsiniz?
Nisan'ta tapi

3
İşaretli cevaba daha yakın bir şey kullandım, ama sizinkinde bir github eki için +1
Rembrandt Q. Einstein

4
@Dan Sizin için işe yaramazsa, genişlik ve yükseklik için de kısıtlamaların olması gerekebilir. VFL genişlik için şu şekilde olur: @ "[label (== 200)]" ve yükseklik için şu şekilde: @ "V: [label (== 200)]"
Jonathan Zhan

1
Neden sonuçlar | ve [denetim] farklı? Bu radar olması gereken bir şey mi, yoksa takip etmediğim bir şey mi var?
Matt G

3
Kısıtlama biçimi ayrıştırılamıyor: Seçenekler, gerekli görünümlerin yatay bir kenarda hizalanmasını maskelemektedir; bu da yatay olan düzen için izin verilmez. H: [Denetim] - (<= 1) - [
etiket1

82

Manuel olarak kısıtlamalar oluşturmanın daha iyi olduğunu düşünüyorum.

[superview addConstraint:
 [NSLayoutConstraint constraintWithItem:view
                              attribute:NSLayoutAttributeCenterX
                              relatedBy:NSLayoutRelationEqual
                                 toItem:superview
                              attribute:NSLayoutAttributeCenterX
                             multiplier:1
                               constant:0]];
[superview addConstraint:
 [NSLayoutConstraint constraintWithItem:view
                              attribute:NSLayoutAttributeCenterY
                              relatedBy:NSLayoutRelationEqual
                                 toItem:superview
                              attribute:NSLayoutAttributeCenterY
                             multiplier:1
                               constant:0]];

Artık NSLayoutAnchor'u kullanarak AutoLayout'u programlı olarak tanımlayabiliriz:

(İOS 9.0 ve sonraki sürümlerinde kullanılabilir)

view.centerXAnchor.constraint(equalTo: superview.centerXAnchor).isActive = true
view.centerYAnchor.constraint(equalTo: superview.centerYAnchor).isActive = true

Otomatik Mizanpaj'ı hem iOS hem de macOS'ta kolaylaştırmak için bir DSL olan SnapKit'i kullanmanızı öneririm .

view.snp.makeConstraints({ $0.center.equalToSuperview() })

1
En iyi çalıştı benim bağlam - hayır VFL olsa.
brainray

bana bir uyarı verir:Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.
Tapas Pal

10

Kesinlikle mümkün böyle yapmayı başardı:

[NSLayoutConstraint constraintsWithVisualFormat:@"H:[view]-(<=1)-[subview]"
                                        options:NSLayoutFormatAlignAllCenterY
                                        metrics:nil
                                          views:NSDictionaryOfVariableBindings(view, subview)];

Bunu buradan öğrendim . Yukarıdaki kod açıkça Y tarafından görüş alt merkezleri.

swift3:

        NSLayoutConstraint.constraints(withVisualFormat: "H:[view]-(<=1)-[subview]",
                                       options: .alignAllCenterY,
                                                       metrics: nil,
                                                       views: ["view":self, "subview":_spinnerView])

7

Aşağıdaki kodu ekleyin ve düğmenizi ekranın ortasına getirin. Kesinlikle mümkün.

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:|-[button]-|"
                           options:NSLayoutFormatAlignAllCenterY
                           metrics:0
                           views:views]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[button]-|"
                           options:NSLayoutFormatAlignAllCenterX
                           metrics:0
                           views:views]];

1

İstediğini istemediğini biliyorum ama elbette kenar boşluklarını hesaplayabilir ve bunları görsel format dizesini oluşturmak için kullanabilirsiniz;)

Her neyse, hayır. Ne yazık ki, bunu 'otomatik olarak' VFL ile yapmak mümkün değil - en azından henüz değil.


VFL dizenizi çalışma zamanında dinamik olarak oluşturmak için NSString stringWithFormat: kullanabilirsiniz.
TRVD1707

1

@Evgenii'nin cevabı sayesinde, özünde tam bir örnek oluşturuyorum:

kırmızı kareyi özel yükseklikle dikey olarak ortalayın

https://gist.github.com/yallenh/9fc2104b719742ae51384ed95dcaf626

VFL'yi (oldukça sezgisel olmayan) kullanarak ya da kısıtlamaları manuel olarak kullanarak bir görünümü dikey olarak ortalayabilirsiniz. Bu arada, hem merkezY hem de yüksekliği birlikte VFL'de birleştiremiyorum:

"H:[subView]-(<=1)-[followIcon(==customHeight)]"

Mevcut çözümde VFL kısıtlamaları ayrı olarak eklenir.


0

Yapılması gereken, denetimin sözlükte beyan edilmesi gerektiğidir. Kullanmak yerine |kullanın @{@"super": view.superview};.

Ve NSLayoutFormatAlignAllCenterXdikey olarak ve NSLayoutFormatAlignAllCenterYyatay olarak seçenekler için.


0

Ekstra görünümler kullanabilirsiniz.

NSDictionary *formats =
@{
  @"H:|[centerXView]|": @0,
  @"V:|[centerYView]|": @0,
  @"H:[centerYView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterY),
  @"V:[centerXView(0)]-(>=0)-[yourView]": @(NSLayoutFormatAlignAllCenterX),
};
NSDictionary *views = @{
  @"centerXView": centerXView, 
  @"centerYView": centerYView, 
  @"yourView": yourView,
};
 ^(NSString *format, NSNumber *options, BOOL *stop) {
     [superview addConstraints:
      [NSLayoutConstraint constraintsWithVisualFormat:format
                                              options:options.integerValue
                                              metrics:nil
                                                views:views]];
 }];

Düzgün olmasını istiyorsanız, o zaman centerXView.hidden = centerYView.hidden = YES;.

Not: Ekstra görüşleri "yer tutucular" olarak adlandırabileceğimden emin değilim, çünkü İngilizce ikinci dilim. Birisi bana bunu söyleyebilirse takdir edilecektir.


Burada bir şey kayıp. Görünüm beyanı altında bloğu nasıl çağırıyorsunuz ? Bu, sizin koyduğunuz şekilde yasal bir kod değildir
Haziran

0

Buraya Interface Buildertemel bir çözüm için gelenler için (Google beni buraya yönlendirir), sabit genişlik / yükseklik kısıtlamaları ekleyin ve onun denetimine ait alt görünümü seçin -> kontrol sürüklemesi -> "denetimde dikey / yatay olarak ortala" yı seçin.


0

Bu benim yöntemim

//create a 100*100 rect in the center of superView
var consts = NSLayoutConstraint.constraints(withVisualFormat: "H:|-space-[myView]-space-|", options: [], metrics:["space":view.bounds.width/2-50], views:["myView":myView])

consts += NSLayoutConstraint.constraints(withVisualFormat: "V:|-space-[myView]-space-|", options: [], metrics: ["space":view.bounds.height/2-50], views: ["myView":myView])

-1

Sadece u kısıtlamalar yerine bunu kullanabilirsiniz söylemek gerekir:

child.center = [parent convertPoint:parent.center fromView:parent.superview];

4
Söylemek gerekir, bu ne istiyor, ne de cihazı döndürürseniz, ekran yeniden boyutlandırılır, vb.
Çalışmaz

-1

Swift 2'de @ igor-muzyka cevabı :

NSLayoutConstraint.constraintsWithVisualFormat("H:[view]-(<=1)-[subview]", 
                                               options: .AlignAllCenterY,
                                               metrics: nil,
                                               views: ["view":view, "subview":subview])

-3

VFL kullanmak yerine bunu arayüz oluşturucuda kolayca yapabilirsiniz. Ana Storyboard'da, ortalamak istediğiniz görünümü ctrl + tıklayın. Denetime sürükleyin (ctrl tuşunu basılı tutarken) ve "Orta X" veya "Orta Y" yi seçin. Kod gerekmez.

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.