Bir UITableView için tableHeaderView nasıl yeniden boyutlandırılır?


103

TableHeaderView'ı yeniden boyutlandırmada sorun yaşıyorum. Basit çalışmıyor.

1) Bir UITableView ve UIView (100 x 320 piksel) oluşturun;

2) UIView 'u UITableView' un tableHeaderView olarak ayarlayın;

3) İnşa Et ve Devam Et. Her şey yolunda.

Şimdi, tableHeaderView'ı yeniden boyutlandırmak istiyorum, bu yüzden bu kodu viewDidLoad'a ekliyorum:

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 yüksekliği 200 ile görünmeli, ancak 100 ile görünmelidir.

Eğer yazarsam:

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;

Sonra istediğim gibi 200 boyla başlıyor. Ama bunu çalışma zamanında değiştirebilmek istiyorum.

Bunu da denedim, başarılı olamadım:

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

Buradaki nokta şudur: Bir tableHeaderView'ı çalışma zamanında nasıl yeniden boyutlandırırız ???

Bunu yapabilen var mı?

Teşekkürler

iMe

Yanıtlar:


180

Bilginize: Bunu, tableHeaderView'ı değiştirip yeniden ayarlayarak çalıştırdım. Bu durumda, UIWebView alt görünümü yüklemeyi bitirdiğinde tableHeaderView boyutunu ayarlıyorum.

