web-dev-qa-db-ja.com

自動レイアウト、IB、およびフォントサイズを使用すると、テーブルヘッダービューの高さが間違っている

UiTableViewのヘッダービューを作成しようとしています(セクションヘッダーではなく、既にあります)。インターフェイスビルダーでXIBを設定しました。すべての接続が接続され、美しく動作します...テーブルが十分なスペースを与えていないことを除いて!私の問題は、テーブルの上部がテーブルのヘッダーと少し重なっていることです。

私のXIBは、すべてのボタンに対してautlayoutを使用してセットアップされており、IBは制約が競合/あいまいにならないことに満足しています。ビューはフリーフォームサイズに設定されますが、私の場合は320 x 471になります。その後、ビューの制約で、同じビューの固有のサイズを設定します。

今、これは私のテーブルで完璧に動作します。すべてが素晴らしく見えます。しかし、ヘッダービューのフォントをコードで手動で変更すると、レイアウトによってビューが大きくなり、テーブルの下に表示されます。

フォントとサイズを設定した後に、tableviewcontrollerにヘッダービューのための十分なスペースを確保する方法はありますか?これを説明するのが理にかなったことを願っています。

34
jedipixel

注:A Swift 3+バージョンはここにあります: https://Gist.github.com/marcoarment/1105553afba6b4900c10#gistcomment-1933639


アイデアは、systemLayoutSizeFittingSize:targetSizeを使用してヘッダーの高さを計算することです。

保持している制約を満たすビューのサイズを返します。保持するすべての制約とそのサブビューの制約を考慮して、ビューの最適なサイズを決定します。

ヘッダーの高さを変更した後、tableHeaderViewプロパティを再割り当てしてテーブルセルを調整する必要があります。

この答えに基づいて: 動的なセルレイアウトと可変行の高さのためのUITableViewでの自動レイアウトの使用

- (void)sizeHeaderToFit
{
    UIView *header = self.tableView.tableHeaderView;

    [header setNeedsLayout];
    [header layoutIfNeeded];

    CGFloat height = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
    CGRect frame = header.frame;

    frame.size.height = height;
    header.frame = frame;

    self.tableView.tableHeaderView = header;
}
65
vokilam

インターフェイスビルダーを使用して自動レイアウトで定義したカスタムビューにテーブルビューヘッダーを設定しようとしたときに、同様の問題が発生しました。

そうすると、セクションヘッダーによって隠されていることがわかります。

私の回避策は、「ダミービュー」をテーブルヘッダービューとして使用し、カスタムビューをサブビューとしてそのダミービューに追加することでした。これにより、自動レイアウトで、制約および包含ビューのフレームに従って外観を構成できると思います。これはおそらくvokilamのソリューションほどエレガントではありませんが、私には有効です。


CGRect headerFrame = CGRectMake(0, 0, yourWidth, yourHeight);
UIView *tempView = [[UIView alloc] initWithFrame:headerFrame];
[tempView setBackgroundColor:[UIColor clearColor]];
YourCustomView *customView = [[YourCustomView alloc] initWithFrame: headerFrame];
[tempView addSubview:movieHeader];
self.tableView.tableHeaderView = tempView;
14
rmigneco

tableHeaderViewは自動レイアウトでxibから初期化されているため、カスタムheaderViewsuperViewの制約は不明です。constraintsを追加する必要がありますカスタムheaderView

1.in viewDidLLoadは、カスタムheaderViewをtableViewのtableHeaderViewに割り当てます

 - (void)viewDidLoad
{
    [super viewDidLoad];
    UIView *yourHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"yourHeaderView" owner:nil options:nil] objectAtIndex:0];
    //important:turn off the translatesAutoresizingMaskIntoConstraints;Apple documents for details
     yourHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
    self.tableView.tableHeaderView = yourHeaderView;
}

2.in void)updateViewConstraints、カスタムheaderViewの本質的な制約を追加

- (void)updateViewConstraints
{
    NSDictionary *viewsDictionary = @{@"headerView":yourHeaderView};

    NSArray *constraint_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];

    NSArray *constraint_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(320)]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];
    [self.headerView addConstraints:constraint_H];
    [self.headerView addConstraints:constraint_V];

    NSArray *constraint_POS_V = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];

    NSArray *constraint_POS_H = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
                                                                    options:0
                                                                    metrics:nil
                                                                      views:viewsDictionary];
    [self.tableView addConstraints:constraint_POS_V];
    [self.tableView addConstraints:constraint_POS_H];

    [super updateViewConstraints];
}

OK! PS:関連ドキュメントは次のとおりです。---(View Controllerのビューのサイズ変更

9
mayqiyue

私の問題を解決したのはこれでした:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    sizeHeaderToFit()
}

