Định tâm chế độ xem trong giám sát của nó bằng Ngôn ngữ định dạng trực quan


160

Tôi mới bắt đầu học AutoLayout cho iOS và đã xem qua Ngôn ngữ định dạng trực quan.

Tất cả đều hoạt động tốt, ngoại trừ một điều: tôi chỉ không thể nhìn vào trung tâm trong phạm vi giám sát của nó.
Điều này có thể với VFL hay tôi cần tự tạo một ràng buộc?

Câu trả lời:


232

Hiện tại, không, có vẻ như không thể tập trung một chế độ xem trong giám sát chỉ bằng cách sử dụng VFL. Tuy nhiên, không khó để thực hiện điều đó bằng cách sử dụng một chuỗi VFL và một ràng buộc bổ sung duy nhất (trên mỗi trục):

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

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

Mọi người sẽ nghĩ rằng bạn chỉ đơn giản là có thể làm điều này (đó là những gì tôi nghĩ ban đầu và đã thử khi tôi thấy câu hỏi này):

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

Tôi đã thử nhiều biến thể khác nhau ở trên để cố gắng uốn cong nó theo ý muốn của tôi, nhưng điều này dường như không áp dụng cho giám sát ngay cả khi rõ ràng có hai chuỗi VFL riêng biệt cho cả hai trục ( H:|V:). Sau đó tôi bắt đầu cố gắng và cô lập chính xác khi lựa chọn làm được áp dụng cho các VFL. Chúng dường như không áp dụng cho giám sát trong VFL và sẽ chỉ áp dụng cho bất kỳ chế độ xem rõ ràng nào được đề cập trong chuỗi VFL (gây thất vọng trong một số trường hợp nhất định).

Tôi hy vọng trong tương lai Apple sẽ bổ sung một số loại tùy chọn mới để có các tùy chọn VFL có tính đến giám sát, ngay cả khi chỉ thực hiện khi chỉ có một chế độ xem rõ ràng bên cạnh giám sát trong VFL. Một giải pháp khác có thể là một tùy chọn khác được đưa vào VFL có nội dung như sau : NSLayoutFormatOptionIncludeSuperview.

Không cần phải nói, tôi đã học được rất nhiều về VFL khi cố gắng trả lời câu hỏi này.


2
Cảm ơn bạn đã trả lời chi tiết. Lý do duy nhất để tôi sử dụng VFL, tuy nhiên, là thoát khỏi những ràng buộc xấu xí đó. Quá tệ, Apple vẫn chưa hỗ trợ điều này ...
Christian Schnorr

@larsacus Bạn có thể bình luận về lý do tại sao câu trả lời dưới đây hoạt động? Nó làm tôi bối rối.
Matt G

8
Câu trả lời của Evgeny bên dưới hoạt động vì công cụ tự động thanh toán xử lý |[superview]như các thực thể nội bộ riêng biệt mặc dù chúng đại diện cho cùng một đối tượng ngữ nghĩa. Bằng cách sử dụng [superview], autolayout bao gồm đối tượng giám sát trong các số liệu căn chỉnh của nó (trong trường hợp trong câu trả lời của anh ta tại liên kết github, NSLayoutFormatAlignAllCenterY/ Xsố liệu của nó ).
larsacus

@larsacus Tuyệt vời, Cảm ơn!
Matt G

Chúng ta có biết nếu giới hạn vẫn áp dụng với phiên bản VFL đi kèm với iOS 7.x hiện tại không?
Drux

138

Có, có thể căn giữa một chế độ xem trong giám sát của nó bằng Ngôn ngữ định dạng trực quan. Cả hai chiều dọc và chiều ngang. Đây là bản demo:

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


15
Điều này thật tuyệt vời, bạn có nghĩ rằng bạn có thể mở rộng về điều này và giải thích lý do tại sao nó hoạt động?
tapi

3
Cuối cùng tôi đã sử dụng một cái gì đó gần hơn với câu trả lời được đánh dấu, nhưng +1 cho một tệp đính kèm github trong bạn
Rembrandt Q. Einstein

4
@Dan Nếu nó không phù hợp với bạn, bạn cũng có thể cần phải có các ràng buộc về chiều rộng và chiều cao. VFL sẽ như thế này cho chiều rộng: @ "[nhãn (== 200)]" và như thế này cho chiều cao: @ "V: [nhãn (== 200)]"
Jonathan Zhan

1
Tại sao kết quả từ | và [giám sát] khác nhau? Đây có phải là thứ gì đó nên là radar hay đang xảy ra mà tôi không theo dõi?
Matt G

