AutoLayoutをUITableViewのtableHeaderViewで使用することは可能ですか?


97

AutoLayout私はどこでもそれを使用していることを発見したので、今はで使用しようとしていますtableHeaderView

subclassUIView追加されたすべて(ラベルなど...)を作成しましたが、それらの制約を使用して、それを' に追加しCustomViewました。UITableViewtableHeaderView

すべてがうまく以外の作品UITableViewは常にディスプレイ上のCustomViewことで、上記の私は意味CustomViewあるの下でUITableViewそれを見ることができないように!

それは私が何をすべきかに関係なく、ということらしいheightUITableView" tableHeaderViewある常に(その幅、xとyがある)0。

私の質問:フレームを手動で設定せずにこれを達成することはまったく可能ですか?

編集:CustomViewsubview私が使用していることは、これらの制約があります。

_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」を使用しています。これは、手動で制約を作成すると時間がかかり、1つの制約に対して行が多すぎるためですが、メソッドは自明です。

そして、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の上部と同じレベルにあり、スクロールすると一緒に移動します。


はい、可能です。使用しているコードを表示できますか?ヘッダービューに設定した制約を知らずにアドバイスするのは困難です。
jrturton 2013年

これを行う簡単な方法は、IBのそのビューをtableView に追加することです。テーブルビューを含む同じシーンでビューを作成し、それをテーブルにドラッグするだけです。
マリアムK. 2013

私はそれが私がIBでみます仕事を得ることができない場合にはこれまでのところ、私は、それを使用する必要はありませんでした、IBに私ができる最もを避けるためにしようとしている
ItsASecret

1
Appleは、自動レイアウトに関しては、可能な限りIBを使用することを開発者に推奨しています。これは、多くの不整合の問題を回避するのに役立ちます。
Mariam K. 2013

真の完全な自動レイアウトソリューションがここに
malex 2016

回答:


134

ここで同様の質問をし、それに答えました。要約すると、ヘッダーを1回追加し、それを使用して必要な高さを見つけます。その後、その高さをヘッダーに適用できます。ヘッダーは、変更を反映するためにもう一度設定されます。

- (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:ます。
ベンジョン2015

2
注:ヘッダーが最初のセルの上にあると感じた場合は、ヘッダープロパティをself.tableView.tableHeaderView
Laszlo

7
このような完全に些細なことをするのがどれほどトリッキーであるかは、しばしば私を驚かせます。
TylerJames、2015

5
注:tableViewとして正確な幅を取得する必要がある場合は、必要な水平優先度で高さを取得する必要がありますlet height = header.systemLayoutSizeFittingSize(CGSizeMake(CGRectGetWidth(self.bounds), 0), withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityFittingSizeLevel).height
JakubKnejzlik

3
Just Use header.setNeedsLayout() header.layoutIfNeeded() header.frame.size = header.systemLayoutSizeFitting(UILayoutFittingCompressedSize) self.tableHeaderView = headerはiOS 10.2で動作します
Kesong Xie

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 2013年

私はそれを試してみましたが、ええフレームワークを設定するが、私はフレームを設定しないようにする方法を探していた、私は見ておこうと、私は他に何もを見つけていない場合、私はあなたの答えを受け入れるだろうしました
ItsASecret

1
追加されたヘッダービューにがある場合、この例外が発生します(現在7.1をテストしています)translatesAutoresizingMaskIntoConstraints = NO。翻訳をオンにすることでエラーを防ぐことができますUITableView。7.1の時点では、ヘッダービューの自動レイアウトを試みておらず、事前設定されたフレームで何かを望んでいると思います。
ベンジョン2015

16

ここでは多くのメソッドが不必要な処理を実行しているのを見ましたが、ヘッダービューで自動レイアウトを使用するのにそれほど多くは必要ありません。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、2017年

1
もちろん、IBのflexibleHeight-Autoresizing-Optionを削除することもできます。
d4Rk 2017年

私は(xib / nibを介して)tableFooterViewの高さを設定しようとしましたが、フレーム、高さ、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は、autolayoutでバギーのようなものです。このようないくつかの回避策があります。私はこれを書いているのでしかし、私はここで、より良いとクリーンな解決策を見つけた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サブビューに適切な自動レイアウト制約を与えます。1つの制約を見逃すと、機能しません。
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が自動的にサイズ変更/レイアウトを正しく行うようにしようと1日過ごしました。この解決策は私にとってはうまくいきます。本当にありがとう。
docchang

こんにちは!self.tableFooterView.transform一部説明していただけますか?なぜそれが必要なのですか?
mrvn 2018年

@mrvn変換を使用して、フッターをtableViewの下部に移動します。
k06a

3

autoLayoutを取得してサイズを提供するには、systemLayoutSizeFittingSizeメソッドを使用します。

これを使用して、アプリケーションのフレームを作成できます。この手法は、内部でautolayoutを使用するビューのサイズを知る必要がある場合に機能します。

迅速なコードは次のようになります

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

この特定のインスタンスでは、サブクラスでrequireConstraintBasedLayoutをオーバーライドすると、レイアウトパスが実行されますが、このレイアウトパスの結果は無視され、システムフレームはtableViewの幅と高さ0に設定されます。


3

以下は私のために働いた。

  1. UIViewヘッダービューとしてプレーンオールドを使用します。
  2. サブビューを追加します UIView
  3. サブビューで自動レイアウトを使用する

私が目にする主な利点は、フレーム計算を制限することです。UITableViewこれを簡単にするために、Apple はの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
このiOSの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

私はこれが古い投稿であることを知っていますが、これに関するすべてのSO投稿を確認し、午後にこれで遊んだ後、ようやくきれいで非常にシンプルな解決策を思いつきました

まず、私のビュー階層は次のようになります。

  1. テーブルビュー
    1. 見る tableHeaderView
      1. headerViewというアウトレットがあるビュー

次にビュー(No.3)の内部で、コンテナーへの下部スペースを通常含めるようにすべての制約を設定します。これにより、コンテナ(つまり、3.View、つまりheaderView)は、そのサブビューとその制約に基づいてサイズが変更されます。

その後、私は間の制約を設定3. Viewし、2. Viewこれらに:

  1. コンテナまでの上部スペース:0
  2. コンテナまでのリーディングスペース:0
  3. コンテナへの後続スペース:0

下のスペースを意図的に省略していることに注意してください。

これらすべてがストーリーボードで完了したら、あとは、次の3行のコードを貼り付けるだけです。

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で私のケースでは機能しませんでした)。ヘッダービューでサブビューを配置し、左、右、上に固定します(下に固定しないでください)。autolayoutを使用してすべてをそのサブビューに配置し、コードで次のようにします。

- (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%確認する必要があります。高さ制約が1つだけの単純なヘッダービューから始めて、上記の設定を試すことをお勧めします。

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

テーブルビューのヘッダービューに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です。

tableFooterViewbefore を設定してから、andに追加の制約を課す必要が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

回避策を見つけました。autolayout 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.