private func sizeHeaderToFit() { 
    if let headerView = tableView.tableHeaderView {

        headerView.setNeedsLayout()
        headerView.layoutIfNeeded()

        let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        var newFrame = headerView.frame

        // Needed or we will stay in viewDidLayoutSubviews() forever
        if height != newFrame.size.height {
            newFrame.size.height = height
            headerView.frame = newFrame

            tableView.tableHeaderView = headerView
        }
    }
}

私はこの解決策をどこかで見つけて、魅力のように働いたが、どこにいるのか思い出せない。

7
ClockWise

私はvokilamの答えが素晴らしいと感じました。 Swiftでの彼のソリューションは次のとおりです。

func sizeHeaderToFit() {
    guard let header = tableView.tableHeaderView else { return }
    header.setNeedsLayout()
    header.layoutIfNeeded()
    let height = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    header.frame.size.height = height
    tableView.tableHeaderView = header
}
3
Mr Rogers

他の答えは、tableHeaderViewを適切にサイズ変更するための正しい方向を示しました。ただし、ヘッダーとtableViewセルの間にギャップが生じていました。これにより、ヘッダーが拡大したか縮小したかによって、セルがヘッダーと重複する可能性もあります。

私はこれから行きました:

 tableView.reloadData()
 let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
 tableView.tableHeaderView?.frame.size.height = height

ギャップ/オーバーラップを修正するには、tableView.reloadData()を前にではなく新しい高さを設定した後に移動するだけでした。

これに:

 let height = tableViewHeader.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
 tableView.tableHeaderView?.frame.size.height = height
 tableView.reloadData()
1
templeman15

@ SwiftArchitect、@ vokilam、および@mayqiyueによる回答を組み合わせ、ペン先の代わりにプログラムで作成されたtableHeaderViewを使用します(ただし、ペン先で動作しない理由はわかりません)。 iOS 10.x/Xcode 8.2.1で、ここに私が働いているものがあります:

View Controllerの-viewDidLoadまたは-initメソッド、またはTable Viewを使用している場所でビューを作成します。

MyCustomTableHeaderView *myCustomTableHeaderView = [[MyCustomTableHeaderView alloc] init]; // Don't set its frame
myCustomTableHeaderView.translatesAutoresizingMaskIntoConstraints = NO;
self.myTableView.tableHeaderView = myCustomTableHeaderView;
self.myCustomTableHeaderView = myCustomTableHeaderView;  // We set and update our constraints in separate methods so we store the table header view in a UIView property to access it later

カスタムヘッダービューの制約を設定した場所( `updateConstraintsにある可能性がありますが、このメソッドは複数回呼び出すことができます):

// We use Pure Layout in our project, but the workflow is the same:
// Set width and height constraints on your custom view then pin it to the top and left of the table view
// Could also use VFL or NSLayoutConstraint methods
[self.myCustomTableHeaderView autoSetDimension:ALDimensionWidth toSize:CGRectGetWidth(self.superview.frame)]; // Width set to tableview's width
[self.myCustomTableHeaderView autoSetDimension:ALDimensionHeight toSize:height]; // Whatever you want your height to be
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeTop];
[self.myCustomTableHeaderView autoPinEdgeToSuperviewEdge:ALEdgeLeft];

// This is important
[self.myCustomTableHeaderView layoutIfNeeded]; // We didn't need to call -setNeedsLayout or reassign our custom header view to the table view's tableHeaderView property again, as was noted in other answers
1
Evan R

私の場合、サブビューの1つがアスペクト比(幅と高さ)4:1制約を使用しているため、systemLayoutSizeFittingSizeは誤ったサイズを返します。

一定の高さの制約値(100)に変更すると、期待どおりに機能し始めます。

1

@vokilamによって提案されたsizeHeaderToFitは私にとってはうまくいきませんでした。

動作したのは、viewDidLoadの間に呼び出される@mayqiyueの修正バージョンで、配線された高さ、テーブルビューと同じ幅です。

// Anchor the headerview, and set width equal to superview
NSDictionary *viewsDictionary = @{@"headerView":self.tableView.tableHeaderView,
                                  @"tableView":self.tableView};

[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[headerView]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[headerView]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[headerView(==tableView)]"
                                                                       options:0
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
[self.tableView.tableHeaderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[headerView(121)]"
                                                                                       options:0
                                                                                       metrics:nil
                                                                                         views:viewsDictionary]];
0
SwiftArchitect

@rmignecoの答えは私のために働いたので、ここにSwiftのバージョンがあります:

let headerFrame = CGRectMake(0, 0, 100, 1);
let tempView = UIView(frame: headerFrame);
tempView.backgroundColor = UIColor.clearColor()

let yourCustomView = CustomView(frame: headerFrame)
tempView.addSubview(yourCustomView)

self.tableView.tableHeaderView = tempView
0
gmogames

以下のコードは私のために働いています:-これをUIViewクラスに追加してください-

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];

if (self) {
    self.frame = CGRectMake(0, 0, self.frame.size.width, [[self class] height]);
}

return self;

}

0
iosDeveloper