3
Không thể phân tích định dạng ràng buộc: Tùy chọn che dấu các khung nhìn được yêu cầu để được căn chỉnh trên cạnh ngang, không được phép cho bố cục cũng nằm ngang. H: [giám sát] - (<= 1) - [nhãn1]
lấy

82

Tôi nghĩ rằng tốt hơn là tự tạo các ràng buộc.

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

Bây giờ chúng ta có thể sử dụng NSLayoutAnchor để xác định lập trình AutoLayout:

(Có sẵn trong iOS 9.0 trở lên)

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

Tôi khuyên bạn nên sử dụng SnapKit , đây là DSL để giúp Auto Layout dễ dàng trên cả iOS và macOS.

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

1
Làm việc tốt nhất là bối cảnh của tôi - mặc dù không có VFL.
brainray

nó cảnh báo tôi: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

Hoàn toàn có thể đã có thể làm điều đó như thế này:

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

Học được điều này từ đây. Mã ở trên trung tâm xem theo quan điểm của Y rõ ràng.

Swift3:

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

7

Thêm mã bên dưới và có nút của bạn ở giữa màn hình. Hoàn toàn có thể.

[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

Tôi biết nó không muốn bạn muốn nhưng tất nhiên bạn có thể tính toán lề và sử dụng chúng để tạo chuỗi định dạng trực quan;)

Dù sao, không. Thật không may, không thể thực hiện điều đó 'tự động' với VFL - ít nhất là chưa.


Chà, bạn có thể sử dụng chuỗi NSStringWithFormat: để xây dựng chuỗi VFL của bạn một cách linh hoạt khi chạy.
TRVD1707

1

Nhờ câu trả lời từ @Evgenii, tôi tạo một ví dụ đầy đủ trong ý chính:

chính giữa hình vuông màu đỏ theo chiều dọc với chiều cao tùy chỉnh

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

Bạn có thể căn giữa chế độ xem theo chiều dọc bằng cách sử dụng VFL (không hoàn toàn trực quan) hoặc sử dụng các ràng buộc theo cách thủ công. Nhân tiện, tôi không thể kết hợp cả trung tâm và chiều cao với nhau trong VFL như:

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

Trong giải pháp hiện tại, các ràng buộc VFL được thêm vào một cách riêng biệt.


0

Những gì nó phải được thực hiện là giám sát nên được khai báo trong từ điển. Thay vì sử dụng |bạn sử dụng @{@"super": view.superview};.

NSLayoutFormatAlignAllCenterXcho dọc và NSLayoutFormatAlignAllCenterYngang là tùy chọn.


0

Bạn có thể sử dụng lượt xem thêm.

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

Nếu bạn muốn nó gọn gàng, sau đó centerXView.hidden = centerYView.hidden = YES;.

Tái bút: Tôi không chắc mình có thể gọi các lượt xem thêm là "giữ chỗ", vì tiếng Anh là ngôn ngữ thứ hai của tôi. Nó sẽ được đánh giá cao nếu ai đó có thể nói với tôi điều đó.


Một cái gì đó đang thiếu ở đây. Làm thế nào để bạn gọi khối theo khai báo lượt xem ? Nó không phải là một mã hợp pháp theo cách bạn đặt nó
ishahak

0

Đối với những người đến đây để tìm Interface Buildergiải pháp dựa trên (Google dẫn tôi đến đây), chỉ cần thêm các ràng buộc về chiều rộng / chiều cao và chọn chế độ xem phụ -> điều khiển kéo đến giám sát của nó -> chọn "trung tâm theo chiều dọc / chiều ngang trong giám sát".


0

Đây là phương pháp của tôi

//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

Chỉ cần nói rằng, bạn có thể sử dụng điều này thay vì các ràng buộc:

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

4
Chỉ cần nói rằng, đó không phải là những gì anh ấy yêu cầu cũng như nó sẽ không hoạt động nếu bạn xoay thiết bị, màn hình được thay đổi kích thước, v.v.
jeffjv

-1

@ igor-muzyka trả lời trong Swift 2 :

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

-3

Thay vì sử dụng VFL, bạn có thể dễ dàng thực hiện việc này trong trình tạo giao diện. Trong Bảng phân cảnh chính, ctrl + nhấp vào chế độ xem bạn muốn căn giữa. Kéo đến giám sát (trong khi giữ ctrl) và chọn "Trung tâm X" hoặc "Trung tâm Y". Không cần mã.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.