programing

UITableView 테이블에서 AutoLayout을 사용할 수 있습니까?머리글 보기?

testmans 2023. 6. 4. 10:21
반응형

UITableView 테이블에서 AutoLayout을 사용할 수 있습니까?머리글 보기?

가 발이후로한견을 발견한 이후로.AutoLayout어디서나 사용하는데, 이제는 사용하려고 합니다.tableHeaderView.

는 내가만을 .subclassUIView 것 등. 그들의 제약 조건과 함께, 저는 이것을 추가했습니다.CustomView에▁UITableView'tableHeaderView.

모든 것이 정상적으로 작동합니다.UITableView항상 위에 표시됩니다.CustomView에서 말하는 것은CustomView아래에 있습니다.UITableView그래서 그것은 보이지 않습니다!

내가 뭘 해도, 그 사람은height의 시대의UITableView'tableHeaderView항상 0입니다(폭, x 및 y도 마찬가지).

제 질문: 프레임을 수동으로 설정하지 않고 이것을 수행하는 것이 가능합니까?

편집 : TheCustomView'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그 안에 "부드러운".

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

다중 라인 레이블이 있는 경우에는 각 레이블의 기본 MaxLayoutWidth를 설정하는 사용자 정의 뷰에도 의존합니다.

- (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
        self.tableHeaderView?.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            header.widthAnchor.constraint(equalTo: self.widthAnchor)
        ])
        header.setNeedsLayout()
        header.layoutIfNeeded()
        header.frame.size =  header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
        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."

스토리보드의 보기를 내 테이블 보기에 추가하면 제약 조건이 나타나지 않고 머리글 보기로도 잘 작동하기 때문에 머리글 보기의 배치가 제약 조건을 사용하여 수행되지 않는다고 생각합니다.그런 점에서 정상적인 시각처럼 행동하지 않는 것 같습니다.

너비는 자동으로 테이블 뷰의 너비가 됩니다. 설정해야 할 것은 높이입니다. 원점 값은 무시되기 때문에 입력한 값은 중요하지 않습니다.예를 들어, 이것은 잘 작동했습니다(직류의 경우 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];
}

systemLayoutSizeFittingSize 메서드를 사용하여 자동 레이아웃을 사용하여 크기를 제공할 수 있습니다.

그런 다음 이를 사용하여 응용프로그램의 프레임을 만들 수 있습니다.이 기술은 내부적으로 자동 레이아웃을 사용하는 보기의 크기를 알아야 할 때마다 작동합니다.

swift의 코드는 다음과 같습니다.

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

또는 목표-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

또한 이 특정 인스턴스에서 재정의가 하위 클래스에서 ConstraintBasedLayout을 필요로 하면 레이아웃 패스가 수행되지만 이 레이아웃 패스의 결과는 무시되고 시스템 프레임이 테이블 View의 너비와 0 높이로 설정됩니다.

코드:

  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

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

다음은 저에게 효과가 있었습니다.

  1. old 오래것사용된일을 합니다.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))
}

이상한 일들이 일어납니다.systemLayoutSizeFittingSize는 iOS9에서는 잘 작동하지만, 제 경우 iOS8에서는 잘 작동하지 않습니다.그래서 이 문제는 꽤 쉽게 해결됩니다.높이를 CGRectGetMaxY(yourview.frame)+패딩으로 삽입하여 슈퍼콜 업데이트 헤더 뷰 경계 후 헤더 및 뷰의 하단 뷰에 대한 링크만 가져옵니다.

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를 호출합니다.뷰의 실제 크기를 알고 있으므로 헤더뷰 높이를 설정하고 다시 할당하여 업데이트합니다.매력적으로 작동합니다!

바닥글 보기에도 사용할 수 있습니다.

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

테이블에서ViewControllerviewDidLoad 메서드

    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

대부분의 경우 가장 좋은 해결책은 프레임워크를 사용하지 않고 마스크 크기를 자동으로 조정하지 않는 것입니다.

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

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

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

자동 레이아웃이 매우 잘 작동합니다.

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;

저의 해결책은 이렇게 새로운 수업을 만드는 것입니다.

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

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

저는 이것이 오래된 게시물이라는 것을 알지만, 이것과 관련된 모든 SO 게시물을 검토하고 오후 내내 이것을 가지고 놀다가 마침내 깨끗하고 매우 간단한 해결책을 생각해냈습니다.

먼저, 내 보기 계층은 다음과 같습니다.

  1. 테이블 보기
    1. tableHeaderView
      1. header라는 아울렛으로 보기보기

