Bagaimana cara mengubah ukuran tableHeaderView dari UITableView?

103

Saya mengalami masalah saat mengubah ukuran tableHeaderView. Sederhana saja tidak berhasil.

1) Buat UITableView dan UIView (100 x 320 px);

2) Setel UIView sebagai tableHeaderView dari UITableView;

3) Bangun dan Mulai. Semuanya baik-baik saja.

Sekarang, saya ingin mengubah ukuran tableHeaderView, jadi saya menambahkan kode ini di 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;

Tinggi tableHeaderView akan muncul dengan 200, tetapi muncul dengan 100.

Jika saya menulis:

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;

Kemudian dimulai dengan ketinggian 200, seperti yang saya inginkan. Tetapi saya ingin dapat memodifikasinya secara runtime.

Saya juga mencoba ini, tetapi tidak berhasil:

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

Intinya di sini adalah: Bagaimana cara mengubah ukuran tableHeaderView dalam runtime ???

Adakah yang bisa melakukan ini?

Terima kasih

iMe

iMe
sumber

Jawaban:

180

FYI: Saya telah membuat ini bekerja dengan memodifikasi tableHeaderView dan mengatur ulangnya. Dalam kasus ini, saya menyesuaikan ukuran tableHeaderView ketika subview UIWebView selesai dimuat.

[webView sizeToFit];
CGRect newFrame = headerView.frame;
newFrame.size.height = newFrame.size.height + webView.frame.size.height;
headerView.frame = newFrame;
[self.tableView setTableHeaderView:headerView];
kubi
sumber
13
+1 Ini berhasil untuk saya. Memanggil 'setTableHeaderView' setelah ukuran subview Anda berubah adalah kuncinya. Masalahnya adalah, subview saya mengubah ukuran lebih dari satu detik sebagai animasi. Sekarang saya mencoba mencari cara untuk menganimasikan tableHeaderView dengannya.
Andrew
1
Sempurna, terima kasih banyak. Bagi saya, ini adalah contoh salah satu kualitas properti yang kurang diinginkan di Objective-C. Tidak ada cara bagi kita untuk mengetahui (dan tidak ada alasan kita harus tahu) bahwa pengaturan tajuk memiliki efek samping menghitung ulang ketinggian. Itu harus melakukannya secara otomatis ketika kita memperbarui tinggi tajuk, atau kita harus diminta untuk memanggil sesuatu seperti itu [tableView recalculateHeaderHeight]setiap saat.
jakeboxer
48
@ Andrew Saya tahu ini hampir satu tahun terlambat, tetapi lebih baik terlambat daripada tidak pernah: Saya dapat menganimasikan ketinggian yang berubah dari tampilan tajuk tabel dengan membungkus setTableHeaderView:panggilan dengan [tableview beginUpdates]dan[tableview endUpdates]
jasongregori
2
@jasongregori komentar berguna yang Anda tambahkan - saya melihat bahwa teknik yang sama (beginUpdates + endUpdates) tidak menganimasikan perubahan ketinggian untuk tableFooterView seperti yang dilakukan tableHeaderView. Sudahkah Anda menemukan cara yang baik untuk menganimasikan tableFooterView juga?
keris
1
Mengesankan, acara ini berfungsi saat melakukannya di dalam blok animasi UIView, meskipun menurut saya itu tidak terlalu efisien dalam kasus itu.
Bisa
12

Jawaban ini sudah lama dan tampaknya tidak berfungsi di iOS 7 ke atas.

Saya mengalami masalah yang sama, dan saya juga ingin perubahan beranimasi, jadi saya membuat subclass UIView untuk tampilan header saya dan menambahkan metode ini:

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

Ini pada dasarnya menganimasikan semua subview dari UITableView yang bukan tipe kelas yang sama dengan kelas pemanggil. Di akhir animasi, ini memanggil setTableHeaderView di superview (UITableView) - tanpa ini, konten UITableView akan melompat kembali saat pengguna menggulir. Satu-satunya batasan yang saya temukan sejauh ini adalah jika pengguna mencoba menggulir UITableView saat animasi berlangsung, pengguliran akan beranimasi seolah-olah tampilan tajuk belum diubah ukurannya (bukan masalah besar jika animasinya diubah). cepat).

