Возможно ли иметь разную высоту в ячейке UITableView, когда я использую несколько разных способов отображения ячейки?

Я потратил несколько дней, пытаясь понять это, но, похоже, не существует решения. У меня очень простая ячейка UITableView с двумя ярлыками. Одна из них будет одной строкой, вторая будет многострочной. Второй будет отличаться по высоте. Вот пример того, что я пытаюсь произвести (UIStackViews внутри UITableViewCells):

введите описание изображения здесь

Отчитав сотни сообщений SO, сотни блогов, чистящих сайты Apple Developer, кажется, существует неограниченное количество способов написать это. После того, как я экспериментировал с сотнями разных способов, я до сих пор не могу отобразить текст так. Я думаю, что некоторые проблемы связаны с тем, что я использую 3 различные изменения ячейки UITableView в одном UITableView.

Вот мой код из моей последней попытки cellForRowAtIndexPath:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell : UITableViewCell!

    let (parent, isParentCell) = self.findParent(indexPath.row)

    if !isParentCell {

        let categories = ["words", "translation","commentary"]

        if categories[parent] == "words" {

            cell = tableView.dequeueReusableCellWithIdentifier(childWordsCellIdentifier, forIndexPath: indexPath) as UITableViewCell

            // Reset content
            for subview in cell.contentView.subviews {
                subview.removeFromSuperview()
            }
            cell.prepareForReuse()


            let words                   = self.page.valueForKey("words")!.allObjects as! [Word]
            let wordsInOrder            = words.sort({Int($0.order!) < Int($1.order!) })
            let word                    = wordsInOrder[indexPath.row - 1]

            let labelWidth              = (self.view.frame.width - 80) / 2


            let wordLabel               = UILabel(frame: CGRectZero)
            wordLabel.text              = word.valueForKey("sanskrit") as? String
            wordLabel.font              = UIFont(name: "EuphemiaUCAS-Bold", size: 16)
            wordLabel.numberOfLines     = 0
            wordLabel.translatesAutoresizingMaskIntoConstraints = false
            wordLabel.layer.borderColor = UIColor.greenColor().CGColor
            wordLabel.layer.borderWidth = 1.0
            let widthWordConstraint = wordLabel.widthAnchor.constraintEqualToConstant(labelWidth)
            widthWordConstraint.priority = 300
            widthWordConstraint.active = true

            let englishWordLabel           = UILabel(frame: CGRectZero)
            englishWordLabel.text          = "Foobar don't want to play my game with my anymore."
            englishWordLabel.font          = UIFont(name: "STHeitiTC-Light", size: 16)
            englishWordLabel.numberOfLines = 0
            englishWordLabel.preferredMaxLayoutWidth = labelWidth
            englishWordLabel.translatesAutoresizingMaskIntoConstraints = false
            let englishWordConstraint = englishWordLabel.widthAnchor.constraintEqualToConstant(labelWidth)
            englishWordConstraint.priority = 300
            englishWordConstraint.active = true
            englishWordLabel.layer.borderColor = UIColor.blueColor().CGColor
            englishWordLabel.layer.borderWidth = 1.0

            let stackView = UIStackView()
            stackView.axis = .Horizontal
            stackView.distribution = .FillProportionally
            stackView.alignment = .FirstBaseline
            stackView.spacing = 15
            stackView.layoutMargins = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
            stackView.layoutMarginsRelativeArrangement = true

            stackView.addArrangedSubview(wordLabel)
            stackView.addArrangedSubview(englishWordLabel)

            stackView.translatesAutoresizingMaskIntoConstraints = false

            englishWordLabel.topAnchor.constraintEqualToAnchor(stackView.topAnchor).active = true
            englishWordLabel.bottomAnchor.constraintEqualToAnchor(stackView.bottomAnchor).active = true


            cell.contentView.addSubview(stackView)

            cell.contentView.layoutIfNeeded()


        } else {

            cell = tableView.dequeueReusableCellWithIdentifier(childCellIdentifier, forIndexPath: indexPath) as UITableViewCell

            // Reset content
            cell.textLabel!.text = ""
            for subview in cell.contentView.subviews {
                subview.removeFromSuperview()
            }
            cell.prepareForReuse()

            cell.textLabel!.text        = self.page.valueForKey(categories[parent]) as? String
            cell.textLabel!.textColor   = UIColor(red: 35/255.0, green: 31/255.0, blue: 32/255.0, alpha: 1.0)
            cell.textLabel!.font        = UIFont(name: "STHeitiTC-Light", size: 16)
        }
    }
    else {
        // Parent
        cell = tableView.dequeueReusableCellWithIdentifier(parentCellIdentifier, forIndexPath: indexPath)
        cell.textLabel!.text        = self.dataSource[parent].title
        cell.textLabel!.textColor   = UIColor(red: 66/255.0, green: 116/255.0, blue: 185/255.0, alpha: 1.0)
        cell.textLabel!.font        = UIFont(name: "STHeitiTC-Light", size: 20)
    }

    cell.selectionStyle                                       = .None
    cell.textLabel!.translatesAutoresizingMaskIntoConstraints = false
    cell.textLabel!.numberOfLines                             = 0
    cell.textLabel!.lineBreakMode = .ByWordWrapping

    return cell
}

