autolayout에 대한 나의 이해는 그것이 superview의 크기를 가지고 그것이 subview의 위치를 계산하는 제약과 본질적인 크기에 기초한다는 것입니다.
이 과정을 되돌릴 수있는 방법이 있습니까? 구속 및 기본 크기의 기초에서 수퍼 뷰의 크기를 조정하고 싶습니다. 이것을 달성하는 가장 간단한 방법은 무엇입니까?
에 대한 헤더로 사용하는 Xcode에서 설계된보기가 있습니다 UITableView
. 이보기에는 레이블과 버튼이 포함되어 있습니다. 라벨의 크기는 데이터에 따라 다릅니다. 구속 조건에 따라 레이블이 성공적으로 버튼을 아래로 눌렀거나 버튼과 수퍼 뷰 하단 사이에 구속 조건이있는 경우 레이블이 압축됩니다.
비슷한 질문이 몇 개 있지만 좋은 대답이 없습니다.
답변
사용할 올바른 API UIView systemLayoutSizeFittingSize:
는 UILayoutFittingCompressedSize
또는을 (를 ) 전달하는 것 UILayoutFittingExpandedSize
입니다.
UIView
자동 레이아웃을 사용 하는 일반적인 경우 제약 조건이 올바른 한 작동해야합니다. UITableViewCell
예를 들어 행 높이를 결정 하기 위해 그것을 사용하려면 셀에 대해 호출 contentView
하고 높이를 가져와야합니다.
하나 이상의 UILabel이 뷰에 여러 줄인 경우 추가 고려 사항이 있습니다. 이러한 경우 preferredMaxLayoutWidth
레이블이 올바른을 제공하여 계산에 intrinsicContentSize
사용될 속성을 올바르게 설정해야합니다 systemLayoutSizeFittingSize's
.
편집 : 요청에 따라 테이블 뷰 셀의 높이 계산 예 추가
테이블 셀 높이 계산에 자동 레이아웃을 사용하는 것은 효율적이지 않지만 특히 레이아웃이 복잡한 셀이있는 경우 편리합니다.
위에서 말했듯이 여러 줄을 사용하는 경우 레이블 너비 UILabel
와 동기화해야 preferredMaxLayoutWidth
합니다. 나는 이것을하기 위해 커스텀 UILabel
서브 클래스를 사용한다 :
@implementation TSLabel
- (void) layoutSubviews
{
[super layoutSubviews];
if ( self.numberOfLines == 0 )
{
if ( self.preferredMaxLayoutWidth != self.frame.size.width )
{
self.preferredMaxLayoutWidth = self.frame.size.width;
[self setNeedsUpdateConstraints];
}
}
}
- (CGSize) intrinsicContentSize
{
CGSize s = [super intrinsicContentSize];
if ( self.numberOfLines == 0 )
{
// found out that sometimes intrinsicContentSize is 1pt too short!
s.height += 1;
}
return s;
}
@end
다음은 heightForRowAtIndexPath를 보여주는 고안된 UITableViewController 하위 클래스입니다.
#import "TSTableViewController.h"
#import "TSTableViewCell.h"
@implementation TSTableViewController
- (NSString*) cellText
{
return @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
}
#pragma mark - Table view data source
- (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView
{
return 1;
}
- (NSInteger) tableView: (UITableView *)tableView numberOfRowsInSection: (NSInteger) section
{
return 1;
}
- (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath
{
static TSTableViewCell *sizingCell;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sizingCell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell"];
});
// configure the cell
sizingCell.text = self.cellText;
// force layout
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
// get the fitting size
CGSize s = [sizingCell.contentView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];
NSLog( @"fittingSize: %@", NSStringFromCGSize( s ));
return s.height;
}
- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
TSTableViewCell *cell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell" ];
cell.text = self.cellText;
return cell;
}
@end
간단한 커스텀 셀 :
#import "TSTableViewCell.h"
#import "TSLabel.h"
@implementation TSTableViewCell
{
IBOutlet TSLabel* _label;
}
- (void) setText: (NSString *) text
{
_label.text = text;
}
@end
스토리 보드에 정의 된 제약 조건에 대한 그림입니다. 레이블에는 높이 / 너비 제한이 없습니다. 레이블에서 다음과 같이 제한됩니다 intrinsicContentSize
.
답변
에릭 베이커 (Eric Baker)의 의견 은 뷰가 그 안에 배치 된 컨텐츠에 의해 크기를 결정하려면 그 안에 배치 된 컨텐츠가 높이를 높이기 위해 포함하는 뷰와 명시 적 관계를 가져야 한다는 핵심 아이디어를 알려주었습니다. (또는 너비) dynamic . “하위 뷰 추가”는 예상 한대로이 관계를 생성하지 않습니다. 컨테이너의 높이 및 / 또는 너비를 구동 할 서브 뷰를 선택해야합니다. 가장 일반적으로 전체 UI의 오른쪽 하단에 배치 한 UI 요소입니다. 요점을 설명하기위한 코드와 인라인 주석이 있습니다.
이것은 스크롤보기 작업을하는 사람들에게 특히 가치가 있습니다. 단지 내용에 따라 동적으로 크기를 결정하고 스크롤보기와 통신하는 단일 콘텐츠보기를 중심으로 디자인하는 것이 일반적이기 때문에 일반적입니다. 행운을 빌어 요, 이것이 누군가를 도울 수 있기를 바랍니다.
//
// ViewController.m
// AutoLayoutDynamicVerticalContainerHeight
//
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) UIView *contentView;
@property (strong, nonatomic) UILabel *myLabel;
@property (strong, nonatomic) UILabel *myOtherLabel;
@end
@implementation ViewController
- (void)viewDidLoad
{
// INVOKE SUPER
[super viewDidLoad];
// INIT ALL REQUIRED UI ELEMENTS
self.contentView = [[UIView alloc] init];
self.myLabel = [[UILabel alloc] init];
self.myOtherLabel = [[UILabel alloc] init];
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_contentView, _myLabel, _myOtherLabel);
// TURN AUTO LAYOUT ON FOR EACH ONE OF THEM
self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
self.myLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.myOtherLabel.translatesAutoresizingMaskIntoConstraints = NO;
// ESTABLISH VIEW HIERARCHY
[self.view addSubview:self.contentView]; // View adds content view
[self.contentView addSubview:self.myLabel]; // Content view adds my label (and all other UI... what's added here drives the container height (and width))
[self.contentView addSubview:self.myOtherLabel];
// LAYOUT
// Layout CONTENT VIEW (Pinned to left, top. Note, it expects to get its vertical height (and horizontal width) dynamically based on whatever is placed within).
// Note, if you don't want horizontal width to be driven by content, just pin left AND right to superview.
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_contentView]" options:0 metrics:0 views:viewsDictionary]]; // Only pinned to left, no horizontal width yet
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_contentView]" options:0 metrics:0 views:viewsDictionary]]; // Only pinned to top, no vertical height yet
/* WHATEVER WE ADD NEXT NEEDS TO EXPLICITLY "PUSH OUT ON" THE CONTAINING CONTENT VIEW SO THAT OUR CONTENT DYNAMICALLY DETERMINES THE SIZE OF THE CONTAINING VIEW */
// ^To me this is what's weird... but okay once you understand...
// Layout MY LABEL (Anchor to upper left with default margin, width and height are dynamic based on text, font, etc (i.e. UILabel has an intrinsicContentSize))
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_myLabel]" options:0 metrics:0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_myLabel]" options:0 metrics:0 views:viewsDictionary]];
// Layout MY OTHER LABEL (Anchored by vertical space to the sibling label that comes before it)
// Note, this is the view that we are choosing to use to drive the height (and width) of our container...
// The LAST "|" character is KEY, it's what drives the WIDTH of contentView (red color)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_myOtherLabel]-|" options:0 metrics:0 views:viewsDictionary]];
// Again, the LAST "|" character is KEY, it's what drives the HEIGHT of contentView (red color)
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_myLabel]-[_myOtherLabel]-|" options:0 metrics:0 views:viewsDictionary]];
// COLOR VIEWS
self.view.backgroundColor = [UIColor purpleColor];
self.contentView.backgroundColor = [UIColor redColor];
self.myLabel.backgroundColor = [UIColor orangeColor];
self.myOtherLabel.backgroundColor = [UIColor greenColor];
// CONFIGURE VIEWS
// Configure MY LABEL
self.myLabel.text = @"HELLO WORLD\nLine 2\nLine 3, yo";
self.myLabel.numberOfLines = 0; // Let it flow
// Configure MY OTHER LABEL
self.myOtherLabel.text = @"My OTHER label... This\nis the UI element I'm\narbitrarily choosing\nto drive the width and height\nof the container (the red view)";
self.myOtherLabel.numberOfLines = 0;
self.myOtherLabel.font = [UIFont systemFontOfSize:21];
}
@end
답변
구속 조건을 작성하고 인터페이스 빌더를 통해 연결하여이를 수행 할 수 있습니다.
설명 참조 : Auto_Layout_Constraints_in_Interface_Builder
@interface ViewController : UIViewController {
IBOutlet NSLayoutConstraint *leadingSpaceConstraint;
IBOutlet NSLayoutConstraint *topSpaceConstraint;
}
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leadingSpaceConstraint;
이 Constraint 콘센트를 하위 뷰와 연결 Constraint 또는 Super Views Constraint도 연결하고 다음과 같은 요구 사항에 따라 설정하십시오.
self.leadingSpaceConstraint.constant = 10.0;//whatever you want to assign
나는 이것이 그것을 명확히하기를 바랍니다.
답변
subview
더 큰 내부의 경우에는이 작업을 수행 할 수 UIView
있지만에 대해서는 자동으로 작동하지 않습니다 headerViews
. a의 높이 headerView
에 의해 반환 있는지에 의해 결정된다 tableView:heightForHeaderInSection:
당신이 계산해야하므로 height
에 기초 height
의 UILabel
플러스 공간 UIButton
과 하나가 padding
당신이 필요. 다음과 같이해야합니다.
-(CGFloat)tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section {
NSString *s = self.headeString[indexPath.section];
CGSize size = [s sizeWithFont:[UIFont systemFontOfSize:17]
constrainedToSize:CGSizeMake(281, CGFLOAT_MAX)
lineBreakMode:NSLineBreakByWordWrapping];
return size.height + 60;
}
여기에 headerString
당신이를 채우기 위해 원하는 문자열 UILabel
및 281 번호는이다 width
의을 UILabel
(에서 설정으로 Interface Builder
)