UITableView의 tableHeaderView와 함께 AutoLayout을 사용할 수 있습니까?


97

내가 AutoLayout어디서나 그것을 사용한다는 것을 알았 기 때문에 이제는 tableHeaderView.

내가 만든 subclassUIView(라벨 등) 그때 나는이 추가, 자신의 제약 원 추가 모든 CustomView받는 UITableView' tableHeaderView.

모든이를 제외하고 잘 작동 UITableView항상 표시 위에CustomView 에 의해 위의 나는 의미 CustomView입니다 아래UITableView 이 볼 수 없도록!

내가 무엇을하든 ' heightof 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;

에서 직접 제약 조건을 설정해야하는지 모르겠지만 CustomViewCustomView의 높이는 UILabel"제목"에 대한 제약 조건에 의해 결정 된다고 생각합니다.

편집 2 : 다른 조사 후 CustomView의 높이와 너비가 올바르게 계산 된 것 같지만 CustomView의 상단은 여전히 ​​UITableView의 상단과 동일한 수준이며 스크롤 할 때 함께 이동합니다.


예, 가능합니다. 사용중인 코드를 보여줄 수 있습니까? 헤더 뷰에 어떤 제약을 설정했는지 모르고 조언하기는 어렵습니다.
jrturton

이를 수행하는 쉬운 방법은 IB의 해당 뷰를 tableView 에 추가하는 것입니다. 테이블 뷰를 포함하는 동일한 장면에 뷰를 생성 하고 테이블로 드래그 하기 만하면 됩니다.
Mariam K.

IB를 최대한 피하려고 노력하고 있습니다. 지금까지는 사용할 필요가 없었습니다. 작동하지 않으면 IB를 사용해 보겠습니다
ItsASecret

1
Apple은 개발자에게 자동 레이아웃과 관련하여 가능한 한 IB를 사용하도록 권장합니다. 많은 불일치 문제를 피하는 데 정말 도움이됩니다.
Mariam K.

진정한 완전 자동 레이아웃 솔루션은 여기
malex

답변:


134

나는 여기 에서 비슷한 질문을하고 대답했다 . 요약하면 헤더를 한 번 추가하고 필요한 높이를 찾는 데 사용합니다. 그런 다음 해당 높이를 헤더에 적용 할 수 있으며 헤더는 변경 사항을 반영하기 위해 두 번째로 설정됩니다.

- (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)

8
를 사용하는 대신를 사용 preferredMaxLayoutWidth하기 전에 헤더보기에 너비 제한 (테이블보기의 너비와 동일)을 추가하는 것 systemLayoutSizeFittingSize:입니다.
Benjohn 2015-07-28

2
참고 : 헤더가 첫 번째 셀 위에있는 경우 헤더 속성을 다음으로 재설정하는 것을 잊은 것입니다.self.tableView.tableHeaderView
Laszlo

8
이와 같이 완전히 사소한 일을하는 것이 얼마나 까다로운 지 종종 놀랍습니다.
TylerJames

5
참고 : tableView와 같은 정확한 너비를 let height = header.systemLayoutSizeFittingSize(CGSizeMake(CGRectGetWidth(self.bounds), 0), withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityFittingSizeLevel).height
가져와야

3
Just Use header.setNeedsLayout() header.layoutIfNeeded() header.frame.size = header.systemLayoutSizeFitting(UILayoutFittingCompressedSize) self.tableHeaderView = header는 iOS 10.2에서 작동합니다
Kesong Xie 2017

24

제약 조건 (코드)을 사용하여 헤더보기를 추가 할 수 없습니다. 내 뷰에 너비 및 / 또는 높이 제약 조건을 지정하면 다음과 같은 메시지와 함께 충돌이 발생합니다.

 "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;

나는 그 예외도 있었지만 UITableView에 카테고리를 추가하면 그 대답에서 그것을 찾았습니다 : stackoverflow.com/questions/12610783/…
ItsASecret

나는 여전히 당신이 제안한 것을 시도 할 것입니다. 그러나 내일 아침은 1:34입니다. 나는 잠자리에들 것입니다. 시간을내어 대답 해 주셔서 대단히 감사합니다! (하지만 높이를 지정하고 싶지 않습니다. CustomView의 레이블에 설정 한 제약 조건으로 계산하고 싶습니다.)
ItsASecret