Что производит это:

введите описание изображения здесь

Ответы

Ответ 1

Высота ячейки представления таблицы определяется таблицей на основе свойства rowHeight или возвращаемого значения optional func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat из делегата представления таблицы.

Высота, которая может быть задана программистом для UITableViewCell через его свойство кадра, игнорируется!

Следовательно, вам необходимо определить желаемую высоту каждой ячейки программно. Затем вам нужно реализовать optional func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat из делегата представления таблицы для каждой из ячеек.

Если размер ячейки изменяется при отображении представления таблицы, вам необходимо либо:

  • перезагрузите таблицу с помощью reloadData() из UITableView или
  • обновите ячейку с помощью func reloadRowsAtIndexPaths(_ indexPaths: [NSIndexPath], withRowAnimation animation: UITableViewRowAnimation) от UITableView.

Edit

Фактически, поскольку вы используете ограничения в своем представлении, он должен работать без использования ``.

Попробуйте заменить код if categories[parent] == "words" { .. } на:

        cell = tableView.dequeueReusableCellWithIdentifier(childWordsCellIdentifier, forIndexPath: indexPath) as UITableViewCell

        // Reset content
        for subview in cell.contentView.subviews {
            subview.removeFromSuperview()
        }
        cell.prepareForReuse()


        let words                   = self.page.valueForKey("words")!.allObjects as! [Word]
        let wordsInOrder            = words.sort({Int($0.order!) < Int($1.order!) })
        let word                    = wordsInOrder[indexPath.row - 1]


        let wordLabel               = UILabel(frame: CGRectZero)
        wordLabel.text              = word.valueForKey("sanskrit") as? String
        wordLabel.font              = UIFont(name: "EuphemiaUCAS-Bold", size: 16)
        wordLabel.numberOfLines     = 0
        wordLabel.translatesAutoresizingMaskIntoConstraints = false
        wordLabel.layer.borderColor = UIColor.greenColor().CGColor
        wordLabel.layer.borderWidth = 1.0

        let englishWordLabel           = UILabel(frame: CGRectZero)
        englishWordLabel.text          = "Foobar don't want to play my game with my anymore."
        englishWordLabel.font          = UIFont(name: "STHeitiTC-Light", size: 16)
        englishWordLabel.numberOfLines = 0

        let stackView = UIStackView()
        stackView.axis = .Horizontal
        stackView.distribution = .FillProportionally
        stackView.alignment = .Fill  // EDIT
        stackView.spacing = 15
        stackView.layoutMargins = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
        stackView.layoutMarginsRelativeArrangement = true

        stackView.addArrangedSubview(wordLabel)
        stackView.addArrangedSubview(englishWordLabel)

        stackView.translatesAutoresizingMaskIntoConstraints = false

        cell.contentView.addSubview(stackView)
        cell.contentView.leadingAnchor.constraintEqualToAnchor(stackView.leadingAnchor).active = true
        cell.contentView.topAnchor.constraintEqualToAnchor(stackView.topAnchor).active = true
        cell.contentView.trailingAnchor.constraintEqualToAnchor(stackView.trailingAnchor).active = true
        cell.contentView.bottomAnchor.constraintEqualToAnchor(stackView.bottomAnchor).active = true

        cell.contentView.layoutIfNeeded()

