Wie kann ich die Größe einer tableHeaderView einer UITableView ändern?

103

Ich habe Probleme beim Ändern der Größe einer tableHeaderView. Es funktioniert einfach nicht.

1) Erstellen Sie eine UITableView und eine UIView (100 x 320 px).

2) Legen Sie die UIView als tableHeaderView der UITableView fest.

3) Bauen und loslegen. Alles ist ok.

Jetzt möchte ich die Größe der tableHeaderView ändern, also füge ich diesen Code in viewDidLoad hinzu:

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;

Die Höhe der tableHeaderView sollte mit 200, aber mit 100 angezeigt werden.

Wenn ich schreibe:

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;

Dann beginnt es mit 200 Höhenmetern, wie ich will. Aber ich möchte es in der Laufzeit ändern können.

Ich habe es auch ohne Erfolg versucht:

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

Der Punkt hier ist: Wie ändern wir die Größe einer tableHeaderView zur Laufzeit ???

Kann jemand das tun?

Vielen Dank

iMe

iMe
quelle

Antworten:

180

Zu Ihrer Information: Ich habe dies zum Laufen gebracht, indem ich die tableHeaderView geändert und neu eingestellt habe. In diesem Fall passe ich die Größe der tableHeaderView an, wenn die UIWebView-Unteransicht vollständig geladen wurde.

[webView sizeToFit];
CGRect newFrame = headerView.frame;
newFrame.size.height = newFrame.size.height + webView.frame.size.height;
headerView.frame = newFrame;
[self.tableView setTableHeaderView:headerView];
kubi
quelle
13
+1 Das hat bei mir funktioniert. Der Aufruf von 'setTableHeaderView', nachdem sich die Größe Ihrer Unteransicht geändert hat, ist der Schlüssel. Das Problem ist, dass meine Unteransicht als Animation im Laufe einer Sekunde die Größe ändert. Jetzt versuche ich herauszufinden, wie man die tableHeaderView damit animiert.
Andrew
1
Perfekt, danke ein paar. Für mich ist dies ein Beispiel für eine der weniger wünschenswerten Eigenschaften von Eigenschaften in Objective-C. Wir können nicht wissen (und keinen Grund, warum wir wissen sollten), dass das Setzen des Headers den Nebeneffekt hat, die Höhe neu zu berechnen. Dies sollte entweder automatisch geschehen, wenn wir die Höhe des Headers aktualisieren, oder wir sollten [tableView recalculateHeaderHeight]jedes Mal so etwas aufrufen müssen .
Jakeboxer
48
@ Andrew Ich weiß, dass dies fast ein Jahr zu spät ist, aber besser spät als nie: Ich konnte die sich ändernde Höhe der Tabellenkopfansicht animieren, indem ich den setTableHeaderView:Anruf mit [tableview beginUpdates]und[tableview endUpdates]
jasongregori
2
@jasongregori praktischer Kommentar, den Sie hinzugefügt haben - ich sehe, dass dieselbe Technik (beginUpdates + endUpdates) die Höhenänderung für eine tableFooterView nicht so animiert wie für eine tableHeaderView. Haben Sie einen guten Weg gefunden, um auch tableFooterView zu animieren?
Kris
1
Beeindruckend, es funktioniert, wenn es in einem UIView-Animationsblock ausgeführt wird, obwohl ich denke, dass es in diesem Fall nicht sehr effizient ist.
Kann
12

Diese Antwort ist alt und funktioniert anscheinend nicht unter iOS 7 und höher.

Ich bin auf dasselbe Problem gestoßen und wollte auch, dass die Änderungen animiert werden. Deshalb habe ich eine Unterklasse von UIView für meine Header-Ansicht erstellt und die folgenden Methoden hinzugefügt:

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

Dadurch werden im Wesentlichen alle Unteransichten der UITableView animiert, die nicht denselben Klassentyp wie die aufrufende Klasse haben. Am Ende der Animation wird setTableHeaderView in der Übersicht (UITableView) aufgerufen. Ohne diese Option springt der UITableView-Inhalt beim nächsten Bildlauf zurück. Die einzige Einschränkung, die ich bisher gefunden habe, ist, wenn der Benutzer versucht, die UITableView zu scrollen, während die Animation stattfindet, wird das Scrollen so animiert, als ob die Größe der Kopfzeilenansicht nicht geändert worden wäre (keine große Sache, wenn die Animation ist schnell).

