2016-05-15 2 views
1

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

enter image description here

От чтения сотни сообщений SO, сотни блогов, обезжиривания сайты для разработчиков Apple, там, кажется, неограниченное количество способов написать это. После того, как я экспериментировал с сотнями разных способов, я до сих пор не могу отобразить текст так. Я думаю, что некоторые проблемы возникают из-за того, что я использую различные варианты 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 
} 

Который производит это:

enter image description here

+0

Почему вы не создаете собственный подкласс и не устанавливаете ограничения размещения там? – ozgur

+0

Возможно, однажды я настроен и хочу СУХОЙ код. – Trip

+0

Почему вы используете stackview? Чтобы реализовать многострочную метку или вы планируете добавить больше вертикального представления под многострочной меткой? – BangOperator

ответ

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.

Редактировать

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

Попробуйте заменить код в 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.

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

+0

Я использую 'tableView.estimatedRowHeight = 200; tableView.rowHeight = UITableViewAutomaticDimension', но на основе того, что вы говорите. Возможно, я не должен этого делать и вычислять каждую ячейку вручную в 'heightForRowAtIndexPath' ..? – Trip

+0

Это то, что я сделал в прошлом. –

+0

А я вижу, что ты там или там. Я .. Пробовал все это. Ничто не работает. : D – Trip

1

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

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

+0

Поскольку я - 3 различных UITableView Cells, каждый из которых имеет совершенно разные требования к высоте, мне определенно нужно было бы вычислить во время выполнения. Как кто-то может вычислить высоту ячейки во время выполнения? – Trip

+0

Я думаю, что большая проблема в том, что в iOS7 и iOS8 есть ошибка, в которой они не распознают intrinsicContentSize многострочного UILabel .. как описано здесь (http://stackoverflow.com/questions/17491376/ios-autolayout -multi-line-uilabel), но ни один из этих ответов не работает. – Trip

+0

Самый простой способ сделать это - переместить код, который устанавливает метки ячеек в новый метод, а затем в heightForRowAtIndex вызовет метод, который устанавливает ячейку, затем вы можете вызвать cell.contentView.systemLayoutSizeFittingSize (UILayoutFittingCompressedSize) – AdamM

1

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

Шаг1: набор высота оценка для просмотра таблицы tableView.estimatedRowHeight = 33,0 Шаг 2: установить высоту строки Tableview к UITableViewAutomaticDimension tableView.rowHeight = UITableViewAutomaticDimension

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

+0

У меня есть все это в моем существующем коде. Ячейки UIStackView и UITableView не соблюдают или не распознают intrinsicContentSize многострочного UILabel – Trip

2

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

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

UITableview cell Autoresize According to textsize

Выход: -

enter image description here

В viewdidload

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

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

enter image description here

Edit: - Если вам нужно шаг за шагом руководство о том, как установить принуждать к UILabel,

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

Adjust UILabel height depending on the text

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

enter image description here

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

Этикетки 2: - верхней, нижней, ведущий от ярлыка 1, Продольной от SuperView

+0

. Спасибо за подробный ответ. Ссылка и прикрепленные файлы имеют сбой в них, что предотвращает его запуск. Я попробовал это первоначально без UIStackView и в настоящее время имею все эти параметры в моей 'viewDidLoad', но они тоже не работают. – Trip

+0

@Trip вам нужно установить правильное ограничение. вы проверяете мою вторую ссылку? step bt step ограничивает UILabel? –

+0

Какие ограничения мне не хватает? По моему опыту, любое ограничение, заданное шириной, высотой, ведущим, конечным, верхним, нижним, игнорируется в contentView, ячейке и любом из ее подзонов. Может, я что-то упустил? – Trip

1

Подход i будет следующий:

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

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

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

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

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

simple dynamic cell height based on what ever image height and what ever image length

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

Наиболее важная настройка ограничения для просмотра контейнера сказать (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's 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]; 
} 

пару вещей я не использовать в выше ПОДХОД:

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

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

+0

Спасибо за подробный ответ. Мой вопрос задает вопрос о выравнивании двух UILabels, один с динамической высотой. У вас строго о динамической высоте. У Mine есть 3 отдельных CellIdentifier, которые, вероятно, приведут к этой проблеме. Ваш использует только один. – Trip

0
- (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; 
} 
+0

Может ли ваш ответ использовать MarkDown? – Trip

1

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

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

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

  1. Высокопоставленное ограничение из вашего содержимого ячейки (т.е. ваших многострочных этикеток) в верхнюю части представления содержимого ячейки
  2. Ведущего ограничения с наклейки однострочной слева клетка
  3. Опущенного ограничение от вашей этикетки многострочного в правую части ячейки
  4. дна ограничения из нижней части этикетки многострочных к нижней части клетки

Я думаю, вы пропустили точку 4.

Редактировать

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

enter image description here

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

enter image description here

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

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

  1. tableView.rowHeight = UITableViewAutomaticDimension
  2. tableView.estimatedRowHeight = 100
  3. Содержимое ячейки должны иметь все четыре ограничения (ведущие, замыкающие, верхний и нижний), чтобы определить высоту ячейки ,
+0

Да, ты совершенно прав. Единственная причина, по которой я хотел получить UIStackView, - это то, что это единственный способ, который я могу придумать, чтобы выровнять два UILabels с их верхними базовыми линиями. Можете ли вы придумать какой-либо другой способ сделать это? – Trip

+0

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

1

Это очень просто. Вы можете сделать шаг за шагом.

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

. Установите свойство rowHeight tableview как UITableViewAutomaticDimension.and не используйте heightForRowAtIndexPath.

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

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

+0

Слово. Решил отказаться от использования stackView. Добавление верхних и нижних ограничений. У меня уже установлен автоматический размер. – Trip

1

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

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

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

1

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

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

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

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

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

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

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

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

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

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

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

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

1

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

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

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

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

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

Так полные шаги:

  1. Создайте подкласс UILabel.
  2. Создайте ячейку с вашими ярлыками, расположенными без UIStackViews.
  3. Установите количество строк в 0 для одной или обеих меток в зависимости от вашей учетной записи.
  4. Установите ярлыки типа вашего подкласса.
  5. Внесите метод estimatedHeightForRowAtIndexPath, чтобы угадать, какова высота.
  6. Рассчитайте высоту ячейки внутри 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 
    } 
} 

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

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