2015-09-28 3 views
4

У меня есть пользовательская ячейка с динамической высотой внутри XIB-файла, которая показывает сообщение с сообщением и изображением. Поскольку изображение будет загружено асинхронно из моего API, соотношение сторон изображения будет отправлено с ресурсом. Внутри метода updateConstraints будет установлено ограничение соотношения сторон с соответствующим множителем.Динамическая высота для ячеек таблицы с изображениями с асинхронной загрузкой

XIB Файл:

My XIB file

Класс клетки:

// 
// PostTableViewCell.swift 
// Lome 
// 
// Created by Tobias Feistmantl on 10/09/15. 
// Copyright (c) 2015 Tobias Feistmantl. All rights reserved. 
// 

import UIKit 
import Alamofire 

class PostTableViewCell: UITableViewCell { 

    @IBOutlet weak var userProfileImageView: TFImageView! 
    @IBOutlet weak var usersNameLabel: UILabel! 
    @IBOutlet weak var usernameLabel: UILabel! 
    @IBOutlet weak var userProfileButton: TFCellButton! 
    @IBOutlet weak var distanceLabel: UILabel! 
    @IBOutlet weak var messageLabel: UILabel! 
    @IBOutlet weak var postImageView: UIImageView! 
    @IBOutlet weak var likeCountLabel: UILabel! 
    @IBOutlet weak var timestampLabel: UILabel! 
    @IBOutlet weak var likeButton: UIButton! 

    @IBOutlet weak var constraintBetweenMessageLabelAndPostImageView: NSLayoutConstraint! 

    var post: Post! { 
     didSet { 
      post.author.profileImage(version: .Thumbnail) { image, _ in 
       self.userProfileImageView.image = image 
      } 

      if let name = post.author.fullName { 
       usersNameLabel.text = name 
       usernameLabel.text = post.author.username 
      } else { 
       usersNameLabel.text = post.author.username 
       usernameLabel.hidden = true 
      } 

      if let attributedMessage = post.attributedMessage { 
       messageLabel.attributedText = attributedMessage 
       messageLabel.hidden = false 
       constraintBetweenMessageLabelAndPostImageView.constant = 15 
      } else { 
       messageLabel.hidden = true 
       messageLabel.attributedText = nil 
       constraintBetweenMessageLabelAndPostImageView.constant = 0 
      } 

      post.image { image, _ in 
       if let image = image { 
        self.postImageView.image = image 
        self.setNeedsUpdateConstraints() 
       } 
      } 

      timestampLabel.text = "Posted \(post.createdAt.timeAgoSinceNow())" 
      distanceLabel.text = post.distanceText 
      likeCountLabel.text = "\(post.likesCount) Likes" 
      likeButton.setImage(post.likeButtonImage, forState: .Normal) 
     } 
    } 

    override func updateConstraints() { 
     if let aspectRatio = post.imageAspectRatio { 
      postImageAspectConstraint = NSLayoutConstraint(item: postImageView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: postImageView, attribute: NSLayoutAttribute.Height, multiplier: CGFloat(aspectRatio), constant: 0) 
     } 

     super.updateConstraints() 
    } 

    func setupUserProfileButton(indexPath: NSIndexPath, viewController: UIViewController) { 
     userProfileButton.indexPath = indexPath 
     userProfileButton.addTarget(viewController, action: "userProfileButtonDidTouch:", forControlEvents: .TouchUpInside) 
    } 

    var postImageAspectConstraint: NSLayoutConstraint? { 
     didSet { 
      if let oldValue = oldValue { 
       postImageView.removeConstraint(oldValue) 
      } 
      if let postImageAspectConstraint = postImageAspectConstraint { 
       postImageView.addConstraint(postImageAspectConstraint) 
      } 
     } 
    } 

    override func prepareForReuse() { 
     super.prepareForReuse() 

     postImageAspectConstraint = nil 
    } 

} 