garrettmoon
sumber
bekerja dengan sempurna, menghapus animasi karena saya tidak membutuhkannya.
Jiho Kang
Bekerja sempurna sampai iOS7 terjadi ... menambahkan solusi saya di bawah
avishic
1
WTF? Anda terlalu banyak mengotak-atik bagian dalam UITableView sehingga Anda tidak perlu terkejut karena UITableView tidak berfungsi di versi iOS yang lebih baru ...;)
Daniel Rinser
10

Jika Anda ingin menganimasikan perubahan secara bersyarat, Anda dapat melakukan hal berikut:

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

Harap dicatat bahwa animasinya dua kali lipat:

  1. Animasi sel di bawah tableHeaderView. Ini dilakukan dengan menggunakan beginUpdatesdanendUpdates
  2. Animasi tampilan header yang sebenarnya. Ini dilakukan dengan menggunakan UIViewblok animasi.

Untuk menyinkronkan dua animasi itu, animationCurveharus disetel ke UIViewAnimationCurveEaseInOutdan durasinya 0.3, yang tampaknya menjadi apa yang digunakan UITableView untuk animasinya.

Memperbarui

Saya membuat proyek Xcode di gihub, yang melakukan ini. Lihat proyek ResizeTableHeaderViewAnimateddi besi / ios-quickies

tangkapan layar

Besi
sumber
2
Teknik ini berfungsi, tetapi tidak berfungsi untuk tampilan tabel dengan header bagian. Saat Anda menggunakan mulai pembaruan / akhir pembaruan itu mengganggu blok animasi, meninggalkan duplikat header bagian.
BlueFish
9

Saya pikir itu harus berfungsi jika Anda hanya mengatur ketinggian myHeaderView seperti ini:

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

self.tableView.tableHeaderView = myHeaderView;
Greg Martin
sumber
Ini benar-benar berfungsi, tetapi hanya jika digunakan dalam viewDidLayoutSubviews
KoCMoHaBTa
6

Menggunakan solusi @garrettmoon di atas hingga iOS 7.
Berikut adalah solusi yang diperbarui berdasarkan @ garrettmoon's:

- (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];
}
avishic
sumber
5

Ini bekerja untuk saya di iOS 7 dan 8. Kode ini berjalan pada pengontrol tampilan tabel.

[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];
}];
Darcy Rayner
sumber
4

Ini karena penyetel tableHeaderView.

Anda harus menyetel tinggi UIView sebelum menyetel tableHeaderView. (Akan jauh lebih mudah jika Apple membuka sumber kerangka kerja ini ...)

Thomas Decaux
sumber
4

Pada iOS 9 dan lebih rendah, tableHeaderViewtidak akan menata ulang setelah mengubah ukurannya. Masalah ini diselesaikan di iOS 10.

Untuk mengatasi masalah ini, lakukan saja dengan kode berikut:

self.tableView.tableHeaderView = self.tableView.tableHeaderView;
klaudz.dll
sumber
2

Di iOS 9.x, melakukan ini pada viewDidLoadberfungsi dengan baik:

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

headerViewdideklarasikan sebagai @IBOutlet var headerView: UIView!dan terhubung di storyboard, di mana ia ditempatkan di bagian atas tableView, untuk berfungsi sebagai tableHeaderView.

Eneko Alonso
sumber
2

Ini hanya untuk saat Anda menggunakan tata letak otomatis dan menyetel translatesAutoresizingMaskIntoConstraints = falseke tampilan tajuk khusus.

Cara terbaik dan termudah adalah menimpa intrinsicContentSize. Secara internal UITableViewdigunakan intrinsicContentSizeuntuk menentukan ukuran header / footernya. Setelah Anda mengganti intrinsicContentSizedalam tampilan kustom Anda, Yang perlu Anda lakukan adalah seperti di bawah ini

  1. konfigurasikan tata letak tampilan header / footer kustom (subview)
  2. memohon invalidateIntrinsicContentSize()
  3. memanggil tableView.setNeedsLayout()dantableView.layoutIfNeeded()

