내가 AutoLayout
어디서나 그것을 사용한다는 것을 알았 기 때문에 이제는 tableHeaderView
.
내가 만든 subclass
의 UIView
(라벨 등) 그때 나는이 추가, 자신의 제약 원 추가 모든 CustomView
받는 UITableView
‘ tableHeaderView
.
모든이를 제외하고 잘 작동 UITableView
항상 표시 위에CustomView
에 의해 위의 나는 의미 CustomView
입니다 아래UITableView
이 볼 수 없도록!
내가 무엇을하든 ‘ height
of the UITableView
‘ tableHeaderView
는 항상 0 인 것 같습니다 (너비, x 및 y).
내 질문 : 프레임을 수동으로 설정하지 않고도이 작업을 수행 할 수 있습니까?
편집 : 내가 사용
하는 CustomView
‘ subview
에는 다음과 같은 제약이 있습니다.
_title = [[UILabel alloc]init];
_title.text = @"Title";
[self addSubview:_title];
[_title keep:[KeepTopInset rules:@[[KeepEqual must:5]]]]; // title has to stay at least 5 away from the supperview Top
[_title keep:[KeepRightInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepLeftInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepBottomInset rules:@[[KeepMin must:5]]]];
제약 조건을 수동으로 작성하려면 하나의 제약 조건에 대해 너무 많은 줄이 필요하지만 메서드는 자체 설명이 가능하기 때문에 편리한 라이브러리 ‘KeepLayout’을 사용하고 있습니다.
그리고 UITableView
다음과 같은 제약이 있습니다.
_tableView = [[UITableView alloc]init];
_tableView.translatesAutoresizingMaskIntoConstraints = NO;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_tableView];
[_tableView keep:[KeepTopInset rules:@[[KeepEqual must:0]]]];// These 4 constraints make the UITableView stays 0 away from the superview top left right and bottom.
[_tableView keep:[KeepLeftInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepRightInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepBottomInset rules:@[[KeepEqual must:0]]]];
_detailsView = [[CustomView alloc]init];
_tableView.tableHeaderView = _detailsView;
에서 직접 제약 조건을 설정해야하는지 모르겠지만 CustomView
CustomView의 높이는 UILabel
“제목”에 대한 제약 조건에 의해 결정 된다고 생각합니다.
편집 2 : 다른 조사 후 CustomView의 높이와 너비가 올바르게 계산 된 것 같지만 CustomView의 상단은 여전히 UITableView의 상단과 동일한 수준이며 스크롤 할 때 함께 이동합니다.
답변
나는 여기 에서 비슷한 질문을하고 대답했다 . 요약하면 헤더를 한 번 추가하고 필요한 높이를 찾는 데 사용합니다. 그런 다음 해당 높이를 헤더에 적용 할 수 있으며 헤더는 변경 사항을 반영하기 위해 두 번째로 설정됩니다.
- (void)viewDidLoad
{
[super viewDidLoad];
self.header = [[SCAMessageView alloc] init];
self.header.titleLabel.text = @"Warning";
self.header.subtitleLabel.text = @"This is a message with enough text to span multiple lines. This text is set at runtime and might be short or long.";
//set the tableHeaderView so that the required height can be determined
self.tableView.tableHeaderView = self.header;
[self.header setNeedsLayout];
[self.header layoutIfNeeded];
CGFloat height = [self.header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
//update the header's frame and set it again
CGRect headerFrame = self.header.frame;
headerFrame.size.height = height;
self.header.frame = headerFrame;
self.tableView.tableHeaderView = self.header;
}
여러 줄 레이블이있는 경우 각 레이블의 preferredMaxLayoutWidth를 설정하는 사용자 정의보기에도 의존합니다.
- (void)layoutSubviews
{
[super layoutSubviews];
self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}
또는 더 일반적으로 :
override func layoutSubviews() {
super.layoutSubviews()
for view in subviews {
guard let label = view as? UILabel where label.numberOfLines == 0 else { continue }
label.preferredMaxLayoutWidth = CGRectGetWidth(label.frame)
}
}
2015 년 1 월 업데이트
불행히도 이것은 여전히 필요한 것 같습니다. 다음은 레이아웃 프로세스의 빠른 버전입니다.
tableView.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
tableView.tableHeaderView = header
이것을 UITableView의 확장으로 옮기는 것이 유용하다는 것을 알았습니다.
extension UITableView {
//set the tableHeaderView so that the required height can be determined, update the header's frame and set it again
func setAndLayoutTableHeaderView(header: UIView) {
self.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
self.tableHeaderView = header
}
}
용법:
let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)
답변
제약 조건 (코드)을 사용하여 헤더보기를 추가 할 수 없습니다. 내 뷰에 너비 및 / 또는 높이 제약 조건을 지정하면 다음과 같은 메시지와 함께 충돌이 발생합니다.
"terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super."
스토리 보드의 뷰를 테이블 뷰에 추가하면 제약이없고 헤더 뷰로 잘 작동하므로 제약 조건을 사용하여 헤더 뷰의 배치가 수행되지 않는다고 생각합니다. 그런 점에서 정상적인 견해처럼 행동하지 않는 것 같습니다.
너비는 자동으로 테이블보기의 너비이며, 설정해야하는 유일한 것은 높이입니다. 원점 값은 무시되므로 입력 한 값은 중요하지 않습니다. 예를 들어, 이것은 잘 작동했습니다 (rect의 경우 0,0,0,80처럼).
UIView *headerview = [[UIView alloc] initWithFrame:CGRectMake(1000,1000, 0, 80)];
headerview.backgroundColor = [UIColor yellowColor];
self.tableView.tableHeaderView = headerview;
답변
여기에서 불필요한 작업을 많이하는 많은 방법을 보았지만 헤더보기에서 자동 레이아웃을 사용하는 데 그다지 많이 필요하지 않습니다. xib 파일을 만들고 제약 조건을 설정하고 다음과 같이 인스턴스화하면됩니다.
func loadHeaderView () {
guard let headerView = Bundle.main.loadNibNamed("CourseSearchHeader", owner: self, options: nil)?[0] as? UIView else {
return
}
headerView.autoresizingMask = .flexibleWidth
headerView.translatesAutoresizingMaskIntoConstraints = true
tableView.tableHeaderView = headerView
}
답변
또 다른 해결책은 헤더 뷰 생성을 다음 메인 스레드 호출로 디스패치하는 것입니다.
- (void)viewDidLoad {
[super viewDidLoad];
// ....
dispatch_async(dispatch_get_main_queue(), ^{
_profileView = [[MyView alloc] initWithNib:@"MyView.xib"];
self.tableView.tableHeaderView = self.profileView;
});
}
참고 :로드 된 뷰의 높이가 고정 된 경우 버그를 수정합니다. 헤더 높이가 콘텐츠에만 의존 할 때 시도하지 않았습니다.
편집하다 :
이 함수 를 구현 하고 호출 하여이 문제에 대한 더 깨끗한 해결책을 찾을 수 있습니다 .viewDidLayoutSubviews
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self sizeHeaderToFit];
}
답변
암호:
extension UITableView {
func sizeHeaderToFit(preferredWidth: CGFloat) {
guard let headerView = self.tableHeaderView else {
return
}
headerView.translatesAutoresizingMaskIntoConstraints = false
let layout = NSLayoutConstraint(
item: headerView,
attribute: .Width,
relatedBy: .Equal,
toItem: nil,
attribute:
.NotAnAttribute,
multiplier: 1,
constant: preferredWidth)
headerView.addConstraint(layout)
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
headerView.frame = CGRectMake(0, 0, preferredWidth, height)
headerView.removeConstraint(layout)
headerView.translatesAutoresizingMaskIntoConstraints = true
self.tableHeaderView = headerView
}
}
답변
이 솔루션 http://collindonnell.com/2015/09/29/dynamically-sized-table-view-header-or-footer-using-auto-layout/ 을 테이블 바닥 글보기로 확장했습니다 .
@interface AutolayoutTableView : UITableView
@end
@implementation AutolayoutTableView
- (void)layoutSubviews {
[super layoutSubviews];
// Dynamic sizing for the header view
if (self.tableHeaderView) {
CGFloat height = [self.tableHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect headerFrame = self.tableHeaderView.frame;
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if (height != headerFrame.size.height) {
headerFrame.size.height = height;
self.tableHeaderView.frame = headerFrame;
self.tableHeaderView = self.tableHeaderView;
}
[self.tableHeaderView layoutIfNeeded];
}
// Dynamic sizing for the footer view
if (self.tableFooterView) {
CGFloat height = [self.tableFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect footerFrame = self.tableFooterView.frame;
// If we don't have this check, viewDidLayoutSubviews() will get
// repeatedly, causing the app to hang.
if (height != footerFrame.size.height) {
footerFrame.size.height = height;
self.tableFooterView.frame = footerFrame;
self.tableFooterView = self.tableFooterView;
}
self.tableFooterView.transform = CGAffineTransformMakeTranslation(0, self.contentSize.height - footerFrame.size.height);
[self.tableFooterView layoutIfNeeded];
}
}
@end
답변
systemLayoutSizeFittingSize 메서드 를 사용하여 크기를 제공하는 자동 레이아웃을 얻을 수 있습니다 .
그런 다음이를 사용하여 응용 프로그램의 프레임을 만들 수 있습니다. 이 기술은 내부적으로 자동 레이아웃을 사용하는 뷰의 크기를 알아야 할 때마다 작동합니다.
신속한 코드는 다음과 같습니다.
//Create the view
let tableHeaderView = CustomTableHeaderView()
//Set the content
tableHeaderView.textLabel.text = @"Hello world"
//Ask auto layout for the smallest size that fits my constraints
let size = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
//Create a frame
tableHeaderView.frame = CGRect(origin: CGPoint.zeroPoint, size: size)
//Set the view as the header
self.tableView.tableHeaderView = self.tableHeaderView
또는 Objective-C에서
//Create the view
CustomTableHeaderView *header = [[CustomTableHeaderView alloc] initWithFrame:CGRectZero];
//Set the content
header.textLabel.text = @"Hello world";
//Ask auto layout for the smallest size that fits my constraints
CGSize size = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
//Create a frame
header.frame = CGRectMake(0,0,size.width,size.height);
//Set the view as the header
self.tableView.tableHeaderView = header
이 특정 인스턴스에서 하위 클래스에서 requiresConstraintBasedLayout을 재정의하면 레이아웃 패스가 수행되지만이 레이아웃 패스의 결과는 무시되고 시스템 프레임이 tableView의 너비와 높이 0으로 설정됩니다.