나는 그것을 시도했고 네 프레임 설정은 작동하지만 프레임 설정을 피할 방법을 찾고 있었지만 계속 찾고 다른 것을 찾지 못하면 대답을 받아 들일 것입니다
ItsASecret

1
추가 된 헤더 뷰에 translatesAutoresizingMaskIntoConstraints = NO. 번역을 켜면 오류가 방지 UITableView됩니다. 7.1부터는 헤더 뷰를 자동 레이아웃하려고하지 않으며 프레임 사전 설정으로 무언가를 원합니다.
Benjohn 2015-07-28

17

여기에서 불필요한 작업을 많이하는 많은 방법을 보았지만 헤더보기에서 자동 레이아웃을 사용하는 데 그다지 많이 필요하지 않습니다. 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
    }

이것은 또한 여러 줄 레이블이있는 동적 높이 헤더가있는 iOS 11에서도 우리에게 효과적이었습니다.
Ben Scheirman

1
물론 IB에서 flexibleHeight-Autoresizing-Option을 제거 할 수도 있습니다.
d4Rk

나는 내 tableFooterView (xib / nib를 통해)의 높이를 설정하려고 시도했지만 프레임, 높이, layoutIfNeeded () 등을 설정하는 데 성공하지 못했습니다.하지만이 솔루션을 통해 마침내 설정이 가능해졌습니다.
vikzilla

xib 파일의 전체보기에 높이 제한을 설정하는 것을 잊지 마십시오.
Denis Kutlubaev

6

또 다른 해결책은 헤더 뷰 생성을 다음 메인 스레드 호출로 디스패치하는 것입니다.

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

1
@TussLaszlo tableHeaderView는 자동 레이아웃에 버그가 있습니다. 이와 같은 몇 가지 해결 방법이 있습니다. 내가 쓴 이후로, 나는 여기에 더 청소기 솔루션을 발견했습니다 stackoverflow.com/a/21099430/127493 의 호출 해 - (void)sizeHeaderToFitviewDidLayoutSubviews
마틴

4

암호:

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

모든 tableheaderview 하위보기에 적절한 자동 레이아웃 제약 조건을 부여하십시오. 하나의 제약 조건을 놓치면 작동하지 않습니다.
abhimuralidharan

4

이 솔루션 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

어제 tableHeader가 자동으로 크기 조정 / 레이아웃되도록하는 데 하루를 보냈습니다. 이 솔루션은 저에게 효과적입니다. 무리 감사.
docchang

안녕하세요! self.tableFooterView.transform부분을 설명해 주 시겠습니까? 왜 필요한가요?
mrvn

@mrvn 변환은 바닥 글을 tableView의 맨 아래로 이동하는 데 사용됩니다.
k06a

3

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으로 설정됩니다.


3

다음은 나를 위해 일했습니다.

  1. UIView헤더보기로 일반 오래된 것을 사용하십시오 .
  2. 그것에 하위보기 추가 UIView
  3. 하위보기에서 자동 레이아웃 사용

내가 보는 주요 이점은 프레임 계산을 제한하는 것입니다. 애플은 UITableView이 작업을 더 쉽게하기 위해의 API를 업데이트해야합니다 .

SnapKit을 사용한 예 :

let layoutView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 60))
layoutView.backgroundColor = tableView.backgroundColor
tableView.tableHeaderView = layoutView

let label = UILabel()
layoutView.addSubview(label)
label.text = "I'm the view you really care about"
label.snp_makeConstraints { make in
    make.edges.equalTo(EdgeInsets(top: 10, left: 15, bottom: -5, right: -15))
}

3

이상한 일이 일어납니다. systemLayoutSizeFittingSize는 iOS9에서는 잘 작동하지만 제 경우에는 iOS 8에서는 작동하지 않습니다. 따라서이 문제는 아주 쉽게 해결됩니다. CGRectGetMaxY (yourview.frame) + padding으로 높이를 삽입하여 헤더보기 경계를 슈퍼 호출 업데이트 한 후 헤더 및 viewDidLayoutSubviews의 하단보기에 대한 링크를 가져옵니다.