Garrettmoon
quelle
funktioniert perfekt, entfernte die Animation, weil ich sie nicht brauchte.
Jiho Kang
Funktionierte perfekt, bis iOS7 passierte ... fügte meine Lösung unten hinzu
avishic
1
WTF? Sie spielen so viel mit den Interna von UITableView, dass Sie sich wirklich nicht wundern sollten, dass es in neueren iOS-Versionen nicht funktioniert ...;)
Daniel Rinser
10

Wenn Sie die Änderungen unter bestimmten Bedingungen animieren möchten, können Sie Folgendes tun:

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

Bitte beachten Sie, dass die Animation zweifach gefaltet ist:

  1. Die Animation der Zellen unter dem tableHeaderView. Dies geschieht mit beginUpdatesundendUpdates
  2. Die Animation der eigentlichen Header-Ansicht. Dies erfolgt über einen UIViewAnimationsblock.

Um diese beiden Animationen zu synchronisieren animationCurve, muss die UIViewAnimationCurveEaseInOutund die Dauer 0.3auf eingestellt werden. Dies scheint das zu sein, was UITableView für seine Animation verwendet.

Aktualisieren

Ich habe ein Xcode-Projekt auf gihub erstellt, das dies tut. Schauen Sie sich das Projekt ResizeTableHeaderViewAnimatedin besi / ios-quickies an

Bildschirmfoto

Besi
quelle
2
Diese Technik funktioniert zwar, aber nicht für Tabellenansichten mit Abschnittsüberschriften. Wenn Sie Startupdates / Endupdates verwenden, stört dies den Animationsblock und hinterlässt doppelte Abschnittsüberschriften.
BlueFish
9

Ich denke, es sollte funktionieren, wenn Sie einfach die Höhe von myHeaderView so einstellen:

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

self.tableView.tableHeaderView = myHeaderView;
Greg Martin
quelle
Dies funktioniert tatsächlich, aber nur, wenn es in viewDidLayoutSubviews
KoCMoHaBTa
6

Verwendete @ Garrettmoon-Lösung oben bis iOS 7.
Hier ist eine aktualisierte Lösung, die auf @ Garrettmoon basiert:

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

Dies funktionierte für mich unter iOS 7 und 8. Dieser Code wird auf dem Table View Controller ausgeführt.

