UITableViewのtableHeaderViewのサイズを変更する方法は?


103

tableHeaderViewのサイズを変更できません。それは単純に機能しません。

1)UITableViewおよびUIView(100 x 320 px)を作成します。

2)UIViewをUITableViewのtableHeaderViewとして設定します。

3)ビルドアンドゴー。全て大丈夫。

ここで、tableHeaderViewのサイズを変更したいので、viewDidLoadに次のコードを追加します。

self.tableView.autoresizesSubviews = YES;

self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;

tableHeaderViewの高さは200で表示されますが、100で表示されます。

私が書いた場合:

self.tableView.autoresizesSubviews = YES;


CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;


self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

それから、私が望むように、それは高さの200から始まります。しかし、実行時に変更できるようにしたいと思います。

私もこれを試しましたが、成功しませんでした:

self.tableView.autoresizesSubviews = YES;

self.tableView.tableHeaderView = myHeaderView;
self.tableView.tableFooterView = myFooterView;

CGRect newFrame = self.tableView.tableHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
self.tableView.tableHeaderView.frame = newFrame;

[self.tableView.tableHeaderView setNeedsLayout];
[self.tableView.tableHeaderView setNeedsDisplay];
[self.tableView setNeedsLayout];
[self.tableView setNeedsDisplay];

ここでのポイントは、実行時にtableHeaderViewのサイズをどのように変更するかです。

誰かがこれを行うことができますか?

ありがとう

iMe

回答:


180

参考:tableHeaderViewを変更して再設定することで、これを機能させることができます。この場合、UIWebViewサブビューの読み込みが完了したときに、tableHeaderViewのサイズを調整しています。

[webView sizeToFit];
CGRect newFrame = headerView.frame;
newFrame.size.height = newFrame.size.height + webView.frame.size.height;
headerView.frame = newFrame;
[self.tableView setTableHeaderView:headerView];

13
+1これでうまくいきました。サブビューのサイズが変更された後に「setTableHeaderView」を呼び出すことが重要です。問題は、サブビューのサイズがアニメーションとして1秒間で変化することです。今私はそれでtableHeaderViewをアニメーション化する方法を理解しようとしています。
Andrew

1
パーフェクト、たくさんありがとう。私にとって、これはObjective-Cのプロパティのあまり望ましくない性質の1つの例です。ヘッダーを設定すると高さが再計算されるという副作用があることを知る方法はありません(知る必要もありません)。ヘッダーの高さを更新するときに自動的に行うか、[tableView recalculateHeaderHeight]毎回のように呼び出す必要があります。
jakeboxer 2010

48
@Andrew私はこれがほぼ1年遅すぎることを知っていますが、それより遅くなることはありません:andでsetTableHeaderView:呼び出しをラップすることにより、テーブルヘッダービューの高さの変化をアニメーション化できました[tableview beginUpdates][tableview endUpdates]
jasongregori

2
追加した@jasongregori便利なコメント-同じ手法(beginUpdates + endUpdates)では、tableFooterViewの高さの変化がtableHeaderViewのようにアニメーション化されないようです。tableFooterViewをアニメーション化する良い方法も考えましたか?
kris

1
印象的な、このイベントはUIViewアニメーションブロック内で実行すると機能しますが、その場合は非常に効率的ではないと思います。

12

この回答は古く、明らかにiOS 7以降では機能しません。

私は同じ問題に遭遇し、変更をアニメーション化したかったので、ヘッダービューにUIViewのサブクラスを作成し、次のメソッドを追加しました。

- (void)adjustTableHeaderHeight:(NSUInteger)newHeight{
    NSUInteger oldHeight = self.frame.size.height;
    NSInteger originChange = oldHeight - newHeight;

    [UIView beginAnimations:nil context:nil];

    [UIView setAnimationDuration:1.0f];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    self.frame = CGRectMake(self.frame.origin.x, 
                        self.frame.origin.y, 
                        self.frame.size.width, 
                        newHeight);

    for (UIView *view in [(UITableView *)self.superview subviews]) {
        if ([view isKindOfClass:[self class]]) {
            continue;
        }
        view.frame = CGRectMake(view.frame.origin.x, 
                            view.frame.origin.y - originChange, 
                            view.frame.size.width, 
                            view.frame.size.height);
    }

    [UIView commitAnimations];
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
    [(UITableView *)self.superview setTableHeaderView:self];
}

