ios UITableView 中的动态 UIImageView 大小

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32281886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:26:26  来源:igfitidea点击:

Dynamic UIImageView Size Within UITableView

iosswiftuitableviewuiimageviewautolayout

提问by fabdarice

I want to implement a TableView with a Custom TableViewCell showing an image.

我想实现一个带有显示图像的自定义 TableViewCell 的 TableView。

To make this simple, I simply put a UIImageView inside a tableviewcell using autolayout (illustrated below). enter image description here

为了简单起见,我只是使用自动布局(如下所示)将 UIImageView 放在 tableviewcell 中。 在此处输入图片说明

What I want is to display the image inside a UIImageView however those images dimensions can be anything and are inconsistent (portrait, landscape, square) ...

我想要的是在 UIImageView 中显示图像,但是这些图像尺寸可以是任何尺寸并且不一致(纵向、横向、方形)......

Therefore, I'm looking to display an image with a fixed width (the width of the device) and a dynamic height that respect the ratio of the images. I want something like this:
enter image description here

因此,我希望显示具有固定宽度(设备的宽度)和动态高度的图像,以尊重图像的比例。我想要这样的东西:
在此处输入图片说明

I unfortunately didn't manage to reach that result.

不幸的是,我没能达到那个结果。

Here's how I implemented it - (I'm using Haneke to load the image from an URL - image stored in Amazon S3):

这是我的实现方式 - (我使用 Haneke 从 URL 加载图像 - 图像存储在 Amazon S3 中):

class TestCellVC: UITableViewCell {

    @IBOutlet weak var selfieImageView: UIImageView!
    @IBOutlet weak var heightConstraint: NSLayoutConstraint!

    func loadItem(#selfie: Selfie) {        
        let selfieImageURL:NSURL = NSURL(string: selfie.show_selfie_pic())!

        self.selfieImageView.hnk_setImageFromURL(selfieImageURL, placeholder: nil, format: HNKFormat<UIImage>(name: "original"), failure: {error -> Void in println(error)
            }, success: { (image) -> Void in
                // Screen Width
                var screen_width = UIScreen.mainScreen().bounds.width

                // Ratio Width / Height
                var ratio =  image.size.height / image.size.width

                // Calculated Height for the picture
                let newHeight = screen_width * ratio

                // METHOD 1
                self.heightConstraint.constant = newHeight

                // METHOD 2
                //self.selfieImageView.bounds = CGRectMake(0,0,screen_width,newHeight)

                self.selfieImageView.image = image
            }
        )
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Register the xib for the Custom TableViewCell
        var nib = UINib(nibName: "TestCell", bundle: nil)
        self.tableView.registerNib(nib, forCellReuseIdentifier: "TestCell")

        // Set the height of a cell dynamically
        self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.estimatedRowHeight = 500.0

        // Remove separator line from UITableView
        self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None

        loadData()
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("TestCell") as TestCellVC


        cell.loadItem(selfie: self.selfies_array[indexPath.row])
        // Remove the inset for cell separator
        cell.layoutMargins = UIEdgeInsetsZero
        cell.separatorInset = UIEdgeInsetsZero

        // Update Cell Constraints
        cell.setNeedsUpdateConstraints()
        cell.updateConstraintsIfNeeded()
        cell.sizeToFit()

        return cell
    }
}

