2015-09-28 127 views
4

我有一個自定義單元格在XIB文件內部具有動態高度,該單元格顯示帶有消息和圖像的文章。由於圖像將從我的API異步加載,圖像的寬高比將與資源一起發送。在updateConstraints方法中,將設置具有適當乘數的寬高比約束。異步加載的圖像的表格視圖單元格的動態高度

的XIB文件:

My XIB file

Cell類:

// 
// 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:'中的寬度。從第一次看,這似乎是一個模棱兩可的情況,因爲你已經用'0'間距固定'ImageView'水平佈局,然後嘗試根據高度改變寬度。 – Gandalf

+0

這是一個縱橫比約束而非寬度約束。 UIImageView的高度是寬度的0.6672倍。然而,如果我在IB中設置了一個固定的高度,並且不添加這種縱橫比約束,它可以工作,但由於每個圖像都是不同的,所以我總是有相同的高度和錯誤的寬高比。 – Tobias

+1

我知道你已經應用了寬高比約束。我想你誤解了我指的是什麼。在你的縱橫比約束中,「第一項」是「寬度」。這意味着約束將試圖使'寬度'的變化不是該視圖的'高度'。因此,如果您倒轉第一個和第二個項目,並在乘數參數中反轉寬高比,則您將具有相同的約束,但根據圖像寬高比具有不同的高度。 – Gandalf

回答

1

此問題是由施加到ImageView 2層衝突的約束造成的。如果你看看調試器輸出

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

你已經擁有水平約束,以寄託對superview 0間距ImageView

現在同時更新寬高比約束你想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,它跟蹤所有的行高,例如

[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]; 
} 
相關問題