Налаштування на висоті рядків стільникових рядків у рекламній дошці не відповідає


213

Я намагаюся регулювати висоту комірок для однієї з комірок на моєму поданні таблиці. Я коригую розмір із налаштування "висота рядка" всередині "інспектора розміру" відповідної комірки. Коли я запускаю додаток на своєму iPhone, у клітинку встановлений розмір за замовчуванням, встановлений із "розміру рядка" на поданні таблиці.

Якщо я зміню "розмір рядка" у поданні таблиці, то розмір усіх комірок змінюється. Я не хочу цього робити, оскільки я хочу користувацький розмір лише для однієї комірки. Я бачив безліч дописів, які мають програмне рішення проблеми, але я вважаю за краще робити це через раскадровку, якщо це можливо.

Відповіді:


295

У динамічних комірках, rowHeightвстановлених на UITableView, завжди переосмислює рядок висоти окремих клітин.

Але для статичних комірок, rowHeightвстановлених на окремих клітинках, може перекрити UITableView.

Не впевнений, чи це помилка, Apple, можливо, це навмисно робить?


36
Правильна відповідь №3, а саме тому, що ця відповідь стосується Інтерфейсу / Будівельника. Якщо вибрати комірку в IB, то розмір Інспектор показує Висота рядка в верхній частині (з «звичаєм» прапорцем), але якщо ви вибираєте всю таблицю перегляд в розмірі Інспектор показує Висоту рядка в верхніх там теж (немає « на замовлення " в цьому випадку). Як говорить pixelfreak, для динамічних комірок використовується лише налаштування подання таблиці. (Не впевнений, чи це навмисно)
Rhubarb

8
ця відповідь означає, що рішенням було б просто змінити UITableViewзміст Dynamic Prototypesна Static Cells, я це зробив, і весь мій проект вибухнув .. мало не вбили себе.
abbood

4
Чи є спосіб отримати це число? Єдиний спосіб копати його в глибині - це зануритися в табло та витягнути звідти?
Біклопс

Це, безумовно, НЕ помилка, тому що ваша таблиця є динамічною, так як система могла знати, куди ви пішли, використовуючи кожну з цих комірок? І скільки разів буде використаний кожен прототип.
Вінсент Берньє

Здається, існує проблема, якщо ви спочатку встановите подання таблиці як "статичні комірки", а потім заміните його на "динамічні прототипи". У мене виникла проблема, коли навіть метод делегата для rowHeight ігнорувався. Я спершу вирішив це, безпосередньо редагуючи XML-майданчик, а потім, нарешті, просто відновив сцену розгортки з нуля, використовуючи динамічні прототипи з самого початку.
Ерік Голдберг

84

Якщо ви використовуєте UITableViewController, реалізуйте цей метод:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

У функції рядка ви можете вибрати висоту. Наприклад,

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
       return 100;
    } 
    else {
       return 60;
    }
}

У цьому прикладі висота першого ряду становить 100 пікселів, а інші - 60 пікселів.

Я сподіваюся, що цей може вам допомогти.


2
Бебер, чи повинен ВЖЕ один раз робити те саме (встановіть прапорець "Користувацькі" та відредагуйте значення "Висота рядка" у розкадровці та вкажіть його у висотуForRowAtIndexPath)?
marciokoko

Чи можете ви мені допомогти з цього приводу? Мені потрібно мати динамічні комірки з динамічною висотою, але якщо я використовую цей метод, незалежно від того, що я повертаю всі клітини замість цього. За винятком iPhone 5 влаштування , де він працює , як очікувалося. Ви можете зрозуміти, чому?
Ostmeistro

34

Для динамічних комірок rowHeightвстановіть на UITableViewзавжди переорієнтовані осередки ' rowHeight.

Така поведінка, IMO, помилка. Щоразу, коли вам доведеться керувати своїм інтерфейсом у двох місцях, він схильний до помилок. Наприклад, якщо ви змінюєте розмір стільника на дошці розкадрувань, вам потрібно пам’ятати, що можна також змінити їх heightForRowAtIndexPath:. Поки Apple не виправить помилку, найкращим поточним рішенням є переосмислення heightForRowAtIndexPath:, але використовувати фактичні комірки-прототипи з розгортки для визначення висоти, а не використання магічних чисел . Ось приклад:

- (CGFloat)tableView:(UITableView *)tableView 
           heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* In this example, there is a different cell for
       the top, middle and bottom rows of the tableView.
       Each type of cell has a different height.
       self.model contains the data for the tableview 
    */
    static NSString *CellIdentifier;
    if (indexPath.row == 0) 
        CellIdentifier = @"CellTop";
    else if (indexPath.row + 1 == [self.model count] )
        CellIdentifier = @"CellBottom";
    else
        CellIdentifier = @"CellMiddle";

    UITableViewCell *cell = 
              [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    return cell.bounds.size.height;
}

Це забезпечить будь-які зміни у висоті вашої прототипу комірок автоматично підбиратимуться під час виконання, і вам потрібно керувати інтерфейсом користувача лише в одному місці: дошці повідомлень.


2
Я опублікував відповідь з повним кодом, включаючи кешування; см stackoverflow.com/a/16881312/292166
JosephH

1
Нічого-ого-ух! Я підтримав відповідь, але будьте БУДІТНІ! Цей метод спричиняє не лише покарання за продуктивність, як говорив @Brennan у коментарях, але також спричиняє все більший розподіл пам'яті при кожному reloadData, щось на зразок витоку пам'яті! Потрібно використовувати вирішення об'єктивів вище! Витратьте день, щоб зловити цю витік пам'яті!
skywinder

Не працює в Swift, тому що cell.bounds.size.height завжди повертає 0,0
King-Wizard

1
Осередки ще не існують у той момент, коли система називала ваш tableView: heightForRowAtIndexPath метод. Ви повинні мати можливість використовувати indexPath, який вам передано, щоб проіндексувати у вашій моделі даних і подивитися, яка саме клітина буде використовуватися там, а потім обчислити висоту для цієї комірки та повернути її. Це дає змогу системі викладати комірки в таблиці до того, як створить будь-які комірки.
Король-Чарівник

1
Крім того, ви не повинні викликати власний метод CellForRowAtIndexPath. У представленнях таблиць є метод cellForRowAtIndexPath, який повертає комірку для цього шляху індексу, якщо вона наразі видно на екрані, але часто цей шлях індексу не пов’язаний з нею.
Король-Чарівник

22

Я створив код, на який натякають різні відповіді / коментарі, так що це працює для мов, які використовують комірки прототипу.

Цей код:

  • Не вимагає, щоб висота комірки була встановлена ​​деінде, окрім очевидного місця в розгортці
  • Кешує висоту з міркувань продуктивності
  • Використовує загальну функцію для отримання ідентифікатора комірки для шляху індексу, щоб уникнути дублювання логіки

Завдяки Answerbot, Brennan та lensovet.

- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = nil;

    switch (indexPath.section)
    {
        case 0:
            cellIdentifier = @"ArtworkCell";
            break;
         <... and so on ...>
    }

    return cellIdentifier;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
    static NSMutableDictionary *heightCache;
    if (!heightCache)
        heightCache = [[NSMutableDictionary alloc] init];
    NSNumber *cachedHeight = heightCache[cellIdentifier];
    if (cachedHeight)
        return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    <... configure cell as usual...>

Я знаю, що це стара відповідь, але чи хтось ще виявить, що це призводить до переповнення стека? Коли перегляд завантажується, я отримую UISectionRowData refreshWithSection: tableViewRowData: який викликає tableView: heightForRowAtIndexPath: який викликає dequeueReusableCellWithIdentifier: який викликає [UISectionRowData ...], тому у мене є рекурсивний переповнення стека. Я дуже хотів використати це рішення, але це, здається, не працює з iOS7.
sbaker

Не працює в Swift, тому що cell.bounds.size.height завжди повертає 0,0
King-Wizard

Осередки ще не існують у той момент, коли система називала ваш tableView: heightForRowAtIndexPath метод. Ви повинні мати можливість використовувати indexPath, який вам передано, щоб проіндексувати у вашій моделі даних і подивитися, яка саме клітина буде використовуватися там, а потім обчислити висоту для цієї комірки та повернути її. Це дає змогу системі викладати комірки в таблиці до того, як створить будь-які комірки.
King-Wizard

Крім того, ви не повинні викликати власний метод CellForRowAtIndexPath. У представленнях таблиць є метод cellForRowAtIndexPath, який повертає комірку для цього шляху індексу, якщо вона наразі видно на екрані, але часто цей шлях індексу не пов'язаний з нею.
King-Wizard