これは基本的に、呼び出しクラスと同じクラスタイプではないUITableViewのすべてのサブビューをアニメーション化します。アニメーションの最後に、スーパービュー(UITableView)でsetTableHeaderViewを呼び出します。これがないと、UITableViewのコンテンツは、ユーザーが次にスクロールしたときにジャンプして戻ります。これまで私が見つけた唯一の制限は、アニメーションの実行中にユーザーがUITableViewをスクロールしようとすると、ヘッダービューのサイズが変更されていないかのようにスクロールがアニメーション化されることです(アニメーションがクイック)。


私はそれを必要としなかったので、完全に動作し、アニメーションを削除しました。
Jiho Kang

iOS7が発生するまで完璧に動作しました...以下に私の解決策を追加しました
Avishic

1
WTF?UITableViewの内部をいじくり回しているので、新しいiOSバージョンでは機能しないことには驚くに値しません...;)
Daniel Rinser

10

条件付きで変更をアニメーション化する場合は、次の操作を実行できます。

- (void) showHeader:(BOOL)show animated:(BOOL)animated{

    CGRect closedFrame = CGRectMake(0, 0, self.view.frame.size.width, 0);
    CGRect newFrame = show?self.initialFrame:closedFrame;

    if(animated){
        // The UIView animation block handles the animation of our header view
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.3];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        // beginUpdates and endUpdates trigger the animation of our cells
        [self.tableView beginUpdates];
    }

    self.headerView.frame = newFrame;
    [self.tableView setTableHeaderView:self.headerView];

    if(animated){
        [self.tableView endUpdates];
        [UIView commitAnimations];
    }
}

アニメーションは2つに分かれていることに注意してください。

  1. の下のセルのアニメーションtableHeaderView。これはbeginUpdatesendUpdates
  2. 実際のヘッダービューのアニメーション。これはUIViewアニメーションブロックを使用して行われます。

これらの2つのアニメーションを同期するにanimationCurveは、をに設定しUIViewAnimationCurveEaseInOut、期間をに設定する0.3必要があります。これは、UITableViewがアニメーションに使用しているようです。

更新

私はこれを行うgihubでXcodeプロジェクトを作成しました。besi / ios-quickiesでプロジェクトResizeTableHeaderViewAnimatedをチェックしてください

スクリーンショット


2
この手法は機能しますが、セクションヘッダーのあるテーブルビューでは機能しません。更新の開始/更新の終了を使用すると、アニメーションブロックに干渉し、重複したセクションヘッダーが残ります。
BlueFish 2013

9

myHeaderViewの高さを次のように設定するだけでうまくいくと思います。

CGRect newFrame = myHeaderView.frame;
newFrame.size.height = newFrame.size.height + 100;
myHeaderView.frame = newFrame;

self.tableView.tableHeaderView = myHeaderView;

これは実際に機能しますが、viewDidLayoutSubviewsで使用する場合に限ります
KoCMoHaBTa

6

上記の@garrettmoonソリューションをiOS 7まで使用しました。
ここに、@ garrettmoonに基づく更新されたソリューションがあります。

- (void)adjustTableHeaderHeight:(NSUInteger)newHeight animated:(BOOL)animated {

    [UIView beginAnimations:nil context:nil];

    [UIView setAnimationDuration:[CATransaction animationDuration]];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

    self.frame = CGRectMake(self.frame.origin.x,
                        self.frame.origin.y,
                        self.frame.size.width,
                        newHeight);

    [(UITableView *)self.superview setTableHeaderView:self];

    [UIView commitAnimations];
}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{
    [(UITableView *)self.superview setTableHeaderView:self];
}

5

これはiOS 7および8で動作しました。このコードはテーブルビューコントローラーで実行されています。

[UIView animateWithDuration:0.3 animations:^{
    CGRect oldFrame = self.headerView.frame;
    self.headerView.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.size.width, newHeight);
    [self.tableView setTableHeaderView:self.headerView];
}];

4

これは、tableHeaderViewのセッターのためです。

tableHeaderViewを設定する前に、UIViewの高さを設定する必要があります。(アップルがこのフレームワークをオープンソース化すれば、はるかに簡単になるでしょう...)


4

iOS 9以下でtableHeaderViewは、サイズ変更後の再レイアウトは行われません。この問題はiOS 10で解決されています。

この問題を解決するには、次のコードを使用します。

self.tableView.tableHeaderView = self.tableView.tableHeaderView;

2

iOS 9.xでは、これをviewDidLoadうまく実行できます。

var frame = headerView.frame
frame.size.height = 11  // New size
headerView.frame = frame

headerView@IBOutlet var headerView: UIView!tableHeaderViewとして機能するように、tableViewの上部に配置されるストーリーボードとして宣言され、接続されます。


2

これは、自動レイアウトを使用translatesAutoresizingMaskIntoConstraints = falseしてカスタムヘッダービューに設定した場合にのみ使用できます。

最善かつ最も簡単な方法は、オーバーライドすることintrinsicContentSizeです。内部的にUITableView使用intrinsicContentSizeして、ヘッダー/フッターのサイズを決定します。intrinsicContentSizeカスタムビューでオーバーライドしたら、次のようにする必要があります

  1. カスタムヘッダー/フッタービューのレイアウト(サブビュー)を構成する
  2. 呼び出す invalidateIntrinsicContentSize()
  3. 呼び出しtableView.setNeedsLayout()tableView.layoutIfNeeded()

次に、UITableViewのヘッダー/フッターが必要に応じて更新されます。ビューをnilに設定したりリセットしたりする必要はありません。

UITableView.tableHeaderViewまたはにとって本当に興味深いことの1つ.tableFooterViewは、UIStackViewを管理する能力を失うことarrangedSubviewsです。あなたが使用したい場合はUIStackViewtableHeaderViewまたはtableFooterViewとして、あなたがに埋め込むstackViewに持っているUIViewとオーバーライドUIView「S intrinsicContentSize


2

Swift 5のテスト済みコード

override func viewDidLayoutSubviews() {
      super.viewDidLayoutSubviews()

        guard let headerView = self.tblProfile.tableHeaderView else {
            return
        }

        let size = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)

        if headerView.frame.size.height != size.height {
            headerView.frame.size.height = size.height
            self.tblProfile.tableHeaderView = headerView
            self.tblProfile.layoutIfNeeded()
        }
    }

注:すべてのサブビューの制約に、上、下、先頭、末尾の形式を与える必要があります。したがって、必要なサイズ全体が取得されます。

参照元: https : //useyourloaf.com/blog/variable-height-table-view-header/


1

設定の高さをヘッダビューのプロパティのtableView.tableHeaderView中には、viewDidLoad予想通りではない仕事、ヘッダビューの高さはまだ変更されないようです。

多くの試みのためにこの問題と戦った後。- (void)didMoveToParentViewController:(UIViewController *)parentメソッド内でヘッダービュー作成ロジックを呼び出すことで高さを変更できることがわかりました 。

したがって、コード例は次のようになります。

- (void)didMoveToParentViewController:(UIViewController *)parent {
    [super didMoveToParentViewController:parent];

    if ( _tableView.tableHeaderView == nil ) {
        UIView *header = [[[UINib nibWithNibName:@"your header view" bundle:nil] instantiateWithOwner:self options:nil] firstObject];

        header.frame = CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), HeaderViewHeight);

        [_tableView setTableHeaderView:header];
    }
}

0

UIViewのinitWithFrameイニシャライザが、渡されたrectを適切に尊重しないことを発見しました。したがって、完全に機能する次のことを行いました。

 - (id)initWithFrame:(CGRect)aRect {

    CGRect frame = [[UIScreen mainScreen] applicationFrame];

    if ((self = [super initWithFrame:CGRectZero])) {

        // Ugly initialization behavior - initWithFrame will not properly honor the frame we pass
        self.frame = CGRectMake(0, 0, frame.size.width, 200);

        // ...
    }
}

