Як змінити розмір tableHeaderView UITableView?


103

У мене виникають проблеми із зміною розміру tableHeaderView. Це просто не працює.

1) Створіть UITableView та UIView (100 x 320 пікселів);

2) Встановити UIView як tableHeaderView UITableView;

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

FYI: Я змусив це працювати, змінивши tableHeaderView і повторно встановивши його. У цьому випадку я коригую розмір tableHeaderView, коли завантаження підрозділу UIWebView закінчується.

[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" після зміни підрозділу. Проблема полягає в тому, що мій підвид змінюється за секунду розміром як анімація. Зараз я намагаюся розібратися, як анімувати tableHeaderView за допомогою нього.
Андрій

1
Ідеально, дякую купу. Для мене це приклад однієї з менш бажаних якостей властивостей у Objective-C. Немає для нас можливості (і жодної причини, яку ми повинні знати), що встановлення заголовка має побічний ефект перерахунку висоти. Він повинен або робити це автоматично, коли ми оновлюємо висоту заголовка, або нам потрібно вимагати дзвонити щось на зразок [tableView recalculateHeaderHeight]кожного разу.
jakeboxer

48
@Andrew Я знаю, що це майже на рік занадто пізно, але краще пізно, ніж ніколи: мені вдалося оживити мінливу висоту подання заголовка таблиці, завершивши 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, які не є типом класу, як клас виклику. Наприкінці анімації він викликає setTableHeaderView під наглядом (UITableView) - без цього вміст UITableView відскакує назад наступного разу, коли користувач прокручує. Єдине обмеження, яке я знайшов до цього моменту, - це якщо користувач намагається прокручувати UITableView, поки відбувається анімація, прокрутка буде анімувати так, ніби перегляд заголовка не було змінено (не велика справа, якщо анімація швидкий).


працює чудово, видалив анімацію, тому що вона мені не потрібна.
Джіхо Канг

Працював ідеально, доки iOS7 не відбувся ... додав моє рішення нижче
avishic

1
WTF? Ви так сильно псуєтесь із внутрішніми майданчиками UITableView, що насправді не варто дивуватися, що він не працює у новіших версіях iOS ...;)
Даніель Рінсер,

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

Зверніть увагу, що анімація двояка:

  1. Анімація комірок нижче tableHeaderView. Це робиться за допомогою beginUpdatesіendUpdates
  2. Анімація фактичного перегляду заголовка. Це робиться за допомогою UIViewанімаційного блоку.

Для синхронізації цих двох анімацій animationCurveнеобхідно встановити UIViewAnimationCurveEaseInOutта тривалість 0.3, що, здається, саме те, що UITableView використовує для своєї анімації.

Оновлення

Я створив проект Xcode на gihub, який робить це. Перегляньте проект ResizeTableHeaderViewAnimatedу besi / ios-quickies

скріншот


2
Ця методика працює, але вона не працює для подання таблиць із заголовками розділів. Під час використання початкових оновлень / кінцевих оновлень він заважає блоку анімації, залишаючи дублюючі заголовки розділів.
BlueFish

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

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.

Ви повинні встановити висоту UIView перед тим, як встановити tableHeaderView. (Було б набагато простіше, якби Apple відкрила джерела цієї рамки ...)


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!і підключений на дошці розкад, де він розміщений у верхній частині tableView, щоб функціонувати як tableHeaderView.


2

Це стосується лише коли ви використовуєте автоматичну компоновку та встановлені translatesAutoresizingMaskIntoConstraints = falseу власному режимі заголовка.

Найкращий і найпростіший спосіб - це перекриття intrinsicContentSize. Внутрішньо UITableViewвикористовує intrinsicContentSizeдля визначення розміру колонтитула / колонтитула. Після того, як ви перейдете intrinsicContentSizeв налаштуваннях власного перегляду, те, що вам потрібно зробити, - це як показано нижче

  1. налаштувати макет перегляду колонтитулу / колонтитула (підпогляди)
  2. викликати invalidateIntrinsicContentSize()
  3. викликати tableView.setNeedsLayout()іtableView.layoutIfNeeded()

Тоді UITableViewзаголовок / колонтитул буде оновлено, як ви хочете. Не потрібно встановлювати режим перегляду нульовим чи скинутим.

Одна річ, яка насправді цікава для, UITableView.tableHeaderViewабо .tableFooterViewце те, що вона UIStackViewвтрачає здатність керувати нею arrangedSubviews. Якщо ви хочете використовувати в UIStackViewякості tableHeaderView або tableFooterView, ви повинні вставляти в stackView в UIViewі перевизначення UIView«S intrinsicContentSize.


2

Для швидкого 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

Я виявив, що ініціалізатор initWithFrame UIView не належним чином вшановує пряму, яку я передаю. Отже, я зробив наступне, що працювало чудово:

 - (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- це погана ідея, як ви повторно використовувати свій погляд?
Зорайр

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 розроблений за допомогою автоматичного вимикання, а headerView потрібно оновити після веб-завантаження або подібного ледачого завдання. то в 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 повинна була впровадити UITableViewAutomaticDimension для tableHeaderView & tableFooterView ...

Наступне, здається, працює для мене, використовуючи контракти на компонування:

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

f.size   = s;

[ self  setFrame : f ];

0

Якщо ваш tableHeaderView - це веб-перегляд, що регулюється вмістом, ви можете спробувати:

[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]призначений лише для динамічних поглядів (осередків), а також розділу « Читачі», який ви, очевидно, думали, мався на увазі;)
Джуліан Ф. Вайнерт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.