My calculation of the dynamic Height is correct (I've printed it). I've tried both method (describe in the code) but none of them worked:

我对动态高度的计算是正确的(我已经打印过了)。我已经尝试了两种方法(在代码中描述),但它们都不起作用:

  1. Set the Height Autolayout constraint of the UIImageView
  2. Modify the frame of the UIImageView
  1. 设置 UIImageView 的高度自动布局约束
  2. 修改UIImageView的frame

See Results of Method 1 and 2 here: imageImage 2

在此处查看方法 1 和 2 的结果: 图片图 2

回答by sash

In the storyboard add trailing, leading, bottom and top constraints to your UIImageView. After you load your image all you need to do is add an aspect constraint to your UIImageView. Your images cell would look something like this:

在故事板中,向UIImageView. 加载图像后,您需要做的就是向UIImageView. 您的图像单元格看起来像这样:

class ImageTableViewCell: UITableViewCell {

    @IBOutlet weak var customImageView: UIImageView!

    internal var aspectConstraint : NSLayoutConstraint? {
        didSet {
            if oldValue != nil {
                customImageView.removeConstraint(oldValue!)
            }
            if aspectConstraint != nil {
                customImageView.addConstraint(aspectConstraint!)
            }
        }
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        aspectConstraint = nil
    }

    func setCustomImage(image : UIImage) {

        let aspect = image.size.width / image.size.height

        let constraint = NSLayoutConstraint(item: customImageView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: customImageView, attribute: NSLayoutAttribute.height, multiplier: aspect, constant: 0.0)
        constraint.priority = 999

        aspectConstraint = constraint

        customImageView.image = image
    }
}

You can check working example here DynamicTableWithImages

您可以在此处查看工作示例DynamicTableWithImages

回答by Hyman

enter image description here

在此处输入图片说明

While loading images into the tableView each image can be with diffrent aspect ratio. With using of SDWebImagewe can get the image from url as -

在将图像加载到 tableView 时,每个图像可以具有不同的纵横比。通过使用SDWebImage,我们可以从 url 获取图像 -

 testImageView.sd_setImage(with: url, placeholderImage: nil, options: [], completed: { (downloadedImage, error, cache, url) in
            print(downloadedImage?.size.width)//prints width of image
            print(downloadedImage?.size.height)//prints height of image
        })

In UITableViewCellset the constraint for imageView as top, bottom, leading, trailing, fixed height constraintwith 999 priority And change height-constraint-constantaccording to image.

UITableViewCell将 imageView 的约束设置为top, bottom, leading, trailing,fixed height constraint优先级为 999 并height-constraint-constant根据图像进行更改。

 var cellFrame = cell.frame.size
 cellFrame.height =  cellFrame.height - 15
 cellFrame.width =  cellFrame.width - 15
 cell.feedImageView.sd_setImage(with: url, placeholderImage: nil, options: [], completed: { (theImage, error, cache, url) in
            cell.feedImageHeightConstraint.constant = self.getAspectRatioAccordingToiPhones(cellImageFrame: cellFrame,downloadedImage: theImage!)

        })

Calculate cell frame & find the respective height based on that.

计算单元格框架并在此基础上找到相应的高度。

  func getAspectRatioAccordingToiPhones(cellImageFrame:CGSize,downloadedImage: UIImage)->CGFloat {
        let widthOffset = downloadedImage.size.width - cellImageFrame.width
        let widthOffsetPercentage = (widthOffset*100)/downloadedImage.size.width
        let heightOffset = (widthOffsetPercentage * downloadedImage.size.height)/100
        let effectiveHeight = downloadedImage.size.height - heightOffset
        return(effectiveHeight)
    }

Example on Github

Github 上的示例

回答by algal

If you want the UIImageView to tell the UITableView how tall it needs to be, then you need to configure the table view to enable automatic row calculation. You do this by setting estimatedRowHeight to a fixed positive value and setting rowHeight to UIViewAutomaticDimension. That's part one.

如果你想让 UIImageView 告诉 UITableView 它需要多高,那么你需要配置 table view 以启用自动行计算。您可以通过将estimatedRowHeight 设置为固定的正值并将rowHeight 设置为UIViewAutomaticDimension 来完成此操作。这是第一部分。

Now you need to configure the UIImageView to request a height based on the width which the table view requires and on the aspect ratio of the image. This will be part two.

现在您需要配置 UIImageView 以根据表格视图所需的宽度和图像的纵横比请求高度。这将是第二部分。

First, set the contentMode to .AspectFit. This will cause the view to resize the appearance of the image based on whatever dimensions it takes. However, this still doesn't cause it to request the needed height with auto layout. Instead, it will request the height of the intrinsicContentSize, which may be quite different from the resized image. So, second, add a constraint to the UIImageView that is of the form width = height * multiplier, where the multiplier is based on the aspect ratio of the image itself.

首先,将 contentMode 设置为 .AspectFit。这将导致视图根据它所采用的任何尺寸调整图像外观的大小。但是,这仍然不会导致它通过自动布局请求所需的高度。相反,它将请求内在内容大小的高度,这可能与调整大小的图像有很大不同。因此,第二,向形式为 的 UIImageView 添加约束width = height * multiplier,其中乘数基于图像本身的纵横比。

Now the table view will require the correct width, the contentMode mechanism will ensure the image is resized correctly without distortion, and the aspect ration constraint will ensure that the image view requires the correct height via auto layout.

现在 table view 将需要正确的宽度,contentMode 机制将确保图像正确调整大小而不会失真,并且宽高比约束将确保图像视图通过自动布局需要正确的高度。

This works. The downside of it is that you will need to update the aspect ratio constraint every time you assign a new image to the image view, which could be quite often if the image view is in a cell that's getting re-used.

这有效。它的缺点是每次将新图像分配给图像视图时都需要更新纵横比约束,如果图像视图位于被重用的单元格中,这种情况可能会经常发生。

An alternative approach is to add only a height constraint and update it in the layoutSubviews of a view containing the image view. This has better performance but worse code modularity.

另一种方法是仅添加高度约束并在包含图像视图的视图的 layoutSubviews 中更新它。这具有更好的性能但更糟糕的代码模块化。

回答by Mohammad Kamran Usmani

Swift 4.0

斯威夫特 4.0

You can use simple code to manage the height of row according to the height of imageView in tableView cell.

您可以使用简单的代码根据tableView单元格中imageView的高度来管理行高。

   func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if let height = self.rowHeights[indexPath.row]{
            return height
        }else{
            return defaultHeight
        }
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return imageArray.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let identifier = "editImageCell"
        let customCell : EdiPostImageCell = (self.imagesTableView.dequeueReusableCell(withIdentifier: identifier)) as! EdiPostImageCell
        let aspectRatio = (imageArray[indexPath.row]).size.height/(imageArray[indexPath.row]).size.width
        customCell.editlImageView.image = imageArray[indexPath.row]
        let imageHeight = self.view.frame.width*aspectRatio
        self.imagesTableView.beginUpdates()
        self.rowHeights[indexPath.row] = imageHeight
        tableView.endUpdates()
    }

