简体   繁体   English

在自定义UITableViewCell中保持UIImageView的长宽比

[英]Keep aspect ratio of an UIImageView in a custom UITableViewCell

So what I want to do is have my custom UITableViewCell contain a UIImageView with an image inside it, and have this ImageView always keep the same aspect ratio as the image inside it, while having the same width as the cell. 所以我想做的是让我的自定义UITableViewCell包含一个UIImageView其中包含一个图像,并让此ImageView始终与其中的图像保持相同的宽高比,同时具有与单元格相同的宽度。 The height of the cell should then be the same as the height of the ImageView . 然后,单元格的高度应与ImageView的高度相同。

Here's the code I'm using: 这是我正在使用的代码:

My custom UITableViewCell class: 我的自定义UITableViewCell类:

import UIKit

class ImageTableViewCell: UITableViewCell {

    var imageURL: NSURL? {
        didSet {
            fetchImage()
        }
    }

    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

    @IBOutlet weak var myImageView: UIImageView!

    func fetchImage() {
        myImageView?.image = nil

        guard let imageURL = self.imageURL else {
            return
        }
        activityIndicator?.startAnimating()
        let queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)
        dispatch_async(queue) {
            guard let imageData = NSData(contentsOfURL: imageURL) else { return }
            dispatch_async(dispatch_get_main_queue()) {
                guard imageURL == self.imageURL else { return }
                if let image = UIImage(data: imageData) {
                    self.tweetImage?.image = image
                    self.tweetImage?.sizeToFit()
                } else { self.tweetImage?.image = nil }
                self.spinner?.stopAnimating()
            }
        }
    }

    func addRatioConstraint(ratio: CGFloat) {
        let ratioConstraint = NSLayoutConstraint(item: myImageView, attribute: .Width, relatedBy: .Equal, toItem: myImageView, attribute: .Height, multiplier: ratio, constant: 0)
        ratioConstraint.priority = UILayoutPriorityDefaultHigh //important piece of code
        myImageView?.addConstraint(ratioConstraint)
    }
}

and here is the relevant code from the UITableViewController : 这是UITableViewController的相关代码:

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.rowHeight = UITableViewAutomaticDimension
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let mention = mentionSections[indexPath.section].mentions[indexPath.row]
    switch mention {
    case .Image(let url, let ratio):
        guard let imageCell = tableView.dequeueReusableCellWithIdentifier(.Image, forIndexPath: indexPath) as? ImageTableViewCell else { fallthrough }
        imageCell.imageURL = url
        imageCell.addRatioConstraint(CGFloat(ratio))
        return imageCell
    //left out code for additional irrelevant cells
    }
}

override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let mention = mentionSections[indexPath.section].mentions[indexPath.row]
    switch mention {
    case .Image(_, _): return 200
    default: return 41
    }
}

and to understand what I'm doing with the dequeueReusableCellWithIdentifier function (it's just a little extension to simplify things for me): 并了解我在使用dequeueReusableCellWithIdentifier函数的操作(只是为我简化事情的一个扩展):

private extension UITableView {

    enum CellIdentifier: String {
        case Image = "Image"
        case Keyword = "Keyword"
    }

    func dequeueReusableCellWithIdentifier(cellIdentifier: CellIdentifier, forIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        return self.dequeueReusableCellWithIdentifier(cellIdentifier.rawValue, forIndexPath: indexPath)
    }
} 

Sorry for so much code, but I felt like I had to include all this. 很抱歉有这么多代码,但是我觉得我必须包括所有这些内容。

Now to the problem! 现在问题了! The problem I'm getting is that when the view first loads everything looks great, but when I turn the device to landscape and then turn it back to portrait I lose the aspect ratio and the image gets squashed. 我遇到的问题是,当视图第一次加载时,所有内容看起来都很不错,但是当我将设备转为横向,然后再转回纵向时,我失去了长宽比,图像被压缩了。 Like this: 像这样:

http://i.imgur.com/tcnBfyH.jpg http://i.imgur.com/tcnBfyH.jpg

However, if I remove this line of code (in the addRatioConstraint(ratio: CGFloat) -method in the ImageTableViewCell-class): 但是,如果我删除以下代码行(在addRatioConstraint(ratio: CGFloat) -方法中):

ratioConstraint.priority = UILayoutPriorityDefaultHigh

(which means that the priority is now 1000 instead of 750 i think), everything works just as expected, except that I now get an error printed out in the console: (这意味着优先级现在是1000,而不是750),一切正常,只是我现在在控制台中打印出一个错误:

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:0x7fcfd4d3e690 UIImageView:0x7fcfd4e29a70.trailing == UITableViewCellContentView:0x7fcfd4e29900.trailingMargin>",
    "<NSLayoutConstraint:0x7fcfd4d3f5c0 UIImageView:0x7fcfd4e29a70.bottom == UITableViewCellContentView:0x7fcfd4e29900.bottomMargin>",
    "<NSLayoutConstraint:0x7fcfd4d3f610 UIImageView:0x7fcfd4e29a70.top == UITableViewCellContentView:0x7fcfd4e29900.topMargin>",
    "<NSLayoutConstraint:0x7fcfd4d3f660 UIImageView:0x7fcfd4e29a70.leading == UITableViewCellContentView:0x7fcfd4e29900.leadingMargin>",
    "<NSLayoutConstraint:0x7fcfd4d52010 UIImageView:0x7fcfd4e29a70.width == 1.34387*UIImageView:0x7fcfd4e29a70.height>",
    "<NSLayoutConstraint:0x7fcfd4e1f200 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7fcfd4e29900(341)]>",
    "<NSLayoutConstraint:0x7fcfd4e1f250 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fcfd4e29900(199.5)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fcfd4d52010 UIImageView:0x7fcfd4e29a70.width == 1.34387*UIImageView:0x7fcfd4e29a70.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.

So basically what Xcode does is it breaks my aspect constraint to try and fix some conflict. 因此,基本上Xcode所做的是它打破了我的方面约束,试图解决一些冲突。 And it works. 而且有效。 In my head that should mean that lowering the priority of that constraint should do the trick as well? 在我的脑海中,这应该意味着降低约束的优先级也可以解决问题?

Any help would be MASSIVELY appreciated, I've been struggling with this for days now. 任何帮助将不胜感激,我已经为此努力了几天。

As in this answer , you're setting a variable width constraint as well as a trailing and leading constraint. 就像在此答案中一样 ,您正在设置可变宽度约束以及尾随和前导约束。 This will cause a conflict. 这将导致冲突。

Replace the trailing/leading constraints with a centerX constraint. 用centerX约束替换尾随/前导约束。

I'd suggest using anchors for this. 我建议为此使用

First, make sure to imageView.translatesAutoreisizingMaskIntoConstraints = false and imageView.contentMode = .scaleAspectFill 首先,请确保imageView.contentMode = .scaleAspectFill imageView.translatesAutoreisizingMaskIntoConstraints = falseimageView.contentMode = .scaleAspectFill

Then, set your anchors for each side as you see fit. 然后,根据需要在每一侧设置锚点。

imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
imageView.bottomAnchor.constraint(self.bottomAnchor).isActive = true

You can also add ..,constant: Float) in the constraint parameters, to set a specific distance between the parent anchor point and your imageView . 您还可以在约束参数中添加..,constant: Float) ,以设置父锚点和imageView之间的特定距离。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM