자동 레이아웃을 사용하여 tableHeaderView (UITableView)의 높이를 어떻게 설정합니까?
이걸로 지난 3 ~ 4 시간 동안 벽에 머리를 박고 있었는데 알아낼 수없는 것 같습니다. 내부에 전체 화면 UITableView가있는 UIViewController가 있고 (화면에 다른 항목이 있으므로 UITableViewController를 사용할 수 없습니다) 자동 레이아웃으로 tableHeaderView의 크기를 조정하고 싶습니다. 말할 필요도없이 그것은 협력하지 않습니다.
아래 스크린 샷을 참조하십시오.
OverviewLabel (예 : "List overview information here."텍스트)에는 동적 콘텐츠가 있기 때문에 자동 레이아웃을 사용하여 크기를 조정하고 수퍼 뷰입니다. 계층 구조의 Paralax Table View 바로 아래에있는 tableHeaderView를 제외하고는 모든 크기가 멋지게 조정되었습니다.
헤더보기의 크기를 조정하는 유일한 방법은 다음 코드를 사용하는 프로그래밍 방식입니다.
CGRect headerFrame = self.headerView.frame;
headerFrame.size.height = headerFrameHeight;
self.headerView.frame = headerFrame;
[self.listTableView setTableHeaderView:self.headerView];
이 경우 headerFrameHeight는 다음과 같이 tableViewHeader 높이를 수동으로 계산 한 것입니다 (innerHeaderView는 흰색 영역이거나 두 번째 "View", headerView는 tableHeaderView 임) .
CGFloat startingY = self.innerHeaderView.frame.origin.y + self.overviewLabel.frame.origin.y;
CGRect overviewSize = [self.overviewLabel.text
boundingRectWithSize:CGSizeMake(290.f, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: self.overviewLabel.font}
context:nil];
CGFloat overviewHeight = overviewSize.size.height;
CGFloat overviewPadding = ([self.overviewLabel.text length] > 0) ? 10 : 0; // If there's no overviewText, eliminate the padding in the overall height.
CGFloat headerFrameHeight = ceilf(startingY + overviewHeight + overviewPadding + 21.f + 10.f);
수동 계산은 작동하지만 나중에 상황이 변경되면 투박하고 오류가 발생하기 쉽습니다. 내가 할 수 있기를 원하는 것은 다른 곳에서 할 수 있듯이 제공된 제약 조건에 따라 tableHeaderView의 크기를 자동으로 조정하는 것입니다. 하지만 제 삶을 위해 저는 그것을 이해할 수 없습니다.
이것에 대한 여러 게시물이 있지만 명확하지 않아서 나를 더 혼란스럽게 만들었습니다. 다음은 몇 가지입니다.
translatesAutoresizingMaskIntoConstraints 속성을 NO로 변경하는 것은 실제로 의미가 없습니다. 그 이유는 저에게 오류가 발생하고 어쨌든 개념적으로 의미가 없기 때문입니다.
어떤 도움이라도 정말 감사하겠습니다!
편집 1 : TomSwift의 제안 덕분에 알아낼 수있었습니다. 개요의 높이를 수동으로 계산하는 대신 다음과 같이 계산하도록 한 다음 이전과 같이 tableHeaderView를 다시 설정할 수 있습니다.
[self.headerView setNeedsLayout];
[self.headerView layoutIfNeeded];
CGFloat height = [self.innerHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + self.innerHeaderView.frame.origin.y; // adding the origin because innerHeaderView starts partway down headerView.
CGRect headerFrame = self.headerView.frame;
headerFrame.size.height = height;
self.headerView.frame = headerFrame;
[self.listTableView setTableHeaderView:self.headerView];
편집 2 : 다른 사람들이 언급했듯이 편집 1에 게시 된 솔루션이 viewDidLoad에서 작동하지 않는 것 같습니다. 그러나 viewWillLayoutSubviews에서 작동하는 것 같습니다. 아래 예제 코드 :
// Note 1: The variable names below don't match the variables above - this is intended to be a simplified "final" answer.
// Note 2: _headerView was previously assigned to tableViewHeader (in loadView in my case since I now do everything programatically).
// Note 3: autoLayout code can be setup programatically in updateViewConstraints.
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[_headerWrapper setNeedsLayout];
[_headerWrapper layoutIfNeeded];
CGFloat height = [_headerWrapper systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect headerFrame = _headerWrapper.frame;
headerFrame.size.height = height;
_headerWrapper.frame = headerFrame;
_tableView.tableHeaderView = _headerWrapper;
}
UIView systemLayoutSizeFittingSize:
헤더보기의 최소 경계 크기를 얻으려면 메서드 를 사용해야합니다 .
이 Q / A에서이 API 사용에 대한 추가 논의를 제공합니다.
자동 레이아웃을 사용하여 모든 하위보기에 맞게 superview의 크기를 조정하는 방법은 무엇입니까?
나는 정말로 이것과 싸웠고 프레임이 viewDidLoad에 설정되지 않았기 때문에 viewDidLoad에 설정을 꽂아도 작동하지 않았습니다. 또한 헤더의 캡슐화 된 자동 레이아웃 높이가 0으로 줄어들고있는 수많은 지저분한 경고로 끝났습니다. . Form 프레젠테이션에서 tableView를 표시 할 때만 iPad에서 문제를 발견했습니다.
나를 위해 문제를 해결 한 것은 viewDidLoad가 아닌 viewWillLayoutSubviews에서 tableViewHeader를 설정하는 것입니다.
func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if tableView.tableViewHeaderView == nil {
let header: MyHeaderView = MyHeaderView.createHeaderView()
header.setNeedsUpdateConstraints()
header.updateConstraintsIfNeeded()
header.frame = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGFloat.max)
var newFrame = header.frame
header.setNeedsLayout()
header.layoutIfNeeded()
let newSize = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
newFrame.size.height = newSize.height
header.frame = newFrame
self.tableView.tableHeaderView = header
}
}
애니메이션을 사용하거나 사용하지 않고 자동 레이아웃을 사용하여 표 머리글의 크기를 조정하는 우아한 방법을 찾았습니다.
이것을 View Controller에 추가하기 만하면됩니다.
func sizeHeaderToFit(tableView: UITableView) {
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
}
}
동적으로 변경되는 레이블에 따라 크기를 조정하려면 :
@IBAction func addMoreText(sender: AnyObject) {
self.label.text = self.label.text! + "\nThis header can dynamically resize according to its contents."
}
override func viewDidLayoutSubviews() {
// viewDidLayoutSubviews is called when labels change.
super.viewDidLayoutSubviews()
sizeHeaderToFit(tableView)
}
제약 조건의 변경 사항에 따라 크기 조정을 애니메이션하려면 :
@IBOutlet weak var makeThisTallerHeight: NSLayoutConstraint!
@IBAction func makeThisTaller(sender: AnyObject) {
UIView.animateWithDuration(0.3) {
self.tableView.beginUpdates()
self.makeThisTallerHeight.constant += 20
self.sizeHeaderToFit(self.tableView)
self.tableView.endUpdates()
}
}
이 작업을 확인하려면 AutoResizingHeader 프로젝트를 참조하십시오. https://github.com/p-sun/Swift2-iOS9-UI
systemLayoutSizeFittingSize :를 사용하는 솔루션은 헤더보기가 각보기 모양에서 한 번만 업데이트되는 경우 작동합니다. 제 경우에는 헤더보기가 상태 변경을 반영하기 위해 여러 번 업데이트되었습니다. 그러나 systemLayoutSizeFittingSize : 항상 동일한 크기를보고했습니다. 즉, 첫 번째 업데이트에 해당하는 크기입니다.
systemLayoutSizeFittingSize를 얻으려면 : 각 업데이트 후 올바른 크기를 반환하려면 먼저 테이블 헤더 뷰를 제거하고 업데이트하고 다시 추가해야했습니다.
self.listTableView.tableHeaderView = nil;
[self.headerView removeFromSuperview];
이 솔루션은 tableHeaderView의 크기를 조정하고 viewDidLayoutSubviews()
여기에 다른 답변 중 일부를 사용 하는 방법 에서 무한 루프를 방지 합니다.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let headerView = tableView.tableHeaderView {
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
var headerFrame = headerView.frame
// comparison necessary to avoid infinite loop
if height != headerFrame.size.height {
headerFrame.size.height = height
headerView.frame = headerFrame
tableView.tableHeaderView = headerView
}
}
}
이 게시물도 참조하십시오 : https://stackoverflow.com/a/34689293/1245231
이것은 ios10 및 Xcode 8에서 나를 위해 일했습니다.
func layoutTableHeaderView() {
guard let headerView = tableView.tableHeaderView else { return }
headerView.translatesAutoresizingMaskIntoConstraints = false
let headerWidth = headerView.bounds.size.width;
let temporaryWidthConstraints = NSLayoutConstraint.constraintsWithVisualFormat("[headerView(width)]", options: NSLayoutFormatOptions(rawValue: UInt(0)), metrics: ["width": headerWidth], views: ["headerView": headerView])
headerView.addConstraints(temporaryWidthConstraints)
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let headerSize = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
let height = headerSize.height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
self.tableView.tableHeaderView = headerView
headerView.removeConstraints(temporaryWidthConstraints)
headerView.translatesAutoresizingMaskIntoConstraints = true
}
머리글보기와 바닥 글 모두에서 작동합니다. 머리글을 바닥 글로 바꿉니다.
func sizeHeaderToFit() {
if let headerView = tableView.tableHeaderView {
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
var frame = headerView.frame
frame.size.height = height
headerView.frame = frame
tableView.tableHeaderView = headerView
}
}
제 경우에는 viewDidLayoutSubviews
더 잘 작동했습니다. viewWillLayoutSubviews
a의 흰색 선이 tableView
나타납니다. 또한 내 headerView
개체가 이미 있는지 확인하는 기능을 추가했습니다 .
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if ( ! self.userHeaderView ) {
// Setup HeaderView
self.userHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"SSUserHeaderView" owner:self options:nil] objectAtIndex:0];
[self.userHeaderView setNeedsLayout];
[self.userHeaderView layoutIfNeeded];
CGFloat height = [self.userHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
CGRect headerFrame = self.userHeaderView.frame;
headerFrame.size.height = height;
self.userHeaderView.frame = headerFrame;
self.tableView.tableHeaderView = self.userHeaderView;
// Update HeaderView with data
[self.userHeaderView updateWithProfileData];
}
}
UIView
AL 내부 서브 뷰 구조와 함께 일반 AutoLayout 기반 을 tableHeaderView
.
필요한 것은 tableFooterView
이전 에 간단한 설정입니다 !
하자가 self.headerView
일부 제약 기반입니다 UIView
.
- (void)viewDidLoad {
........................
self.tableView.tableFooterView = [UIView new];
[self.headerView layoutIfNeeded]; // to set initial size
self.tableView.tableHeaderView = self.headerView;
[self.tableView.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor].active = YES;
[self.tableView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
[self.tableView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor].active = YES;
// and the key constraint
[self.tableFooterView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
}
self.headerView
UI 회전에서 높이가 변경 되면 구현해야합니다.
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition: ^(id<UIViewControllerTransitionCoordinatorContext> context) {
// needed to resize header height
self.tableView.tableHeaderView = self.headerView;
} completion: NULL];
}
이 목적으로 ObjC 카테고리를 사용할 수 있습니다.
@interface UITableView (AMHeaderView)
- (void)am_insertHeaderView:(UIView *)headerView;
@end
@implementation UITableView (AMHeaderView)
- (void)am_insertHeaderView:(UIView *)headerView {
NSAssert(self.tableFooterView, @"Need to define tableFooterView first!");
[headerView layoutIfNeeded];
self.tableHeaderView = headerView;
[self.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor].active = YES;
[self.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor].active = YES;
[self.topAnchor constraintEqualToAnchor:headerView.topAnchor].active = YES;
[self.tableFooterView.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor].active = YES;
}
@end
또한 Swift 확장
extension UITableView {
func am_insertHeaderView2(_ headerView: UIView) {
assert(tableFooterView != nil, "Need to define tableFooterView first!")
headerView.layoutIfNeeded()
tableHeaderView = headerView
leadingAnchor.constraint(equalTo: headerView.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true
tableFooterView?.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
}
}
이 솔루션은 저에게 완벽하게 작동합니다.
https://spin.atomicobject.com/2017/08/11/swift-extending-uitableviewcontroller/
UITableViewController를 확장합니다. 그러나 UITableView를 사용하는 경우에도 여전히 작동합니다. UITableViewController 대신 UITableView를 확장하기 만하면됩니다. 메서드를 호출 sizeHeaderToFit()
하거나 높이 sizeFooterToFit()
를 변경하는 이벤트가있을 때마다 호출합니다 tableViewHeader
.
'development' 카테고리의 다른 글
왜 그리고 언제 Liquibase입니까? (0) | 2020.09.22 |
---|---|
Pandas timeseries 플롯 설정 x 축 주 및 부 눈금 및 레이블 (0) | 2020.09.22 |
내 서버에서 실행할 수있는 Github 복제본이 PHP에 있습니까? (0) | 2020.09.22 |
Google Analytics libAdIdAccess.a에 비트 코드가 포함되어 있지 않습니다. (0) | 2020.09.22 |
SQL Server 2005에서 MySQL로 데이터를 내보내는 방법 (0) | 2020.09.22 |