cellForRowAtIndexPath метод:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCellWithIdentifier("postCell", forIndexPath: indexPath) as! PostTableViewCell 

    cell.post = posts[indexPath.row] 
    cell.setupUserProfileButton(indexPath, viewController: self) 

    return cell 
} 

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

Broken cell

Ошибка:

2015-09-28 11:58:27.546 Lome[32812:528936] Unable to simultaneously satisfy constraints. 
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7f8a008bf6f0 V:[Lome.TFImageView:0x7f8a008bf470(35)]>", 
    "<NSLayoutConstraint:0x7f89f9fbc490 V:|-(15)-[Lome.TFCellButton:0x7f8a0087fde0] (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a00831520 Lome.TFCellButton:0x7f8a0087fde0.top == Lome.TFImageView:0x7f8a008bf470.top>", 
    "<NSLayoutConstraint:0x7f8a008315c0 Lome.TFCellButton:0x7f8a0087fde0.bottom == Lome.TFImageView:0x7f8a008bf470.bottom>", 
    "<NSLayoutConstraint:0x7f8a00831750 V:[Lome.TFCellButton:0x7f8a0087fde0]-(18)-[UILabel:0x7f8a008806d0'Water']>", 
    "<NSLayoutConstraint:0x7f8a00831840 H:|-(0)-[UIImageView:0x7f8a00830910] (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a00831890 H:[UIImageView:0x7f8a00830910]-(0)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a008318e0 V:[UILabel:0x7f8a008806d0'Water']-(15)-[UIImageView:0x7f8a00830910]>", 
    "<NSLayoutConstraint:0x7f8a00831930 V:[UIImageView:0x7f8a00830910]-(20)-[UILabel:0x7f8a00830b90'0 Likes']>", 
    "<NSLayoutConstraint:0x7f8a00831980 V:[UILabel:0x7f8a00830b90'0 Likes']-(20)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a00860870 UIImageView:0x7f8a00830910.width == 0.6672*UIImageView:0x7f8a00830910.height>", 
    "<NSLayoutConstraint:0x7f8a0084e990 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8a008bf270(611)]>", 
    "<NSLayoutConstraint:0x7f8a0084f930 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7f8a008bf270(375)]>" 
) 

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f8a008bf6f0 V:[Lome.TFImageView:0x7f8a008bf470(35)]> 

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. 
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. 
2015-09-28 11:58:27.547 Lome[32812:528936] Unable to simultaneously satisfy constraints. 
    Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7f89f9fbc490 V:|-(15)-[Lome.TFCellButton:0x7f8a0087fde0] (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a00831520 Lome.TFCellButton:0x7f8a0087fde0.top == Lome.TFImageView:0x7f8a008bf470.top>", 
    "<NSLayoutConstraint:0x7f8a008315c0 Lome.TFCellButton:0x7f8a0087fde0.bottom == Lome.TFImageView:0x7f8a008bf470.bottom>", 
    "<NSLayoutConstraint:0x7f8a00831750 V:[Lome.TFCellButton:0x7f8a0087fde0]-(18)-[UILabel:0x7f8a008806d0'Water']>", 
    "<NSLayoutConstraint:0x7f8a00831840 H:|-(0)-[UIImageView:0x7f8a00830910] (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a00831890 H:[UIImageView:0x7f8a00830910]-(0)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a008318e0 V:[UILabel:0x7f8a008806d0'Water']-(15)-[UIImageView:0x7f8a00830910]>", 
    "<NSLayoutConstraint:0x7f8a00831930 V:[UIImageView:0x7f8a00830910]-(20)-[UILabel:0x7f8a00830b90'0 Likes']>", 
    "<NSLayoutConstraint:0x7f8a00831980 V:[UILabel:0x7f8a00830b90'0 Likes']-(20)-| (Names: '|':UITableViewCellContentView:0x7f8a008bf270)>", 
    "<NSLayoutConstraint:0x7f8a00860870 UIImageView:0x7f8a00830910.width == 0.6672*UIImageView:0x7f8a00830910.height>", 
    "<NSLayoutConstraint:0x7f8a0084e990 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f8a008bf270(611)]>", 
    "<NSLayoutConstraint:0x7f8a0084f930 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7f8a008bf270(375)]>" 
) 

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f8a00860870 UIImageView:0x7f8a00830910.width == 0.6672*UIImageView:0x7f8a00830910.height> 

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. 
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. 

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

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