[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
quelle
4

Es liegt daran, dass der Setter von tableHeaderView.

Sie müssen die UIView-Höhe festlegen, bevor Sie tableHeaderView festlegen können. (Wäre viel einfacher, wenn Apple dieses Framework als Open Source anbietet ...)

Thomas Decaux
quelle
4

Unter iOS 9 und niedriger tableHeaderView das Layout nach dem Ändern der Größe nicht neu gestaltet. Dieses Problem wurde in iOS 10 behoben.

Um dieses Problem zu lösen, führen Sie einfach den folgenden Code aus:

self.tableView.tableHeaderView = self.tableView.tableHeaderView;
klaudz
quelle
2

Unter iOS 9.x viewDidLoadfunktioniert dies einwandfrei:

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

headerViewwird @IBOutlet var headerView: UIView!im Storyboard als deklariert und verbunden, wo es oben in der tableView platziert wird, um als tableHeaderView zu fungieren.

Eneko Alonso
quelle
2

Dies gilt nur, wenn Sie das automatische Layout verwenden und festlegen translatesAutoresizingMaskIntoConstraints = false eine benutzerdefinierte Kopfzeilenansicht .

Der beste und einfachste Weg ist das Überschreiben intrinsicContentSize. Wird intern UITableViewverwendet intrinsicContentSize, um die Größe der Kopf- / Fußzeile zu bestimmen. Sobald Sie intrinsicContentSizeIhre benutzerdefinierte Ansicht überschrieben haben , müssen Sie wie folgt vorgehen

  1. Konfigurieren Sie das Layout der benutzerdefinierten Kopf- / Fußzeilenansicht (Unteransichten).
  2. aufrufen invalidateIntrinsicContentSize()
  3. aufrufen tableView.setNeedsLayout()undtableView.layoutIfNeeded()

Dann wird die UITableViewKopf- / Fußzeile des Benutzers nach Ihren Wünschen aktualisiert. Sie müssen die Ansicht nicht auf Null setzen oder zurücksetzen.

Eine Sache, die für das UITableView.tableHeaderViewoder wirklich interessant .tableFooterViewist, ist, dass es UIStackViewseine Fähigkeit verliert, es zu verwalten arrangedSubviews. Wenn Sie verwenden möchten , UIStackViewals tableHeaderView oder tableFooterView, Sie haben die stackView in ein einbetten UIViewund überschreiben UIView‚s intrinsicContentSize.

Ryan
quelle
2

Für schnelle 5 Getesteten Code

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

Hinweis: Sie müssen alle Einschränkungen der Unteransicht von oben, unten, oben und unten angeben. So wird es die gesamte benötigte Größe bekommen.

Referenz entnommen aus: https://useyourloaf.com/blog/variable-height-table-view-header/

Hardik Thakkar
quelle
1

Das Festlegen der Höhe für die Header-Ansichtseigenschaft tableView.tableHeaderViewin viewDidLoadscheint nicht zu funktionieren. Die Höhe der Header-Ansicht ändert sich immer noch nicht wie erwartet.

Nach dem Kampf gegen dieses Problem für viele Versuche. Ich habe festgestellt, dass Sie die Höhe ändern können, indem Sie die Erstellungslogik der Header-Ansicht innerhalb der - (void)didMoveToParentViewController:(UIViewController *)parentMethode aufrufen .

Der Beispielcode würde also so aussehen:

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

Ich habe festgestellt, dass der initWithFrame-Initialisierer eines UIView das von mir übergebene Rect nicht richtig berücksichtigt. Daher habe ich Folgendes getan, was perfekt funktioniert hat:

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

        // ...
    }
}

Dies hat den Vorteil, dass es besser in Ihren Ansichtscode eingekapselt ist.

Harald Schubert
quelle
Das Abrufen des Rahmens von UIScreenist eine schlechte Idee. Wie werden Sie Ihre Ansicht wiederverwenden?
Zorayr
0

Ich habe eine animierte Höhenänderung der Kopfzeile der Tabelle implementiert, um sie beim Tippen auf den Gesamtbildschirm zu erweitern. Der Code kann jedoch in anderen Fällen hilfreich sein:

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

UITableView-Header zur Größenänderung - UISearchBar mit Bereichsleiste

Ich wollte ein UITableViewmit einem UISearchBarals Überschrift für die Tabelle, also habe ich eine Hierarchie, die so aussieht

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

UISearchBarDelegate-Methoden

Wie bereits an anderer Stelle erwähnt, geschieht nichts, wenn Sie TableViewHeader nach dem Ändern nicht festlegen.

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

Wenn die benutzerdefinierte headerView mit Autolayout erstellt wurde und headerView nach dem Webabruf oder einer ähnlichen verzögerten Aufgabe aktualisiert werden muss. dann habe ich dies in iOS-Swift getan und meine Header-Ansicht mit folgendem Code aktualisiert:

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

Offensichtlich sollte Apple jetzt UITableViewAutomaticDimension für tableHeaderView & tableFooterView implementiert haben ...

Folgendes scheint für mich mit Layout-Kontraint (s) zu funktionieren:

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

f.size   = s;

[ self  setFrame : f ];
digitaldaemon
quelle
0

Wenn Ihre tableHeaderView eine inhaltsanpassbare WebView ist, können Sie Folgendes versuchen:

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

Ich habe es auf iOS9 und iOS11 getestet und gut funktioniert.

无 夜 之 星辰
quelle
-3

Haben Sie es [self.tableView reloadData]nach dem Ändern der Höhe versucht ?

codelogic
quelle
1
Es geht um die tableHeaderView, eine statische Ansicht. - [UITableView reloadData]ist nur für die dynamischen Ansichten (Zellen) und auch die sectionHeaders gedacht, von denen Sie offensichtlich dachten, dass sie gemeint sind;)
Julian F. Weinert