UPD : 가장 쉬운 솔루션 : 헤더보기에서 하위보기를 배치하고 왼쪽 , 오른쪽 , 상단에 고정 합니다. 그 하위보기에서 자동 높이 제한으로 하위보기를 배치하십시오. 그 후 모든 작업을 자동 레이아웃에 제공 (계산이 필요하지 않음)

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    CGFloat height = CGRectGetMaxY(self.tableView.tableHeaderView.subviews.firstObject.frame);
    self.tableView.tableHeaderView.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
    self.tableView.tableHeaderView = self.tableView.tableHeaderView;
}

결과적으로 하위 뷰가 확장 / 축소되고 결국에는 viewDidLayoutSubviews를 호출합니다. 당시 우리는 뷰의 실제 크기를 알고 있으므로 headerView 높이를 설정하고 다시 할당하여 업데이트합니다. 매력처럼 작동합니다!

바닥 글보기에서도 작동합니다.


1
아이폰 OS (10)에 나를 위해이 루프
사이먼

3

Swift 4.2 업데이트

extension UITableView {

    var autolayoutTableViewHeader: UIView? {
        set {
            self.tableHeaderView = newValue
            guard let header = newValue else { return }
            header.setNeedsLayout()
            header.layoutIfNeeded()
            header.frame.size = 
            header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
            self.tableHeaderView = header
        }
        get {
            return self.tableHeaderView
        }
    }
}

2

헤더와 테이블 뷰 사이에 상단 + 수평 위치 제약을 추가하여 올바르게 배치 할 수 있습니다 (헤더 자체에 올바른 프레임을 갖는 데 필요한 모든 내부 레이아웃 제약이 포함되어있는 경우).

tableViewController viewDidLoad 메소드에서

    headerView.translatesAutoresizingMaskIntoConstraints = false

    tableView.tableHeaderView = headerView

    headerView.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true
    headerView.topAnchor.constraint(equalTo: tableView.topAnchor).isActive = true
    headerView.centerXAnchor.constraint(equalTo: tableView.centerXAnchor).isActive = true

1

내 테이블 헤더 뷰는 UIView 하위 클래스입니다. 이니셜 라이저 내에 단일 contentView UIView를 만들고 테이블 헤더 뷰의 프레임과 동일한 경계를 사용하여 모든 개체를 하위 뷰로 추가했습니다.

그런 다음 layoutSubviews이니셜 라이저가 아닌 테이블 헤더 뷰의 메서드 내에서 개체에 대한 제약 조건을 추가합니다 . 그것이 충돌을 해결했습니다.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:CGRectMake(0, 0, 0, 44.0)];
    if (self) {
        UIView *contentView = [[UIView alloc] initWithFrame:self.bounds];
        contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;

        // add other objects as subviews of content view

    }
    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    // remake constraints here
}

1

내 AutoLayout이 매우 잘 작동합니다.

CGSize headerSize = [headerView systemLayoutSizeFittingSize:CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), 0) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
headerView.frame = CGRectMake(0, 0, headerSize.width, headerSize.height);
self.tableView.tableHeaderView = headerView;

이 작업을 정확히 수행하지는 않았지만 headerView를 제거하고 프레임을 재설정 한 다음 다시 추가하는 좋은 아이디어를 주셨습니다.
dinesharjani

1

대부분의 경우 최상의 솔루션은 프레임 워크와 싸우지 않고 자동 크기 조정 마스크를 채택하는 것입니다.

// embrace autoresizing masks and let the framework add the constraints for you
headerView.translatesAutoresizingMaskIntoConstraints = true
headerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