이제 View(3번) 안에서 컨테이너에 대한 하단 공간을 포함하는 것처럼 모든 제약 조건을 설정했습니다.이렇게 하면 용기가 만들어집니다(예: 3).View(예: 머리글 보기)를 사용하여 하위 뷰와 해당 제약 조건에 따라 크기를 조정할 수 있습니다.

그 후에, 저는 다음과 같은 제약 조건을 설정합니다.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를 사용하는 경우 하위 뷰의 프레임을 업데이트해야 하므로 이 상황에서는 시스템LayoutSizeFittingSize가 호출되기 전에 UILabel의 기본 MaxLayoutWidth가 호출되어야 합니다. 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));
    }];
  }];

오래된 게시물.하지만 좋은 게시물.여기 제 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% 확인해야 합니다.저는 한 가지 높이 제한이 있는 간단한 헤더 뷰로 시작하여 위의 설정을 사용해 보는 것을 추천합니다.

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

표 보기의 머리글 보기 이름을 표 보기로 지정했다고 가정합니다.머리글

다음은 당신이 할 수 있는 방법입니다.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.

명은 ▁to▁one를 .tableFooterView 후 제 행 조 적 하 기 용 전 에 을 건 가 약 ▁const ▁on ▁addition ▁and ▁trailing ▁before ▁then 전 ▁impose 에 추 기하 가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;

}

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

해결 방법을 알아냈습니다. 자동 레이아웃 쓰기 xib 헤더 뷰를 빈 uiview 래퍼로 래핑하고 헤더 뷰를 테이블에 할당합니다.view's table머리글 속성.

    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를 표 보기로 끌어다 놓습니다.필요에 따라 머리글과 바닥글을 설정합니다.필요한 모든 제약 조건을 설정합니다.

이제 다음 확장 방법을 사용합니다.

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

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

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

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

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

저에게 맞는 버전은 다음과 같습니다.

사마린.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;
}

빠른 버전(@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및 사용된UIStackView머리글과 바닥글 모두에서 둘 이상의 보기를 설정할 수 있습니다.

https://github.com/omaralbeik/StackableTableView

이전에는 작동했지만 더 이상 작동하지 않는 다른 솔루션을 확인한 iOS 12, iOS 13, iOS 14, iOS 15에서 모든 경우에 장치 회전에서도 잘 작동하는 다중 라인 레이블을 사용하여 헤더 뷰를 위한 다음 솔루션을 만들었습니다.뷰를 테이블 머리글 뷰로 직접 설정하는 대신 실제 뷰에서 높이가 변경될 경우 높이를 자동으로 업데이트하는 래퍼 뷰를 사용합니다.프로젝트에 다음 클래스를 추가합니다.

class TableViewHeaderHelperView: UIView {
  private weak var headerView: UIView?
  private weak var tableView: UITableView?
  private var lastUpdatedHeight: CGFloat = 0

  init(headerView: UIView) {
    self.headerView = headerView
    super.init(frame: .zero)
    translatesAutoresizingMaskIntoConstraints = true
    addSubview(headerView)
  }

  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  func addToTableView(_ tableView: UITableView) {
    self.tableView = tableView
    tableView.tableHeaderView = self
    headerView?.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true
  }

  func removeFromTableView() {
    self.tableView?.tableHeaderView = nil
    self.tableView = nil
  }

  override func layoutSubviews() {
    super.layoutSubviews()
    refreshHeaderHeightIfNeeded()
  }

  func refreshHeaderHeightIfNeeded() {
    DispatchQueue.main.async {
      let headerViewSize = self.headerView?.bounds.size ?? .zero
      if headerViewSize.height != self.lastUpdatedHeight {
        self.lastUpdatedHeight = headerViewSize.height
        self.frame.size = headerViewSize
        self.tableView?.tableHeaderView = self
      }
    }
  }
}

그런 다음 이 도우미 클래스를 다음과 같이 사용할 수 있습니다.

let headerWrapperView = TableViewHeaderHelperView(headerView: yourRealHeaderView)
headerWrapperView.addToTableView(tableView)

또는 라이브러리 LSCategories에서 UITableView 클래스에 대한 확장을 포함한 다양한 확장 기능을 제공하는 유사한 접근 방식을 사용했습니다. UITableView 클래스는 테이블 헤더 뷰 또는 코드 한 줄로 바닥글 뷰에 자동 레이아웃 뷰를 설정할 수 있으므로 대신 사용할 수도 있습니다.

승인된 답변은 섹션이 하나인 테이블에만 유용합니다.다중 단면의 경우UITableView헤더가 에서 상속되는지 확인하기만 하면 됩니다.

또는 현재 헤더를 다음에 삽입합니다.contentView상당한UITableViewHeaderFooterView꼭 닮음UITableViewCell작동하다.

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

반응형