これの利点は、ビューコードへのカプセル化が向上することです。


からフレームをフェッチすることUIScreenは悪い考えです。どのようにビューを再利用しますか?
Zorayr

0

テーブルのヘッダーのアニメーション化された高さの変更を実装して、タップすると画面全体に拡大します。ただし、コードは他の場合にも役立ちます。

// Swift
@IBAction func tapped(sender: UITapGestureRecognizer) {

    self.tableView.beginUpdates()       // Required to update cells. 

    // Collapse table header to original height
    if isHeaderExpandedToFullScreen {   

        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.scrollView.frame.size.height = 110   // original height in my case is 110
        })

    }
    // Expand table header to overall screen            
    else {      
        let screenSize = self.view.frame           // "screen" size

        UIView.animateWithDuration(0.5, animations: { () -> Void in
            self.scrollView.frame.size.height = screenSize.height
        })
    }

    self.tableView.endUpdates()  // Required to update cells. 

    isHeaderExpandedToFullScreen= !isHeaderExpandedToFullScreen  // Toggle
}

0

UITableViewサイズ変更ヘッダー-スコープバー付きのUISearchBar

私が望んでいたUITableViewとしUISearchBar、私は階層構造を持っているので、テーブルのヘッダーとして、このようになります

UITableView
  |
  |--> UIView
  |     |--> UISearchBar
  |
  |--> UITableViewCells

UISearchBarDelegateメソッド

他の場所で述べたように、変更後にTableViewHeaderを設定しないと、何も起こりません。

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    searchBar.showsScopeBar = YES;
    [UIView animateWithDuration:0.2f animations:^{
        [searchBar sizeToFit];
        CGFloat height = CGRectGetHeight(searchBar.frame);

        CGRect frame = self.tableView.tableHeaderView.frame;
        frame.size.height = height;
        self.tableHeaderView.frame = frame;
        self.tableView.tableHeaderView = self.tableHeaderView;
    }];

    [searchBar setShowsCancelButton:YES animated:YES];
    return YES;
}

- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
    searchBar.showsScopeBar = NO;
    [UIView animateWithDuration:0.f animations:^{
        [searchBar sizeToFit];

        CGFloat height = CGRectGetHeight(searchBar.frame);

        CGRect frame = self.tableView.tableHeaderView.frame;
        frame.size.height = height;
        self.tableHeaderView.frame = frame;
        self.tableView.tableHeaderView = self.tableHeaderView;
    }];

    [searchBar setShowsCancelButton:NO animated:YES];
    return YES;
}

0

カスタムheaderViewがautolayoutを使用して設計されており、headerViewがWebフェッチまたは同様の遅延タスクの後で更新される必要がある場合。次に、iOS-Swiftでこれを行い、次のコードを使用してheaderViewを更新しました。

//to reload your cell data
self.tableView.reloadData()
dispatch_async(dispatch_get_main_queue(),{
// this is needed to update a specific tableview's headerview layout on main queue otherwise it's won't update perfectly cause reloaddata() is called
  self.tableView.beginUpdates()
  self.tableView.endUpdates()
} 

0

明らかに、これまでにAppleはtableHeaderViewとtableFooterView ...のUITableViewAutomaticDimensionを実装しているはずです...

以下は、レイアウト制約を使用して私のために働くようです:

CGSize   s  = [ self  systemLayoutSizeFittingSize : UILayoutFittingCompressedSize ];
CGRect   f  = [ self  frame ];

f.size   = s;

[ self  setFrame : f ];

0

tableHeaderViewがコンテンツ調整可能なwebViewの場合、次のことを試すことができます。

[self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    self.webView.height = self.webView.scrollView.contentSize.height;
    self.tableView.tableHeaderView = self.webView;
}

私はそれをiOS9とiOS11でテストし、うまくいきました。


-3

[self.tableView reloadData]高さを変えてみました か?


1
静的ビューであるtableHeaderViewについてです。- [UITableView reloadData]動的ビュー(セル)と、明らかに意図されたと考えられるsectionHeadersのみを対象としています;)
Julian F. Weinert
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.