// figure out what's the best size based on the table view width
let width = self.tableView.frame.width
let targetSize = headerView.systemLayoutSizeFitting(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
headerView.frame.size = targetSize
self.tableView.tableHeaderView = headerView

자동 크기 조정 마스크를 사용하면 수퍼 뷰가 크기를 변경할 때 뷰의 크기가 어떻게 변경되어야하는지 프레임 워크에 알려줍니다. 그러나이 변경 사항은 설정 한 초기 프레임을 기반으로합니다.


0

나는 이것이 오래된 게시물이라는 것을 알고 있지만 이것에 관한 모든 게시물을 검토하고 이것으로 오후 내내 놀고 나서 마침내 깨끗하고 매우 간단한 해결책을 찾았습니다.

우선 내 뷰 계층 구조는 다음과 같습니다.

  1. 테이블보기
    1. 전망 tableHeaderView
      1. headerView 라는 콘센트로 보기

이제 View (No.3) 내에서 일반적으로 컨테이너에 대한 바닥 공간을 포함하는 것처럼 모든 제약 조건을 설정했습니다. 그러면 컨테이너 (즉, 3.View 즉 headerView)가 하위 뷰와 제약 조건에 따라 자체 크기가 조정됩니다.

그 후, 3. View과 사이의 제약 조건을 설정했습니다 2. View.

  1. 컨테이너까지의 상단 공간 : 0
  2. 컨테이너까지의 선행 공간 : 0
  3. 컨테이너까지의 후행 공간 : 0

의도적으로 바닥 공간을 의도적으로 생략했습니다.

이 모든 작업이 스토리 보드에서 완료되면 남은 작업은 다음 세 줄의 코드를 붙여 넣는 것입니다.

if (self.headerView.frame.size.height != self.tableView.tableHeaderView.frame.size.height) {
    UIView *header = self.tableView.tableHeaderView;
    CGRect frame = self.tableView.tableHeaderView.frame;
    frame.size.height = self.headerView.frame.size.height + frame.origin.y;
    header.frame = frame;
    self.tableView.tableHeaderView = header;
}

0

팁 : setAndLayoutTableHeaderView 메소드를 사용하는 경우 서브 뷰의 프레임을 업데이트해야합니다. 따라서이 상황에서 UILabel의 preferredMaxLayoutWidth는 systemLayoutSizeFittingSize가 호출되기 전에 호출해야합니다. layoutSubview에서 호출하지 마십시오.

코드 쇼


0

내 접근 방식을 공유하십시오.

UITableView+XXXAdditions.m

- (void)xxx_setTableHeaderView:(UIView *)tableHeaderView layoutBlock:(void(^)(__kindof UIView *tableHeaderView, CGFloat *containerViewHeight))layoutBlock {
      CGFloat containerViewHeight = 0;
      UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
      [backgroundView addSubview:tableHeaderView];
      layoutBlock(tableHeaderView, &containerViewHeight);

      backgroundView.frame = CGRectMake(0, 0, 0, containerViewHeight);

      self.tableHeaderView = backgroundView;
}

용법.

[self.tableView xxx_setTableHeaderView:myView layoutBlock:^(__kindof UIView * _Nonnull tableHeaderView, CGFloat *containerViewHeight) {
    *containerViewHeight = 170;

    [tableHeaderView mas_makeConstraints:^(MASConstraintMaker *make) {
      make.top.equalTo(@20);
      make.centerX.equalTo(@0);
      make.size.mas_equalTo(CGSizeMake(130, 130));
    }];
  }];

0

내 경우에는 어떤 이유로 systemLayoutSizeFittingSize를 사용하는 방법이 작동하지 않았습니다. 나를 위해 일한 것은 HotJard가 게시 한 솔루션의 수정입니다 (그의 원래 솔루션은 iOS 8에서 제 경우에도 작동하지 않았습니다). 내가해야 할 일은 헤더보기에서 하위보기를 배치하고 왼쪽, 오른쪽, 상단에 고정하는 것입니다 (아래에 고정하지 마십시오). 자동 레이아웃을 사용하는 모든 것을 해당 하위 뷰에 넣고 코드에서 다음을 수행하십시오.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self resizeHeaderToFitSubview];
}

- (void)resizeHeaderToFitSubview
{
    UIView *header = self.tableView.tableHeaderView;
    [header setNeedsLayout];
    [header layoutIfNeeded];
    CGFloat height = CGRectGetHeight(header.subviews.firstObject.bounds);
    header.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
    self.tableView.tableHeaderView = nil;
    self.tableView.tableHeaderView = header;
}

0

오래된 게시물. 그러나 좋은 게시물입니다. 여기 내 2 센트입니다.

첫째, 헤더 뷰가 고유 한 콘텐츠 크기를 지원할 수 있도록 제약 조건이 배열되어 있는지 확인합니다. 그런 다음 다음을 수행하십시오.