[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 Bu benim için çalıştı. Alt görünümünüzün boyutu değiştikten sonra 'setTableHeaderView' çağrısı anahtar noktadır. Sorun şu ki, alt görünümüm animasyon olarak bir saniyede boyut değiştiriyor. Şimdi tableHeaderView ile nasıl canlandırılacağını anlamaya çalışıyorum.
Andrew

1
Mükemmel, çok teşekkürler. Bana göre bu, Objective-C'deki özelliklerin daha az istenen niteliklerinden birine bir örnektir. Başlığı ayarlamanın yüksekliği yeniden hesaplamak gibi yan etkiye sahip olduğunu bilmemizin bir yolu yoktur (ve bilmemiz için bir neden yoktur). Başlığın yüksekliğini güncellediğimizde bunu otomatik olarak yapmalı ya da [tableView recalculateHeaderHeight]her seferinde olduğu gibi bir şey aramamız gerekmeli .
jakeboxer

48
@Andrew bunun neredeyse bir yıl geç olduğunu biliyorum, ama hiç olmamasından daha geç olması daha iyi: setTableHeaderView:Çağrıyı [tableview beginUpdates]ve[tableview endUpdates]
jasongregori

2
@jasongregori eklediğiniz kullanışlı yorum - aynı tekniğin (beginUpdates + endUpdates) bir tableFooterView için bir tableHeaderView gibi yükseklik değişikliğini canlandırmadığını görüyorum. TableFooterView'ı da canlandırmanın iyi bir yolunu buldunuz mu?
kris

1
Etkileyici, olay bir UIView animasyon bloğu içinde yapıldığında çalışıyor, ancak bu durumda çok verimli olduğunu düşünmüyorum.
Can

12

Bu cevap eski ve görünüşe göre iOS 7 ve üzeri sürümlerde çalışmıyor.

Aynı problemle karşılaştım ve değişikliklerin canlandırılmasını da istedim, bu yüzden başlık görünümüm için bir UIView alt sınıfı yaptım ve şu yöntemleri ekledim:

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

Bu, esasen, çağıran sınıfla aynı sınıf türü olmayan UITableView'ın tüm alt görünümlerini canlandırır. Animasyonun sonunda, süpervizyon üzerinde setTableHeaderView (UITableView) çağırır - bu olmadan UITableView içeriği, kullanıcının bir sonraki kaydırmasında geri atlayacaktır. Şimdiye kadar bulduğum tek sınırlama, kullanıcı animasyon devam ederken UITableView'ı kaydırmaya çalışırsa, kaydırma, üstbilgi görünümü yeniden boyutlandırılmamış gibi hareket edecek (animasyon ise hızlı).


mükemmel çalışıyor, ihtiyacım olmadığı için animasyonu kaldırdım.
Jiho Kang

İOS7 gerçekleşene kadar mükemmel çalıştı ... çözümümü aşağıya ekledi
avishic

1
O NE LAN? UITableView'ın içindekilerle o kadar çok uğraşıyorsunuz ki, daha yeni iOS sürümlerinde çalışmamasına gerçekten şaşırmamalısınız ...;)
Daniel Rinser

10

Değişiklikleri koşullu olarak canlandırmak istiyorsanız, aşağıdakileri yapabilirsiniz:

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

Lütfen animasyonun iki katlı olduğunu unutmayın:

  1. Altındaki hücrelerin animasyonu tableHeaderView. Bu beginUpdatesve kullanılarak yapılırendUpdates
  2. Gerçek başlık görünümünün animasyonu. Bu, bir UIViewanimasyon bloğu kullanılarak yapılır .

Bu iki animasyonu senkronize etmek için , UITableView'ün animasyonu için kullandığı gibi görünen ve süresi animationCurveayarlanmalıdır .UIViewAnimationCurveEaseInOut0.3

Güncelleme

Gihub'da bunu yapan bir Xcode projesi oluşturdum. Besi / ios-quickies'deki projeye ResizeTableHeaderViewAnimatedgöz atın

ekran görüntüsü


2
Bu teknik işe yarıyor, ancak bölüm başlıklarına sahip tablo görünümlerinde çalışmıyor. Güncellemeleri başlat / güncellemeleri bitir kullandığınızda, animasyon bloğuna müdahale eder ve yinelenen bölüm başlıkları bırakır.
BlueFish

9

MyHeaderView yüksekliğini şu şekilde ayarlarsanız işe yarayacağını düşünüyorum:

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

self.tableView.tableHeaderView = myHeaderView;

Bu gerçekten işe yarıyor, ancak yalnızca viewDidLayoutSubviews
KoCMoHaBTa

6

İOS 7'ye kadar yukarıda @garrettmoon çözümü kullanıldı.
İşte @ garrettmoon'a göre güncellenmiş bir çözüm:

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

Bu benim için iOS 7 ve 8'de çalıştı. Bu kod, tablo görünümü denetleyicisinde çalışıyor.

[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

Bunun nedeni tableHeaderView ayarlayıcısının olmasıdır.

TableHeaderView'ı ayarlamadan önce UIView yüksekliğini ayarlamanız gerekir. (Apple bu çerçeveyi kaynakları açarsa çok daha kolay olurdu ...)


4

İOS 9 ve daha eski sürümlerde, tableHeaderViewyeniden boyutlandırıldıktan sonra yeniden düzenlenmez. Bu sorun iOS 10'da çözülmüştür.

Bu sorunu çözmek için aşağıdaki kodla yapmanız yeterlidir:

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

2

İOS 9.x'te bunu yapmak viewDidLoadgayet iyi çalışıyor:

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

headerView, @IBOutlet var headerView: UIView!tableHeaderView olarak işlev görmesi için tableView'in en üstüne yerleştirildiği film şeridi olarak bildirilir ve bağlanır.


2

Bu yalnızca otomatik düzen kullandığınızda ve translatesAutoresizingMaskIntoConstraints = falseözel bir başlık görünümüne ayarladığınızda geçerlidir .

En iyi ve en basit yol geçersiz kılmaktır intrinsicContentSize. Üstbilgi / altbilgi boyutuna karar vermek için dahili olarak UITableViewkullanır intrinsicContentSize. intrinsicContentSizeÖzel görünümünüzde geçersiz kıldıktan sonra yapmanız gereken şey aşağıdaki gibidir

  1. özel üstbilgi / altbilgi görünümünün düzenini yapılandırın (alt görünümler)
  2. çağırmak invalidateIntrinsicContentSize()
  3. çağır tableView.setNeedsLayout()vetableView.layoutIfNeeded()

Ardından UITableView'ın üstbilgi / altbilgisi istediğiniz gibi güncellenecektir. Görünümü sıfırlamaya veya sıfırlamaya gerek yok.

UITableView.tableHeaderViewVeya için gerçekten ilginç olan bir şey .tableFooterView, onu UIStackViewyönetme yeteneğini kaybetmesidir arrangedSubviews. Kullanmak isterseniz UIStackViewbir tableHeaderView veya tableFooterView olarak, bir gömmek stackView zorunda UIViewve geçersiz kılma UIView's intrinsicContentSize.


2

Swift 5 için test edilmiş kod

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

Not: Alt görünümün tüm kısıtlamalarını üst, alt, satır başı, sondan vermeniz gerekir. Böylece gerekli boyutun tamamını alacaktır.

Referans şu adresten alınmıştır: https://useyourloaf.com/blog/variable-height-table-view-header/


1

Ayar yüksekliği başlık görünümü özelliği için tableView.tableHeaderViewde viewDidLoadbeklendiği gibi değil işi gibi görünüyor, başlık görünümü yüksekliği hala değişmez.

Bu sorunla birçok deneme için mücadele ettikten sonra. - (void)didMoveToParentViewController:(UIViewController *)parentYöntemin içinde başlık görünümü oluşturma mantığını çağırarak yüksekliği değiştirebileceğinizi buldum .

Dolayısıyla örnek kod şöyle görünecektir:

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

Bir UIView initWithFrame başlatıcısının geçtiğim düzeltmeyi tam olarak karşılamadığını buldum. Bu nedenle, aşağıdakileri mükemmel bir şekilde yaptım:

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

        // ...
    }
}