Надеюсь, у кого-то есть решение.

Заранее спасибо.

+0

Можете ли вы попытаться установить высоту изображения, а не ширину в 'updateConstraints:'. С первого взгляда это кажется неоднозначной ситуацией, поскольку вы уже привязали «ImageView» с горизонтальными макетами с интервалом 0 и затем пытались изменить ширину по высоте. – Gandalf

+0

Это ограничение отношения к формату, а не ограничение ширины. Высота UIImageView в 0.6672 раза больше ширины. Однако, если я устанавливаю фиксированную высоту в IB и не добавляю это ограничение соотношения сторон, это работает, но у меня всегда одинаковая высота и ложное соотношение сторон, потому что каждое изображение отличается. – Tobias

+1

Я знаю, что вы применили ограничение соотношения сторон. Я думаю, вы неправильно поняли, о чем я говорю. В вашем аспекте ограничения ration, 'first item' является' width'. Это означает, что ограничение будет пытаться внести изменения в 'width' не в' height' этого представления. Поэтому, если вы отмените первый и второй элементы от него и измените соотношение сторон в аргументе множителя, у вас будет такое же ограничение, но с разной высотой в соответствии с соотношением сторон изображения. – Gandalf

ответ

1

Эта проблема вызвана 2 конфликтующих ограничений, применяемых к ImageView. Если вы посмотрите на вывод отладчика

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f8a00860870 UIImageView:0x7f8a00830910.width == 0.6672*UIImageView:0x7f8a00830910.height> 

У вас уже есть горизонтальное ограничение на ImageView возлагали к superview с 0 интервалом.

Теперь при обновлении соотношения сторон ограничения вы пытаетесь установить width (сохраняя ширину в качестве первого пункта) в ImageView как отношение этого height, что приведет к конфликту с это ведущим/Скользящим ограничением. Вам необходимо установить высоту этого ImageView, заменив первый и второй элементы и инвертируя коэффициент соотношения сторон.

postImageAspectConstraint = NSLayoutConstraint(item: postImageView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: postImageView, attribute: NSLayoutAttribute.Width, multiplier: 1/CGFloat(aspectRatio), constant: 0) 
0

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

[rowHeightArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithFloat:imageHeight]]; 

Затем вызовите

[aTableView reloadRowsAtIndexPaths:indexPath withRowAnimation:YES]; 

Это будет вызывать

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    return [[rowHeightArray objectAtIndex:indexPath.row] floatValue]; 
} 

где вы вернуть объект в indexPath с высоты строки.

+0

Высота строки ячеек установлена ​​в 'UITableViewAutomaticDimension'. С помощью ограничений автоматической компоновки высота строки будет автоматически определена. Проблема заключается в том, что ограничение пропорций нарушается после прокрутки вверх и вниз. – Tobias

+0

Вы пытались добавить ограничение в UIImageView? Имеются ли изображения одинаковой ширины и высоты или, по крайней мере, одного и того же соотношения? Если нет, вы должны удалить предыдущее ограничение и добавить новое ограничение или проверить ScaleToFit или ScaleToFill ... Я действительно не знаю, как вы это делаете. – Leonardo

0

Чтобы удалить ограничения, проверьте:

[aView setTranslatesAutoresizingMaskIntoConstraints:NO]; 
[aView removeConstraints:view.constraints]; 

или

for(NSLayoutConstraint *constraint in aView.constraints){ 
    [aView.view removeConstraint:constraint]; 
} 
Смежные вопросы