2014-09-25 174 views
30

到目前爲止,我一直在使用應自動調整大小的單元格內的文本標籤。我通常把約束,所有的邊緣(內容視圖或鄰居),並添加以下行到我的viewDidLoad()自動佈局:獲取UIImageView高度以正確計算單元格高度

// 190.0 is the actual height of my custom cell (see next image) in the storyboard containing a label and a randomly sized UIImageView 
tableView.estimatedRowHeight = 190.0 
tableView.rowHeight = UITableViewAutomaticDimension 

現在,試圖與圖片,包括什麼時候,我遇到的幾個問題。在一些研究中,我發現了幾種用Objective-C編寫的方法,但我不確定哪些方法真正解決了我的中心問題,但我仍然在使用複雜的Objective-C代碼。所以繼續:我的最終目標是獲得一個正確大小(正確高度)的單元格,每個單元格包含一個標題和一個適合屏幕寬度的圖像。這些圖像可以具有不同的縱橫比和不同的尺寸。爲了簡化一些挑戰,我準備了一個新的,更簡單的項目:

  1. 首先,我創建了一個UITableViewControllerCustomCell類有兩個IBOutlets title: StringpostedImage: UIImage(UIImage的隨機情節板中的大小)配置細胞。我定義了邊和彼此的約束。

  • 當建,兩個單元獲得含有相同的圖像配置,但它們是取出從具有不同的尺寸和分辨率的兩個單獨的文件(900×171對比半尺寸450 x 86)。 UIImage視圖模式設置爲「Aspect Fit」,但由於我無法以我想要的方式運行,所以我不確定這是否是正確的設置。儘管我期望單元格高度可以根據重新定標的UIImage計算出來,包括我設置的約束條件,但它似乎基於圖像文件的初始高度(如171和86)。它實際上並不適應實際的UIImage視圖高度(大概70我猜)。
  • Both cell heights are based on the initial image file height and not on the actual UIImage height

    在我的一個較爲複雜的項目,我想不同的圖像自動適應屏幕的寬度,無論他們是否是縱向還是橫向 - 並且如果它們的寬度小於屏幕的寬度,他們應該被放大。就像在上面的項目中一樣,每個單元格高度都應該符合故事板中約束所定義的單個內容。無論如何,它始於上面討論的問題:我如何讓這兩個單元具有相同的正確高度,擁抱故事板中定義的內容?

    非常感謝任何幫助!

    +0

    花式發佈的測試項目了GitHub上或其他地方? – 2014-09-25 15:56:44

    +0

    @MikePollard對不起,真的不明白你的意思......順便說一句,我編輯並指定了我的問題。 – 2014-09-25 20:22:59

    +0

    我只是建議上傳你的代碼,以便我們可以玩一玩,並幫助你... – 2014-09-25 20:24:20

    回答

    65

    所以我認爲潛在的問題是一種雞和雞蛋的問題。

    爲了「方面匹配」的圖像提供給UIImageView系統需要一個大小爲視圖,但我們想給定的已知寬度爲方面擬合圖像之後確定視圖的高度風景。

    解決方法是自己計算圖像的寬高比,並在設置圖像時將其設置爲UIImageView的約束條件。這樣自動佈局系統有足夠的信息來確定視圖的大小(寬度和寬高比)。

    所以我改變了你的自定義單元格類:

    class CustomCell: UITableViewCell { 
    
        @IBOutlet weak var imageTitle: UILabel! 
    
        @IBOutlet weak var postedImageView: UIImageView! 
    
        internal var aspectConstraint : NSLayoutConstraint? { 
         didSet { 
          if oldValue != nil { 
           postedImageView.removeConstraint(oldValue!) 
          } 
          if aspectConstraint != nil { 
           postedImageView.addConstraint(aspectConstraint!) 
          } 
         } 
        } 
    
        override func prepareForReuse() { 
         super.prepareForReuse() 
         aspectConstraint = nil 
        } 
    
        func setPostedImage(image : UIImage) { 
    
         let aspect = image.size.width/image.size.height 
    
         aspectConstraint = NSLayoutConstraint(item: postedImageView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: postedImageView, attribute: NSLayoutAttribute.Height, multiplier: aspect, constant: 0.0) 
    
         postedImageView.image = image 
        } 
    
    } 
    

    然後在委託做到這一點,而不是圖像直接設置的:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
         let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as CustomCell 
    
         cell.imageTitle.text = titles[indexPath.row] 
    
         let image = images[titles[indexPath.row]]! 
         cell.setPostedImage(image) 
    
         return cell 
    } 
    

    ,你會得到:

    enter image description here

    希望這會有所幫助!

    +0

    太好了,謝謝!只是一個可選的問題:你是如何着手分析這個問題並得到正確的解決方法的?或者它只是純粹的體驗?;-)任何關鍵點可以幫助我下次進一步進步? – 2014-09-26 10:21:21

    +5

    我開始通過添加一些日誌記錄來打印出imageView的'intrinsicSize',圖像的'size'和imageView的'frame',然後試圖考慮自動佈局系統如何使用這些信息來得到你想要的答案。過了一會兒,我發現「方面配件」部分與自動佈局部分是分開的......這有助於我的頭部近期處於「自動佈局模式」,最近已經解決了各種問題與做4,5,6和6plus很好地佈局工作。 – 2014-09-26 10:39:15

    +0

    這似乎是一個很好的解決方案。雖然我不是斯威夫特那種人。所以我在我的自定義單元格中添加了一個NSLayoutConstraint作爲IBOutlet,並將其綁定到高度約束。我不想每次都添加和刪除高度約束,而只想設置高度。但不知怎的,這會導致崩潰,出現一個「非關鍵值編碼 - 符合」佈局約束IBOutlet。我錯過了什麼? – esbenr 2015-04-20 21:52:04

    1

    邁克波拉德有一個很好的解決方案,但我在設備旋轉時遇到問題。隨着輪換,我得到Autolayout的投訴:

    大概至少在下面的列表中的一個約束是你不想要的。試試這個:(1)看看每個約束,並試圖找出你不期望的; (2)找到添加不需要的約束或約束並修復它的代碼。 (注意:如果您看到您不明白的NSAutoresizingMaskLayoutConstraints,請參閱UIView屬性translatesAutoresizingMaskIntoConstraints的文檔) 。 。 。

    將嘗試打破約束 NSLayoutConstraint恢復:0x82ccc110的UIImageView:0x82ccbed0.width ==的UIImageView:0x82ccbed0.height

    有趣的是,佈局是旋轉後的罰款。我想知道,如果這是一個抱怨,當單元格框架被更改,但然後Autolayout踢,並糾正一切。

    6

    我翻譯了Pollard的解決方案objc版本就像這樣。
    此外,我收到了「無法同時滿足約束條件」等警告。我的解決方案設置垂直空間約束的優先級爲999,而不是1000

    @interface PostImageViewCell() 
    
    @property (nonatomic, strong) NSLayoutConstraint *aspectContraint; 
    @end 
    
    @implementation PostImageViewCell 
    
    - (void) setAspectContraint:(NSLayoutConstraint *)aspectContraint { 
    
        if (_aspectContraint != nil) { 
         [self.postImage removeConstraint:_aspectContraint]; 
        } 
        if (aspectContraint != nil) { 
         [self.postImage addConstraint:aspectContraint]; 
        } 
    } 
    
    - (void) prepareForReuse { 
        [super prepareForReuse]; 
        self.aspectContraint = nil; 
    } 
    
    - (void)setPicture:(UIImage *)image { 
    
        CGFloat aspect = image.size.width/image.size.height; 
        self.aspectContraint = [NSLayoutConstraint constraintWithItem:self.postImage 
                     attribute:NSLayoutAttributeWidth 
                     relatedBy:NSLayoutRelationEqual 
                      toItem:self.postImage 
                     attribute:NSLayoutAttributeHeight 
                     multiplier:aspect 
                     constant:0.0]; 
        [self.postImage setImage:image]; 
    } 
    @end 
    
    +1

    set中缺少'set':_aspectContraint = aspectContraint; – ingaham 2015-11-13 07:56:03

    0

    而不必定製0​​方法,它更方便updateConstraints更新方面的約束。這樣的話,你可以直接改變的UIImageView的圖像,無需額外的輔助方法:

    static NSLayoutConstraint *constraintWithMultiplier(NSLayoutConstraint *constrain, CGFloat multiplier) { 
        return [NSLayoutConstraint constraintWithItem:constrain.firstItem 
                 attribute:constrain.firstAttribute 
                 relatedBy:constrain.relation 
                  toItem:constrain.secondItem 
                 attribute:constrain.secondAttribute 
                 multiplier:multiplier 
                 constant:constrain.constant]; 
    } 
    
    -(void)viewDidLoad 
    { 
        UIView *contentView = self.contentView; 
    
        _imageView = [[UIImageView alloc] init]; 
        _imageView.translatesAutoresizingMaskIntoConstraints = NO; 
        _imageView.contentMode = UIViewContentModeScaleAspectFit; 
        [contentView addSubview:_imageView]; 
    
        _imageAspectConstraint = [_imageView.heightAnchor constraintEqualToAnchor:_imageView.widthAnchor multiplier:1.0f]; 
        NSArray <NSLayoutConstraint *> *constraints = @[ 
          [_imageView.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor constant:0], 
          [_imageView.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor constant:0], 
          [_imageView.topAnchor constraintEqualToAnchor:contentView.topAnchor constant:0], 
          [_imageView.bottomAnchor constraintEqualToAnchor:contentView.bottomAnchor constant:0], 
        ]; 
        [NSLayoutConstraint activateConstraints:constraints]; 
    } 
    
    -(void)updateConstraints 
    { 
        const CGSize size = _imageView.image.size; 
        const CGFloat multiplier = size.width/size.height; 
        _imageAspectConstraint.active = NO; 
        _imageAspectConstraint = constraintWithMultiplier(_imageAspectConstraint, multiplier); 
        _imageAspectConstraint.active = YES; 
        [super updateConstraints]; 
    } 
    
    1

    工作在斯威夫特3 +的iOS 8

    使用自動版式和可變大小的UITableViewCell對象 -

    對於ImageView的,設置頂部,底部,頂部和尾部空間限制爲0.

    要添加到viewDidLoad的代碼()

    tableView.rowHeight = UITableViewAutomaticDimension 
    tableView.estimatedRowHeight = 200 
    

    定義的UITableViewDelegate的heightForRowAtIndexPath()

    extension ViewController: UITableViewDelegate { 
    
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 
         let image = UIImage(named: list_images[indexPath.row]) 
         let aspect = (image?.size.width)!/(image?.size.height)! 
         let cellHeight = (tableView.frame.width/aspect) + <<Height of image title label>> 
         return cellHeight 
        } 
    } 
    
    +0

    我在這個問題上努力奮鬥 - 而且現在還在做 - 根據我的經驗,使用tableView:heightForRowAtIndexPath:使得UITableView非常慢;滾動性能受到嚴重影響。 您不想使用此功能,除了可能用於測試/檢查可能的解決方案。 – dinesharjani 2017-08-07 10:32:11

    相關問題