Bunun avantajı, görünüm kodunuza daha iyi kapsüllenmiş olmasıdır.


Çerçeveyi içinden almak UIScreenkötü bir fikir, görünümünüzü nasıl yeniden kullanacaksınız?
Zorayr

0

Dokunulduğunda genel ekrana genişletmek için tablo başlığının animasyonlu yükseklik değişikliğini uyguladım. Bununla birlikte, kod diğer durumlarda yardımcı olabilir:

// 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 yeniden boyutlandırma başlığı - Kapsam Çubuğu ile UISearchBar

Ben istediğim UITableViewbir ile UISearchBarbir hiyerarşi var bu yüzden tabloya başlık olarak bu böyle görünüyor

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

UISearchBarDelegate yöntemleri

Başka bir yerde belirtildiği gibi, değiştirdikten sonraTableViewHeader'ı ayarlamazsanız, hiçbir şey olmayacaktır.

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

Özel headerView otomatik düzen kullanılarak tasarlandıysa ve web getirme veya benzer yavaş görevlerden sonra headerView'ın güncellenmesi gerekiyorsa. sonra iOS- Swift'de bunu yaptım ve aşağıdaki kodu kullanarak headerView güncellememi aldım:

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

Açıkçası, Apple şimdiye kadar tableHeaderView & tableFooterView için UITableViewAutomaticDimension uygulamış olmalıydı ...

Aşağıdakiler, düzen kurallarını kullanarak benim için çalışıyor gibi görünüyor:

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

f.size   = s;

[ self  setFrame : f ];

0

TableHeaderView'unuz içerikle ayarlanabilir bir webView ise şunları deneyebilirsiniz:

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

İOS9 ve iOS11'de test ettim, iyi çalıştı.


-3

Boyu [self.tableView reloadData]değiştirdikten sonra denedin mi?


1
Statik bir görünüm olan tableHeaderView hakkındadır. - [UITableView reloadData]yalnızca dinamik görünümler (hücreler) ve ayrıca kast edildiğini düşündüğünüz bölüm Başlıkları için tasarlanmıştır;)
Julian F. Weinert
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.