//ViewDidLoad
headerView.translatesAutoresizingMaskIntoConstraints = false
headerView.configure(title: "Some Text A")

//Somewhere else
headerView.update(title: "Some Text B)

private var widthConstrained = false

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if widthConstrained == false {
        widthConstrained = true
        tableView.addConstraint(NSLayoutConstraint(item: headerView, attribute: .width, relatedBy: .equal, toItem: tableView, attribute: .width, multiplier: 1, constant: 0))
        headerView.layoutIfNeeded()
        tableView.layoutIfNeeded()
    }
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: { (context) in
        self.headerView.layoutIfNeeded()
        self.tableView.layoutIfNeeded()
    }, completion: nil)
}

0

나는 다음과 같은 접근 방식으로 그것을 달성 할 수있었습니다 (이것은 바닥 글에서도 같은 방식으로 작동합니다).

먼저 작은 UITableView확장 이 필요 합니다.

스위프트 3

extension UITableView {
    fileprivate func adjustHeaderHeight() {
        if let header = self.tableHeaderView {
            adjustFrame(header)
        }
    }

    private func adjustFrame(_ view: UIView) {
        view.frame.size.height = calculatedViewHeight(view)
    }

    fileprivate func calculatedHeightForHeader() -> CGFloat {
        if let header = self.tableHeaderView {
            return calculatedViewHeight(header)
        }
        return 0.0
    }

    private func calculatedViewHeight(_ view: UIView) -> CGFloat {
        view.setNeedsLayout()
        let height = view.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        return height
    }
}

보기 컨트롤러 클래스 구현에서 :

// this is a UIView subclass with autolayout
private var headerView = MyHeaderView()

override func loadView() {
    super.loadView()
    // ...
    self.tableView.tableHeaderView = headerView
    self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension
    // ...
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    // this is to prevent recursive layout calls
    let requiredHeaderHeight = self.tableView.calculatedHeightForHeader()
    if self.headerView.frame.height != requiredHeaderHeight {
        self.tableView.adjustHeaderHeight()
    }
}

헤더 UIView의 하위보기 구현 에 대한 참고 사항 :

  1. 헤더보기에 올바른 자동 레이아웃 설정이 있는지 100 % 확인해야합니다. 하나의 heigh 제약 조건으로 간단한 헤더보기로 시작하고 위의 설정을 시도하는 것이 좋습니다.

  2. 재정의 requiresConstraintBasedLayout및 반환 true:

.

class MyHeaderView: UIView {
   // ...
   override static var requiresConstraintBasedLayout : Bool {
       return true
   }
   // ...
}

0

Xamarin 사용자의 경우 :

public override void ViewDidLayoutSubviews()
{
    base.ViewDidLayoutSubviews();

    TableviewHeader.SetNeedsLayout();
    TableviewHeader.LayoutIfNeeded();

    var height = TableviewHeader.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize).Height;
    var frame = TableviewHeader.Frame;
    frame.Height = height;
    TableviewHeader.Frame = frame;
}

tableview의 헤더 뷰를 TableviewHeader로 명명했다고 가정합니다.


0

여기에서 할 수있는 방법은 UIViewController

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if headerView.frame.size.height == 0 {
      headerView.label.preferredMaxLayoutWidth = view.bounds.size.width - 20
      let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height

      headerView.frame.size = CGSize(width: tableView.bounds.size.width, height: height)
    }
  }

0

제약 기반 모든 UIView것이 좋습니다 tableHeaderView.

하나의 요구는을 설정 tableFooterView하기 전에 다음에 추가 후행 제약 조건을 부과 tableFooterView하고 tableHeaderView.

- (void)viewDidLoad {

    ........................
    // let self.headerView is some constraint-based UIView
    self.tableView.tableFooterView = [UIView new];
    [self.headerView layoutIfNeeded];
    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;
    [self.tableFooterView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;

}

여기에서 모든 세부 정보와 코드 스 니펫을 찾을 수 있습니다.


0

해결 방법을 찾았습니다. 자동 레이아웃 wrriten xib 헤더 뷰를 빈 uiview 래퍼에 래핑하고 헤더 뷰를 tableView의 tableViewHeader 속성에 할당합니다.

    UIView *headerWrapper = [[UIView alloc] init];
    AXLHomeDriverHeaderView *headerView = [AXLHomeDriverHeaderView loadViewFromNib];
    [headerWrapper addSubview:headerView];
    [headerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(headerWrapper);
    }];
    self.tableView.tableHeaderView = headerView;