回答by Fazal rahman Puliyanchali

  1. make sure you have set top-bottom constraints in storyboard.
  2. save the thumbnail/image as data to local storage (I'm using core data)
  3. using the thumb image, calculate the aspect of the image
  4. customise the row height as you want in heightForRowAt method.
  1. 确保您在故事板中设置了自上而下的约束。
  2. 将缩略图/图像作为数据保存到本地存储(我正在使用核心数据)
  3. 使用拇指图像,计算图像的方面
  4. 在 heightForRowAt 方法中根据需要自定义行高。
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let entity = self.fetchedResultController.object(at: indexPath as IndexPath) as! Message
        var newh:CGFloat = 100.00

        if let fileThumbnails =  entity.file_thumbnails as? NSArray{
            if fileThumbnails.count != 0{
                fileThumbnails.map { (thumbNail) in
                    newh = self.getImageHeight(image:UIImage(data: thumbNail as! Data)! , h: UIImage(data: thumbNail as! Data)!.size.height , w: UIImage(data: thumbNail as! Data)!.size.width)
                }

            }

        }

        if entity.fileStatus == "DeletedMedia" {
            newh = 100
        }
        if entity.fileStatus == nil{
            newh = 0.0
        }
        print ("newH " , newh)
        return newh
    }
    func getImageHeight(image : UIImage, h : CGFloat, w : CGFloat) -> CGFloat {
        let aspect = image.size.width / image.size.height
        var newH = (messagesTV.frame.size.width) / aspect
        // customise as you want in newH
        if(newH > 500){
            newH = 500
           //maximum height 500
        }
        if(newH < 100){
            newH = 100
            //minimum height = 100
        }
        return newH
    }

if the thumb image is deleted in local storage then a placeholder image will be shown. you can customise the newHvariable to get the desired output

如果在本地存储中删除拇指图像,则将显示占位符图像。您可以自定义 newHvariable 以获得所需的输出

if you want to change the params like a fixed width then change it in the newHvariable in getImageHeight()method. eg: var newH = (messagesTV.frame.size.width * 0.6) / aspectI will get height with aspect based on the width I mentioned here in this example, my fixed width is 60% width of the screen. hope this helps!

如果您想像固定宽度一样更改参数,请newHgetImageHeight()方法中的变量中更改它。例如:var newH = (messagesTV.frame.size.width * 0.6) / aspect我将根据我在此示例中在这里提到的宽度获得带有纵横比的高度,我的固定宽度是屏幕宽度的 60%。希望这可以帮助!

回答by Rohit Kumar

Remove the height constraint from your imageView. Choose the contentMode of image view that starts with "aspect" eg: aspect fill or aspect fit (as it fits according to your requirements).

从 imageView 中删除高度约束。选择以“aspect”开头的图像视图的 contentMode 例如:aspect fill 或 aspect fit(根据您的要求适合)。

NOTE: You also need to set the height of the row so that the imageView fits in it. Use

注意:您还需要设置行的高度,以便 imageView 适合它。用

heightForRowAtIndexPath

to set custom row height.

设置自定义行高。