programing

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

nasanasas 2020. 9. 9. 08:08
반응형

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


내가 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의 상단과 동일한 수준이며 스크롤 할 때 함께 이동합니다.


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

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

이상한 일이 일어납니다. 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 높이를 설정하고 다시 할당하여 업데이트합니다. 매력처럼 작동합니다!

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


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


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

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

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

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

내 테이블 헤더 뷰는 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
}

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

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

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

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

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

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

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

코드 쇼


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

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

내 경우에는 어떤 이유로 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;
}

오래된 게시물. 그러나 좋은 게시물입니다. 여기 내 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)
}

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

먼저 작은 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
   }
   // ...
}

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로 명명했다고 가정합니다.


여기에서 할 수있는 방법은 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)
    }
  }

제약 기반 모든 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;

}

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


해결 방법을 찾았습니다. 자동 레이아웃 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;

다음은 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();
}

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

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

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

참고 URL : https://stackoverflow.com/questions/16471846/is-it-possible-to-use-autolayout-with-uitableviews-tableheaderview

반응형