Также я бы использовал для разных классов ячеек для этой задачи, а не для удаления представлений в ContentView.

Пожалуйста, дайте мне знать, как это происходит!

Ответ 2

Я предлагаю вам не использовать представление стека для этого. Просто возьмите пользовательскую ячейку с ярлыком в соответствии с вашим требованием, и ячейка автоматически изменит размер в соответствии с размером текста метки.

Проверьте, здесь я приложил демо.

UITableview cell Autoresize В соответствии с текстом

Выход: -

введите описание изображения здесь

В viewdidload

super.viewDidLoad()
        self.tblView.estimatedRowHeight = 100;
        self.tblView.rowHeight = UITableViewAutomaticDimension;
        self.tblView.setNeedsLayout()
        self.tblView.layoutIfNeeded()

Не забудьте установить свойство Numberoflines=0 свойства UILabel.

введите описание изображения здесь

Изменить: - Если вам требуется пошаговое руководство относительно того, как установить ограничение на UILabel,

проверьте эту ссылку,

Отрегулируйте высоту UILabel в зависимости от текста

Изменить: - Здесь у меня есть 2 ярлыка в ячейке в соответствии с вашим изображением выше. Просто установите ограничение таким образом.

введите описание изображения здесь

Метка 1: - Верх, Ведущий, (Высота и ширина согласно вашему требованию)

Ярлык 2: - Верх, нижний, ведущий от метки 1, переход от Superview

Ответ 3

То, что вы хотите достичь, может быть выполнено простой реализацией heightForRowAtIndexPath из делегата tableView.

Если вы не знаете, какая ячейка должна иметь высоту, вы можете просто вычислить ее во время выполнения.

Ответ 4

Для этого вам нужно использовать ячейку просмотра таблицы размеров, т.е. сам вид таблицы вычисляет высоту, необходимую для каждой ячейки, чтобы отображать ее содержимое, которое может быть достигнуто в двух строках кода:

Шаг1: установите высоту оценки для представления таблицы tableView.estimatedRowHeight = 33.0 step2: установить tableView высоту строки в UITableViewAutomaticDimension tableView.rowHeight = UITableViewAutomaticDimension

Вот учебник для подробного описания http://www.appcoda.com/self-sizing-cells/

Ответ 5

Подход я будет следующим:

Я создам UIView SubClass как container view, который будет содержать "метку слова" и "английскую метку слова". это намного проще, отдельный код и maintanable.

Я создам подкласс ячейки и использую этот вид контейнера как subView of cell'scontent view.

Затем я использую всю эту настройку в cellForRowAtIndex.

Я также сделаю некоторую реализацию кода в heightForRow. Что касается динамической высоты строки ячейки во время выполнения, то u должен реализовать этот метод heightForRow.

Результат вывода будет примерно таким, как показано ниже, он имеет один UIImageView и два UILabel и пользовательский серосепаратор. Эта динамическая высота ячейки основана на том, что когда-либо высота изображения и какая длина строки должна отображаться в UILabel:

простая динамическая высота ячейки, основанная на том, что когда-либо высота изображения и какая длина изображения

Я поделюсь некоторым фрагментом кода для вас. Итак, здесь приведен пример концептуального кода для представления контейнера:

Наиболее важная установка ограничений для представления в контейнере (например, VenueViewContainer: UIView) выглядит следующим образом (для вашего случая вы можете создавать метки по горизонтали, а не по вертикали):

"V:|-0-[venueImage]-10-[venueName]-2-[sportName]-10-[lblSeperator(10)]",
"H:|-0-[venueImage]-0-|",
"H:|-20-[venueName]-20-|",
"H:|-20-[sportName]-20-|",
"H:|-0-[lblSeperator]-0-|",

Обязательно установите эти два свойства для своих меток:

[lbl setNumberOfLines:0];

[lbl setLineBreakMode:NSLineBreakByWordWrapping];

В вашем файле реализации VenueViewContainer создайте метод:

/*!This method is responsible for getting view dynamic height .*/

-(float)getViewHeight
{
[self layoutIfNeeded];

CGFloat maxY = 0;

for (UIView *subview in self.subviews) {

    maxY = MAX(CGRectGetMaxY(subview.frame),maxY);

}

return maxY;

}

/*!
 This method is responsible for set up Venue.
 @param venue object
 */

#pragma -mark data population

- (void)setupViewWithVenue:(Venue *)venue
{
    self.venueLabel.text = @"my venue my venue my venue my venue my venue my venue my venue my venue my venue my venue my venue my venue my venue my venue last";

    self.sportName.text = @"my sport my sport my sport my sport my sport  my sport my sport my sport my sport my sport my sport my sport my sport my sport last";

    [self.venueImage setImageWithURLString:venue.venueImageUrl defaultImage:[UIImage imageNamed:@"venueinfo_main"]];

}

Теперь поговорим о пользовательской ячейке. подкласс UITableViewCell. Реализация такая тонкая:

    @implementation VenueCellTableViewCell

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    if (self) {

        self.selectionStyle = UITableViewCellSelectionStyleNone;

        [self setUpContainer];

        [self setUpConstraints];

    }

    return self;
}

/*!
 This method is responsible for set up Container
 */

-(void)setUpContainer{

    aViewContainer = [[VenueViewContainer alloc] initWithFrame:CGRectZero];

    [aViewContainer setTranslatesAutoresizingMaskIntoConstraints:NO];

    [self.contentView addSubview:aViewContainer];

}

/*!constraints setup*/

-(void)setUpConstraints{

    /*!
     dictionary of views for autolayout
     */
    NSMutableDictionary* views;

    views = [NSMutableDictionary new];

    UIView *parentView = self.contentView;

    views[@"aViewContainer"] = aViewContainer;

    views[@"parentView"] = parentView;

    NSArray* constraints;

    NSString* format;

    /*!
     layouting horizontal
     */
    format = @"|-0-[aViewContainer]-0-|";

    constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];

    [parentView addConstraints:constraints];

    /*!
     layouting vertical
     */
    format = @"V:|-0-[aViewContainer]-0-|";

    constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:views];

    [parentView addConstraints:constraints];
}
/*!
 This method is responsible for set up venue
 @param venue object
 */

- (void)setupCellWithVenue:(Venue *)venue
{
    [aViewContainer setupViewWithVenue:venue];
}
/*!
 This method is responsible to get cell height dynamically
 @param venue object
 */

-(float)getCellHeight
{
   return [aViewContainer getViewHeight];
}

Это связано с настройкой вашей ячейки.

теперь говорят о cellForRow и heightForRow:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    VenueCellTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kVenueCellIdentifier];

    if (nil == cell) {
        cell = [[VenueCellTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
                                      reuseIdentifier:kVenueCellIdentifier];
    }

    [cell setBackgroundColor:[[AWPViewFactory sharedInstance]getColor:@"colorWhite"]];

#pragma uncomment below line as per ur need
//    Venue *venue = [_dataSourceArray objectAtIndex:indexPath.row];
    [cell setupCellWithVenue:nil];

    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
        [cell setLayoutMargins:UIEdgeInsetsZero];
    }

    return cell;
}

#pragma mark - UITableViewDelegate methods

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Use the dictionary of offscreen cells to get a cell for the reuse identifier, creating a cell and storing
    // it in the dictionary if one hasn't already been added for the reuse identifier.
    // WARNING: Don't call the table view dequeueReusableCellWithIdentifier: method here because this will result
    // in a memory leak as the cell is created but never returned from the tableView:cellForRowAtIndexPath: method!
    VenueCellTableViewCell *cell = [self.offscreenCells objectForKey:kVenueCellIdentifier];
    if (!cell) {
        cell = [[VenueCellTableViewCell alloc] init];
        [self.offscreenCells setObject:cell forKey:kVenueCellIdentifier];
    }

    // Configure the cell for this indexPath

#pragma uncomment below line as per ur need

//    Venue *venue = [_dataSourceArray objectAtIndex:indexPath.row];
    [cell setupCellWithVenue:nil];

    return [cell getCellHeight];
}

