2014-09-25 173 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

    相关问题