0

다음은 iOS 12의 UITableViewController에서 작동하는 것입니다.

머리글의 모든 프로토 타입 셀 위와 바닥 글의 모든 프로토 타입 셀 아래에 UIView를 TableView에 드 래핑합니다. 필요에 따라 머리글과 바닥 글을 설정하십시오. 필요한 모든 제약을 설정합니다.

이제 다음 확장 방법을 사용하십시오.

public static class UITableVIewExtensions
{

    public static void MakeHeaderAutoDimension(this UITableView tableView)
    {
        if (tableView.TableHeaderView is UIView headerView) {
            var size = headerView.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
            if (headerView.Frame.Size.Height != size.Height) {
                var frame = headerView.Frame;
                frame.Height = size.Height;
                headerView.Frame = frame;
                tableView.TableHeaderView = headerView;
                tableView.LayoutIfNeeded();
            }
        }
    }

    public static void MakeFooterAutoDimension(this UITableView tableView)
    {
        if (tableView.TableFooterView is UIView footerView) {
            var size = footerView.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
            if (footerView.Frame.Size.Height != size.Height) {
                var frame = footerView.Frame;
                frame.Height = size.Height;
                footerView.Frame = frame;
                tableView.TableFooterView = footerView;
                tableView.LayoutIfNeeded();
            }
        }
    }
}

UITableViewController 하위 클래스의 ViewDidLayoutSubviews에서 호출합니다.

public override void ViewDidLayoutSubviews()
{
    base.ViewDidLayoutSubviews();

    TableView.MakeHeaderAutoDimension();
    TableView.MakeFooterAutoDimension();
}

0

너비 375pt를 얻는 문제가 발생했습니다. 나를 위해 일한 유일한 방법은 올바른 너비를 얻기 위해 tableView를 릴레이하는 것입니다. 또한 프레임 크기 설정보다 AutoLayout을 선호했습니다.

저에게 적합한 버전은 다음과 같습니다.

Xamarin.iOS

public static void AutoLayoutTableHeaderView(this UITableView tableView, UIView header)
{
    tableView.TableHeaderView = header;
    tableView.SetNeedsLayout();
    tableView.LayoutIfNeeded();
    header.WidthAnchor.ConstraintEqualTo(tableView.Bounds.Width).Active = true;       
    tableView.TableHeaderView = header;
}

Swift 버전 (@Ben Packard 답변에서 수정 됨)

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
        self.setNeedsLayout()
        self.layoutIfNeeded()
        header.widthAnchor.widthAnchor.constraint(equalTo: self.bounds.width).isActive = true
        self.tableHeaderView = header
    }
}


0

내 솔루션은 이와 같은 새로운 클래스를 만드는 것입니다.

class BaseTableHeaderView: UIView {

    func sizeToFitBasedOnConstraints(width: CGFloat = Screen.width) {
        let size = systemLayoutSizeFitting(CGSize(width: width, height: 10000),
                                              withHorizontalFittingPriority: .required,
                                              verticalFittingPriority: .fittingSizeLevel)
        frame = CGRect(origin: .zero, size: size)
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        sizeToFitBasedOnConstraints()
        super.willMove(toSuperview: newSuperview)
    }

}

이를 사용하려면 모든 하위 뷰를의 인스턴스에 BaseTableHeaderView추가하고 테이블 뷰에 연결하면됩니다.

let tableHeaderView = BaseTableHeaderView()
tableHeaderView.addSubview(...)
tableView.tableHeaderView = tableHeaderView

제약 조건에 따라 자동으로 크기가 조정됩니다.


-1

허용되는 답변은 단일 섹션이있는 테이블에만 유용합니다. 다중 섹션 UITableView의 경우 헤더가 상속되는지 확인하십시오 UITableViewHeaderFooterView.

대안으로, 단지에 현재 헤더를 포함 contentViewUITableViewHeaderFooterView. UITableViewCell작품 과 똑같습니다.


9
질문은 tableHeaderView섹션 헤더 가 아닙니다.
Rpranata 2014 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.