пару вещей, которые я не должен использовать в следующем aproach:

1. Нет использования автоматического вычисления высоты строки. 2.Нет использования расчетной высоты 3. Нет необходимости в ненужных updateConstraints. 4.Не используйте автоматическую максимальную ширину макета макета. 5. Нет использования systemLayoutSizeFittingSize (должен использовать, но не работать для меня, я не знаю, что он делает изнутри), но вместо этого мой метод - (float) getViewHeight работает, и я знаю, что он делает внутри.

Я поделился с вами самыми важными блоками кода, я еще не работал над быстрым. Но основы остаются такими же. Благодаря

Ответ 6

Прежде всего, если вам не нужен UIStackView для какой-либо другой цели, о которой вы не упоминаете в своем вопросе, не используйте их. Многострочные метки и ячейки динамической высоты хорошо работают без них (не обязательно усложнять код, если они не нужны).

В iOS нет ошибок, которые перестают работать, что я знаю. Ячейки с динамическим размером отлично работают с Auto Layout, все, что вам нужно сделать, это установить правильные ограничения в ячейках и установить свойства rowHeight и estimatedRowHeight в представлении таблицы.

Наиболее вероятная причина, по которой это не работает для вас, заключается в том, что вы не поставили все необходимые ограничения в своей ячейке. Необходимые ограничения:

  • Верхнее ограничение содержимого вашей ячейки (т.е. многострочная метка) в верхней части представления содержимого ячейки
  • Ведущее ограничение от вашей однострочной метки слева от ячейки
  • Следящее ограничение на вашей многострочной метке справа от вашей ячейки
  • Нижнее ограничение от нижней части вашей многострочной метки до нижней части вашей ячейки

Я думаю, что вам не хватает точки 4.

Edit

Согласно вашим комментариям, вы используете UIStackView, чтобы выровнять верхние базовые линии между одиночными и многострочными метками. Таким образом, я понимаю, что вы хотите, чтобы ваши метки выравнивались так:

введите описание изображения здесь

Чтобы получить это поведение, вам не нужен UIStackView. Просто дайте ограничениям меток, чтобы позволить многострочной метке определять высоту ячейки. На следующем изображении показаны верхние базовые линии, выровненные между двумя метками (т.е. Первые строки каждой метки выровнены).

введите описание изображения здесь

Обратите внимание, что левому ярлыку требуется только главное и верхнее ограничение, тогда как правой метке нужен верхний, конечный и нижний, поскольку он определяет высоту ячейки.

Таким образом, для динамических ячеек таблицы требуется три вещи:

  • tableView.rowHeight = UITableViewAutomaticDimension
  • tableView.estimatedRowHeight = 100
  • Содержимое ячейки должно содержать все четыре ограничения (ведущие, конечные, верхние и нижние) для определения высоты ячейки.

Ответ 7

Это очень просто. Команды идут шаг за шагом.

1. установите значение оценочного графика таблицы. Это упрощает и ускоряет загрузку ячейки.

2. Установите свойство rowHeight таблицы view как UITableViewAutomaticDimension.и не используйте heightForRowAtIndexPath.

3.Введите все верхние и нижние ограничения для обоих ярлыков Label.its.

Позволяет рок-н-ролл нет необходимости использовать stackView

Ответ 8

В iOS 9.1 UIStackView не реализуется intrinsicContentSize:, поэтому представление таблицы не может вычислить высоту каждой ячейки, поэтому вместо этого они отображаются на предполагаемой высоте.

Итак, в идеале вы упростили бы ваш код, чтобы вы не использовали представление стека, и вы не продолжаете добавлять и удалять (и создавать и уничтожать) представления все время. Корень решения состоит в том, чтобы не использовать представление стека, хотя.

Вы можете продолжить использовать представление стека, если хотите, но вам нужно создать подкласс и реализовать intrinsicContentSize:. Ваша причина использовать представление стека не требуется, хотя вы можете настроить ограничения для соответствия первым базовым линиям.

Ответ 9

Как уже упоминалось, убедитесь, что вы разрешаете ячейкам просмотра таблицы динамически изменять размер с помощью:

tableView.estimatedRowHeight = <estimatedHeightValue>
tableView.rowHeight = UITableViewAutomaticDimension

Но вы уже упоминали, что уже делаете это.

Остальная часть проблемы - это случай недостающих ограничений. Вы уже сказали автоопределению, что хотите, чтобы ваш многострочный ярлык соответствовал верхней и нижней части представления стека, как в следующем коде:

englishWordLabel.topAnchor.constraintEqualToAnchor(stackView.topAnchor).active = true
englishWordLabel.bottomAnchor.constraintEqualToAnchor(stackView.bottomAnchor).active = true

Но вы не упомянули для автоопределения, как это представление стека связано с представлением содержимого ячейки (его супервизор). Это необходимо для динамически размерных ячеек, поскольку согласно Apple:

Чтобы определить высоту ячеек, вам нужна непрерывная цепочка ограничений и представлений (с определенными высотами), чтобы заполнить область между верхним краем представления контента и его нижним краем. Если ваши представления имеют высоту собственного контента, система использует эти значения. Если нет, вы должны добавить соответствующие ограничения по высоте, либо к представлениям, либо к самому представлению содержимого.

В ваших ярлыках есть встроенный контент, поэтому нет проблем, но для того, чтобы завершить "неразрывную цепочку", вам нужно сообщить автоопределению, что представление стека сверху и снизу должно быть равно представлению содержимого сверху и снизу, например

// stackView.superview! is the table view cell content view
stackView.topAnchor.constraintEqualToAnchor(stackView.superview!.topAnchor).active = true
stackView.bottomAnchor.constraintEqualToAnchor(stackView.superview!.bottomAnchor).active = true

Добавьте эти две строки после того, как вы добавили представление стека в представление контента, и я считаю, что вы будете в бизнесе.

FYI, даже если вы программно добавляете эти представления в свои ячейки, как и вы, вы все же можете визуально отлаживать проблемы с макетами довольно хорошо с помощью Xcode awesome Capture View Hierarchy. Пока ваше приложение запускается из Xcode, щелкните пункт меню Debug > View Debugging > Capture View Hierarchy. Очень легко понять, что происходит в вашей иерархии взглядов, какие ограничения активны, где исчезли ваши просмотры и т.д.

2-й FYI, уничтожая представления и затем восстанавливая новые, каждый раз, когда ячейка появляется на экране, значительно ухудшается производительность при прокрутке. Насколько это возможно, вы захотите использовать существующие представления из выделенных ячеек и переназначить их содержимое соответствующим содержимым для этой строки (и, таким образом, избежать создания экземпляра). Вы все еще можете сделать это, используя свой чисто программный способ делать вещи, выгружая ячейку и вызывая cell.viewWithTag для каждого возможного вида. Если метод возвращает nil, вы выполняете одноразовое создание представления для ячейки и даете тегу вида (скажем, 1 для wordLabel и 2 для englishWordLabel). Затем назначьте правильное содержимое строки для представления.

Ответ 10

У меня были очень похожие проблемы с autoLayout снова и снова. Я не использую stackViews много, я обычно использую их, когда у меня есть требование добавить/удалить или показать/скрыть представление. Когда я не делаю этого, я предпочитаю использовать ограничения. Я чувствую, что стоп-шоу довольно затруднительно в довольно многих обстоятельствах. Особенно в xib. Я не знаю, почему это имеет значение, но, похоже, всегда вызывает предупреждения, которые я не могу удалить при использовании более 1 метки.

Это говорит о том, что autoLayout тоже не без проблем, и все они в основном сосредоточены вокруг preferredMaxLayoutWidth.

Чтобы объяснить, для того, чтобы AutouLayout вычислил высоту метки, ему нужно знать, какой шириной может быть метка. Когда у вас есть несколько ярлыков вместе, особенно в tableViewCell, это вызывает всевозможные проблемы.

Я спросил и впоследствии ответил на соответствующий вопрос здесь несколько дней спустя.

Что я сделал, добавлен подкласс UILabel, который всегда гарантирует, что preferredMaxLayoutWidth обновляется всякий раз, когда метка изменена. Я недавно обновил его для iOS 8, iOS 9 и отдельную проблему, которую я нашел с модальными представлениями.