@ snow-tiger Я не пробував цього швидко, але я не розумію ваших коментарів. Я не "викликаю [власний] власний метод CellForRowAtIndexPath", і навмисно, що я цього не роблю. Я також знаю, що клітинки не існують у таблиці timeView: heightForRowAtIndexPath викликається, тобто вся суть цього коду, і чому він використовує dequeueReusableCellWithIdentifier для отримання комірки. Код, розміщений у цій відповіді, працює. Або відбувається щось додаткове в швидкому переході, щось не в порядку у швидкому перетворенні, або намагаються вирішити іншу проблему, на яку це питання / відповідь націлено.
JosephH

19

Насправді є два місця, де потрібно змінити висоту рядка, спочатку клітинку (ви вже це змінили), а тепер виберіть Табличний вигляд і перевірте інспектор розмірів


in tableview (not cellview)> вкладка інспектора розмірів> висота рядка
iman kazemayni

Кожен раз, коли я забуваю цю деталь, ганяє мене. Не маю уявлення, чому коригування комірки не оновлює tableView автоматично при використанні розкадров!
Скутер

11

Я думаю, що це помилка.

Спробуйте відрегулювати висоту не інспектором утиліти, а безпосередньо перетягуванням миші на аркуші розкадровки.

Я вирішив цю проблему цим методом.


10

Якщо ви користуєтеся швидким, використовуйте так. Не використовуйте табло для вибору висоти рядка. Програмно встановити висоту рядка таблиці таким чином,

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 0 || indexPath.row == 1{
        let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
        self.tableView.rowHeight = 150
        cell.label1.text = "hiiiiii"
        cell.label2.text = "Huiiilllllll"
        return cell

    } else {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
        self.tableView.rowHeight = 60
        cell.label3.text = "llll"
        return cell
    }

}

Це працює, але в більш загальному випадку ви можете зробити:cell.sizeToFit(); self.tableView.rowHeight = cell.frame.height
Енді Чоу

7

Ви можете отримати висоту UITableviewCell (в UITableviewController - статичні комірки) з таблички розкадрів за допомогою наступних рядків.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}

6

Відкрийте дошку розкадрування у вікні XML і спробуйте відредагувати rowHeightатрибут шуканого елемента.

Це працювало для мене, коли я намагався встановити користувальницький rowHeight для мого прототипу рядка. Це не працює через інспектора, але через XML це працює.


1
Я натиснув правою кнопкою миші та вибрав "відкрити як" -> "вихідний код". У rowHeight вже було встановлено 120. Я вважаю, що в раскадровці є помилка, і вона ігнорує власну висоту комірок.
zirinisp

6

Ви можете використовувати прототип cellsіз користувацьким способом height, а потім викликати cellForRowAtIndexPath:та повертати його frame.height.:.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}

Додавання цього методу спрацювало дуже добре, і тепер зберігає всі налаштування на дошці розкадрувань, як належить.
даспіаніст

На сьогодні найкраще рішення
TheJeff

4

Якщо ви хочете встановити статичну висоту рядка, ви можете зробити щось подібне:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}

4

Я останнім часом вела боротьбу з цим. Моя проблема полягала в тому, що рішення, розміщені вище за допомогою heightForRowAtIndexPath:методу, працювали б для iOS 7.1 в Simulator, але потім повністю перекрутили результати, просто перейшовши на iOS 8.1.

Я почав читати докладніше про саморозміри клітинок (представлений в iOS 8, читайте тут ). Очевидно, що використання UITableViewAutomaticDimensioni допоможе в iOS 8. Я спробував використовувати цю техніку і видалив використання heightForRowAtIndexPath:та вуаля, він працював ідеально в iOS 8 зараз. Але тоді iOS 7 не був. Що я мав робити? Мені потрібно heightForRowAtIndexPath:для iOS 7, а не для iOS 8.

Ось моє рішення (підстрижене заради стислості), яке запозичено у відповіді @JosephH, розміщеній вище:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 50.;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

    // ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
        return UITableViewAutomaticDimension;

    } else {
        NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
        static NSMutableDictionary *heightCache;
        if (!heightCache)
            heightCache = [[NSMutableDictionary alloc] init];
        NSNumber *cachedHeight = heightCache[cellIdentifier];
        if (cachedHeight)
            return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
    }
}

- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
    NSString * reuseIdentifier;
    switch (indexPath.row) {
        case 0:
            reuseIdentifier = EventTitleCellIdentifier;
            break;
        case 2:
            reuseIdentifier = EventDateTimeCellIdentifier;
            break;
        case 4:
            reuseIdentifier = EventContactsCellIdentifier;
            break;
        case 6:
            reuseIdentifier = EventLocationCellIdentifier;
            break;
        case 8:
            reuseIdentifier = NotesCellIdentifier;
            break;
        default:
            reuseIdentifier = SeparatorCellIdentifier;
            break;
    }

    return reuseIdentifier;
}

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO (@ "8.0") насправді є набором макрозначень, які я використовую, які я десь знайшов (дуже корисно). Вони визначаються як:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

2

Така ж проблема виникла під час роботи на XCode 9 за допомогою Swift 4 .

Додати AutoLayout для елементів інтерфейсу всередині комірки та власна висота рядка комірок буде працювати відповідно до вказаних.


1
Привіт, будь ласка, як ти це зробив?
Назад Пакер

Вам просто потрібно додати обмеження, встановлене в нижній частині комірки.
Джастін

Коли я це роблю і вибираю "автоматичний" на дошці розкадрування для висоти комірки, він хоче встановити всі висоти до 44 у розгортці, хоча це здається правильним при запуску. Як я можу змусити графічне відображення правильно відображатись?
Девід

1

Для динамічних комірок rowHeight, встановлений на UITableView, завжди переосмислює "rowHeight" окремих комірок. Просто обчисліть динамічну висоту, якщо вміст всередині рядка.


0

Єдине справжнє рішення, яке я міг знайти, це таке

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
    return cell.frame.size.height;
}

Це працює і дозволяє не мати жахливого перемикача / якщо дублювати логіку вже в StoryBoard. Не впевнений у продуктивності, але я гадаю, що при надходженні в cellForRow:осередок, який вже є ініталізованим, це так само швидко. Звичайно, тут, мабуть, є пошкодження застави, але, схоже, це тут добре працює для мене.

Я також розмістив це тут: https://devforums.apple.com/message/772464

EDIT: Ортвін Генц нагадав мені, що heightForRowAtIndexPath:буде викликано всі клітини TableView, не лише видимі. Звучить логічно, оскільки iOS повинен знати загальну висоту, щоб мати змогу показувати потрібні смуги прокрутки. Це означає, що, мабуть, добре на маленьких TableView (наприклад, 20 комірок), але забудьте про це на 1000 Cell TableView.

Також попередній трюк з XML: Те саме, що перший коментар для мене. Правильне значення вже було.


0

Додано як коментар, але публікація як відповідь для наочності:

Здається, також існує проблема, якщо ви спочатку встановите подання таблиці як "статичні комірки", а потім заміните його на "динамічні прототипи". У мене виникла проблема, коли навіть метод делегата для heightForRowAtIndexPathігнорування. Я спершу вирішив це, безпосередньо редагуючи XML-майданчик, а потім, нарешті, просто відновив сцену розгортки з нуля, використовуючи динамічні прототипи з самого початку.


0

З огляду на те, що я не знайшов жодного рішення цієї проблеми через Interface Builder, я вирішив опублікувати програмне рішення проблеми в Swift за допомогою двох динамічних комірок , навіть незважаючи на те, що в початковому запитанні було запропоновано рішення через Interface Builder. Незалежно від того, я думаю, це може бути корисним для спільноти переповнення стека:

    import UIKit

    enum SignInUpMenuTableViewControllerCellIdentifier: String {
       case BigButtonCell = "BigButtonCell"
       case LabelCell = "LabelCell"
    }

    class SignInUpMenuTableViewController: UITableViewController {
            let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
                              SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]

    private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
        if indexPath.row == 2 {
            return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
        } else {
            return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
        }
    }

   override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
   }

   ...

  }

Це все добре і добре, але якщо я неправильно читаю код, він просто покладається на магічні числа і повністю ігнорує будь-яке значення, яке ви встановили в IB для динамічних комірок, так що ... не зовсім вирішення питання ОП
Денні

0

Ще одне, що ви можете зробити - це перейти до «Структура документа» і вибрати таблицю перегляду, що ваша комірка-прототип вкладена. Потім в Інспекторі розмірів змініть висоту рядка подання таблиці на потрібне значення та зніміть прапорець Автоматичне поле.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.