Kemudian UITableViewheader / footer akan diperbarui sesuai keinginan Anda. Tidak perlu mengatur tampilan nihil atau mengatur ulang.

Satu hal yang sangat menarik bagi UITableView.tableHeaderViewatau .tableFooterViewadalah UIStackViewkehilangan kemampuannya untuk mengelolanya arrangedSubviews. Jika Anda ingin menggunakan UIStackViewsebagai tableHeaderView atau tableFooterView, Anda harus menanamkan stackView dalam UIViewdan menimpa UIView's intrinsicContentSize.

Ryan
sumber
2

Untuk cepat 5 kode Teruji

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

Catatan: Anda perlu memberikan semua batasan subview dari top, bottom, leading, trailing. Jadi itu akan mendapatkan seluruh ukuran yang dibutuhkan.

Referensi diambil dari: https://useyourloaf.com/blog/variable-height-table-view-header/

Hardik Thakkar
sumber
1

Pengaturan tinggi properti tampilan header tableView.tableHeaderViewdi viewDidLoadtampaknya tidak berfungsi, tinggi tampilan header masih tidak berubah sesuai harapan.

Setelah berjuang melawan masalah ini untuk banyak percobaan. Saya menemukan bahwa, Anda dapat mengubah ketinggian dengan menjalankan tampilan header membuat logika di dalam - (void)didMoveToParentViewController:(UIViewController *)parentmetode.

Jadi kode contoh akan terlihat seperti ini:

- (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];
    }
}
Enix
sumber
0

Saya menemukan initWithFrame penginisialisasi dari UIView tidak benar-benar menghormati rect yang saya berikan. Oleh karena itu, saya melakukan hal berikut yang bekerja dengan sempurna:

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

        // ...
    }
}

Keuntungannya adalah lebih baik dikemas ke dalam kode tampilan Anda.

Harald Schubert
sumber
Mengambil bingkai dari UIScreenadalah ide yang buruk, bagaimana Anda akan menggunakan kembali tampilan Anda?
Zorayr
0

Saya telah menerapkan perubahan tinggi animasi header tabel untuk memperluas ke layar keseluruhan saat diketuk. Namun, kode dapat membantu dalam kasus lain:

// 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
}
Alexander Volkov
sumber
0

Header pengubah ukuran UITableView - UISearchBar dengan Scope Bar

Saya menginginkan a UITableViewdengan a UISearchBarsebagai tajuk ke tabel jadi saya memiliki hierarki yang terlihat seperti ini

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

UISearchBarDelegate

Seperti yang telah dinyatakan di tempat lain, jika Anda tidak menyetelTableViewHeader setelah mengubahnya, tidak akan terjadi apa-apa.

- (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;
}
Cameron Lowell Palmer
sumber
0

Jika custom headerView dirancang menggunakan autolayout dan headerView perlu diperbarui setelah web-fetch atau tugas malas serupa. kemudian di iOS-Swift saya melakukan ini dan memperbarui headerView saya menggunakan kode di bawah ini:

//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()
} 
Rafat touqir Rafsun
sumber
0

Jelas, sekarang Apple seharusnya telah mengimplementasikan UITableViewAutomaticDimension untuk tableHeaderView & tableFooterView ...

Berikut ini tampaknya berfungsi untuk saya menggunakan contraint layout:

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

f.size   = s;

[ self  setFrame : f ];
digitaldaemon
sumber
0

Jika tableHeaderView Anda adalah webView yang dapat disesuaikan konten, Anda dapat mencoba:

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

Saya mengujinya di iOS9 dan iOS11, bekerja dengan baik.

无 夜 之 星辰
sumber
-3

Apakah Anda mencoba [self.tableView reloadData]setelah mengubah ketinggian?

codelogic
sumber
1
Ini tentang tableHeaderView, yang merupakan tampilan statis. - [UITableView reloadData]hanya ditujukan untuk tampilan dinamis (sel) dan juga sectionHeaders yang Anda pikir jelas dimaksudkan;)
Julian F. Weinert