Итак, полные шаги:

  • Создайте подкласс UIlabel.
  • Создайте ячейку с вашими ярлыками, расположенными без UIStackViews.
  • Задайте количество строк в 0 для одной или обеих меток в зависимости от вашей учетной записи.
  • Установите ярлыки типа вашего подкласса.
  • Внедрите метод estimatedHeightForRowAtIndexPath, чтобы угадать, какова высота.
  • Вычислить высоту ячейки внутри heightForRowAtIndexPath.


Чтобы вычислить высоту, вы можете использовать что-то вроде этого (которое я отвлек на вспомогательный метод, который я могу использовать повторно)

// Set the cell data first, i.e. the label text, any programmatic  fonts, font sizes etc.


if let tempCell = cell as? UITableViewCell
{
    tempCell.width = tableView.width

    let size = tempCell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

    if tableView.separatorStyle != UITableViewCellSeparatorStyle.None
    {
        // +0.5 for seperator
        return size.height+0.5
    }
    else
    {
        return size.height
    }
}

Я объединил это с протоколом, который заставляет все ячейки использовать словарь для установки своих данных. Затем я могу завершить этот метод, чтобы взять и передать в словаре и повторно использовать код снова и снова.

Это работает без проблем для меня в течение очень долгого времени.

Ответ 11

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


    NSString *firstLable = firstLable.text;
    NSString *secondLable = SecondLable.text;



    CGSize constraint = CGSizeMake(cell.frame.size.width/2, 20000.0f);
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
    CGRect firstLableRect = [firstLable boundingRectWithSize:constraint
                       options:NSStringDrawingUsesLineFragmentOrigin
                       attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],      
                        NSParagraphStyleAttributeName: paragraphStyle.copy} context:nil];


    CGRect secondLableRect = [secondLable boundingRectWithSize:constraint
                              options:NSStringDrawingUsesLineFragmentOrigin
                              attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],                                       NSParagraphStyleAttributeName: paragraphStyle.copy}context:nil];


    float max = MAX(firstLableRect.size.height, secondLableRect.size.height) + 20;


    //20 for spacing 10 pc above and 10 pc below 


    return max ;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *[email protected]"cellIdentifier";
    UITableViewCell *cell =  [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell)
    {
        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }
    cell.selectionStyle =UITableViewCellSelectionStyleNone;



    NSString *lable1 = @"first label text";
    NSString *lable2 = @"second lable text";

    CGSize constraint = CGSizeMake(cell.frame.size.width/2-10, 20000.0f);
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
    CGRect firstLableRect = [lable1 boundingRectWithSize:constraint
                             options:NSStringDrawingUsesLineFragmentOrigin
                             attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],
                             NSParagraphStyleAttributeName: paragraphStyle.copy} context:nil];


    CGRect secondLableRect = [lable2 boundingRectWithSize:constraint
                              options:NSStringDrawingUsesLineFragmentOrigin
                              attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],                                       NSParagraphStyleAttributeName: paragraphStyle.copy}context:nil];



    UILabel *firstLable = [[UILabel alloc]initWithFrame:CGRectMake(5,10,constraint.width,firstLableRect.size.height)];
    [firstLable setLineBreakMode:NSLineBreakByWordWrapping];
    firstLable.minimumScaleFactor = 15.0f;
    [firstLable setNumberOfLines:0];
    firstLable.textAlignment = NSTextAlignmentLeft;
    [firstLable setFont:[UIFont fontWithName:@"your App font" size:16.0f]];
    [cell.contentView addSubview:firstLable];


    UILabel *secondLable = [[UILabel alloc]initWithFrame:CGRectMake(cell.frame.size.width/                       2+5,10,constraint.width,secondLableRect.size.height)];
    [secondLable setLineBreakMode:NSLineBreakByWordWrapping];
    secondLable.minimumScaleFactor = 15.0f;
    [secondLable setNumberOfLines:0];
    secondLable.textAlignment = NSTextAlignmentLeft;
    [secondLable setFont:[UIFont fontWithName:@"your App font" size:16.0f]];

    [cell.contentView addSubview:secondLable];

    return cell;
}