简体   繁体   English

即使图像较小,如何使UITableViewCell的ImageView成为固定大小

[英]How do I make UITableViewCell's ImageView a fixed size even when the image is smaller

I have a bunch of images I am using for cell's image views, they are all no bigger than 50x50. 我有一堆用于细胞图像视图的图像,它们都不超过50x50。 eg 40x50, 50x32, 20x37 ..... 例如40x50,50x32,20x37 .....

When I load the table view, the text doesn't line up because the width of the images varies. 当我加载表格视图时,文本不会排列,因为图像的宽度会有所不同。 Also I would like small images to appear in the centre as opposed to on the left. 此外,我希望小图像出现在中心而不是左侧。

Here is the code I am trying inside my 'cellForRowAtIndexPath' method 这是我在'cellForRowAtIndexPath'方法中尝试的代码

cell.imageView.autoresizingMask = ( UIViewAutoresizingNone );
cell.imageView.autoresizesSubviews = NO;
cell.imageView.contentMode = UIViewContentModeCenter;
cell.imageView.bounds = CGRectMake(0, 0, 50, 50);
cell.imageView.frame = CGRectMake(0, 0, 50, 50);
cell.imageView.image = [UIImage imageWithData: imageData];

As you can see I have tried a few things, but none of them work. 正如你所看到的,我尝试了一些东西,但它们都没有用。

It's not necessary to rewrite everything. 没有必要重写所有内容。 I recommend doing this instead: 我推荐这样做:

Post this inside your .m file of your custom cell. 将其发布在自定义单元格的.m文件中。

- (void)layoutSubviews {
    [super layoutSubviews];
    self.imageView.frame = CGRectMake(0,0,32,32);
}

This should do the trick nicely. 这应该很好地完成。 :] :]

For those of you who don't have a subclass of UITableViewCell : 对于那些没有UITableViewCell子类的人:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 [...]

      CGSize itemSize = CGSizeMake(40, 40);
      UIGraphicsBeginImageContextWithOptions(itemSize, NO, UIScreen.mainScreen.scale);
      CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
      [cell.imageView.image drawInRect:imageRect];
      cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();

 [...]
     return cell;
}

The code above sets the size to be 40x40. 上面的代码将大小设置为40x40。

Swift 2 斯威夫特2

    let itemSize = CGSizeMake(25, 25);
    UIGraphicsBeginImageContextWithOptions(itemSize, false, UIScreen.mainScreen().scale);
    let imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
    cell.imageView?.image!.drawInRect(imageRect)
    cell.imageView?.image! = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

Or you can use another(not tested) approach suggested by @Tommy: 或者您可以使用@Tommy建议的另一种(未经测试)方法:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 [...]

      CGSize itemSize = CGSizeMake(40, 40);
      UIGraphicsBeginImageContextWithOptions(itemSize, NO, 0.0)          
 [...]
     return cell;
}

Swift 3+ Swift 3+

let itemSize = CGSize.init(width: 25, height: 25)
UIGraphicsBeginImageContextWithOptions(itemSize, false, UIScreen.main.scale);
let imageRect = CGRect.init(origin: CGPoint.zero, size: itemSize)
cell?.imageView?.image!.draw(in: imageRect)
cell?.imageView?.image! = UIGraphicsGetImageFromCurrentImageContext()!;
UIGraphicsEndImageContext();

The code above is the Swift 3+ version of the above. 上面的代码是上面的Swift 3+版本。

Here's how i did it. 这是我如何做到的。 This technique takes care of moving the text and detail text labels appropriately to the left: 此技术负责将文本和详细文本标签适当地移动到左侧:

@interface SizableImageCell : UITableViewCell {}
@end
@implementation SizableImageCell
- (void)layoutSubviews {
    [super layoutSubviews];

    float desiredWidth = 80;
    float w=self.imageView.frame.size.width;
    if (w>desiredWidth) {
        float widthSub = w - desiredWidth;
        self.imageView.frame = CGRectMake(self.imageView.frame.origin.x,self.imageView.frame.origin.y,desiredWidth,self.imageView.frame.size.height);
        self.textLabel.frame = CGRectMake(self.textLabel.frame.origin.x-widthSub,self.textLabel.frame.origin.y,self.textLabel.frame.size.width+widthSub,self.textLabel.frame.size.height);
        self.detailTextLabel.frame = CGRectMake(self.detailTextLabel.frame.origin.x-widthSub,self.detailTextLabel.frame.origin.y,self.detailTextLabel.frame.size.width+widthSub,self.detailTextLabel.frame.size.height);
        self.imageView.contentMode = UIViewContentModeScaleAspectFit;
    }
}
@end

...

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[SizableImageCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }

    cell.textLabel.text = ...
    cell.detailTextLabel.text = ...
    cell.imageView.image = ...
    return cell;
}

image view add as a sub view to the tableview cell 图像视图作为子视图添加到tableview单元格

UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(20, 5, 90, 70)];
imgView.backgroundColor=[UIColor clearColor];
[imgView.layer setCornerRadius:8.0f];
[imgView.layer setMasksToBounds:YES];
[imgView setImage:[UIImage imageWithData: imageData]];
[cell.contentView addSubview:imgView];

The whole cell doesn't need to be remade. 整个细胞不需要重新制作。 You could use the indentationLevel and indentationWidth property of tableViewCells to shift the content of your cell. 您可以使用tableViewCells的indentationLevel和indentationWidth属性来移动单元格的内容。 Then you add your custom imageView to the left side of the cell. 然后将自定义imageView添加到单元格的左侧。

A Simply Swift , 一个简单的快速

Step 1: Create One SubClass of UITableViewCell 第1步:创建UITableViewCell一个子类
Step 2: Add this method to SubClass of UITableViewCell 第2步:将此方法添加到UITableViewCell的SubClass

override func layoutSubviews() {
    super.layoutSubviews()
    self.imageView?.frame = CGRectMake(0, 0, 10, 10)
}

Step 3: Create cell object using that SubClass in cellForRowAtIndexPath , 第3步:使用cellForRowAtIndexPath中的SubClass创建单元格对象,

Ex: let customCell:CustomCell = CustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")

Step 4: Enjoy 第4步:享受

更好地创建图像视图并将其作为子视图添加到单元格。然后您可以获得所需的帧大小。

UIImage *image = cell.imageView.image;

UIGraphicsBeginImageContext(CGSizeMake(35,35));
// draw scaled image into thumbnail context

[image drawInRect:CGRectMake(5, 5, 35, 35)]; //
UIImage *newThumbnail = UIGraphicsGetImageFromCurrentImageContext();
// pop the context
UIGraphicsEndImageContext();
if(newThumbnail == nil)
{
    NSLog(@"could not scale image");
    cell.imageView.image = image;
}
else
{
    cell.imageView.image = newThumbnail;
}

I've created an extension using @GermanAttanasio 's answer. 我使用@GermanAttanasio的答案创建了一个扩展。 It provides a method to resize an image to a desired size, and another method to do the same while adding a transparent margin to the image (this can be useful for table views where you want the image to have a margin as well). 它提供了一种将图像大小调整为所需大小的方法,以及在向图像添加透明边距时执行相同操作的另一种方法(这对于您希望图像也具有边距的表视图非常有用)。

import UIKit

extension UIImage {

    /// Resizes an image to the specified size.
    ///
    /// - Parameters:
    ///     - size: the size we desire to resize the image to.
    ///
    /// - Returns: the resized image.
    ///
    func imageWithSize(size: CGSize) -> UIImage {

        UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.mainScreen().scale);
        let rect = CGRectMake(0.0, 0.0, size.width, size.height);
        drawInRect(rect)

        let resultingImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return resultingImage
    }

    /// Resizes an image to the specified size and adds an extra transparent margin at all sides of
    /// the image.
    ///
    /// - Parameters:
    ///     - size: the size we desire to resize the image to.
    ///     - extraMargin: the extra transparent margin to add to all sides of the image.
    ///
    /// - Returns: the resized image.  The extra margin is added to the input image size.  So that
    ///         the final image's size will be equal to:
    ///         `CGSize(width: size.width + extraMargin * 2, height: size.height + extraMargin * 2)`
    ///
    func imageWithSize(size: CGSize, extraMargin: CGFloat) -> UIImage {

        let imageSize = CGSize(width: size.width + extraMargin * 2, height: size.height + extraMargin * 2)

        UIGraphicsBeginImageContextWithOptions(imageSize, false, UIScreen.mainScreen().scale);
        let drawingRect = CGRect(x: extraMargin, y: extraMargin, width: size.width, height: size.height)
        drawInRect(drawingRect)

        let resultingImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return resultingImage
    }
}

This worked for me in swift: 这对我来说非常有用:

Create a subclass of UITableViewCell (make sure you link up your cell in the storyboard) 创建UITableViewCell的子类(确保在故事板中链接您的单元格)

class MyTableCell:UITableViewCell{
    override func layoutSubviews() {
        super.layoutSubviews()

        if(self.imageView?.image != nil){

            let cellFrame = self.frame
            let textLabelFrame = self.textLabel?.frame
            let detailTextLabelFrame = self.detailTextLabel?.frame
            let imageViewFrame = self.imageView?.frame

            self.imageView?.contentMode = .ScaleAspectFill
            self.imageView?.clipsToBounds = true
            self.imageView?.frame = CGRectMake((imageViewFrame?.origin.x)!,(imageViewFrame?.origin.y)! + 1,40,40)
            self.textLabel!.frame = CGRectMake(50 + (imageViewFrame?.origin.x)! , (textLabelFrame?.origin.y)!, cellFrame.width-(70 + (imageViewFrame?.origin.x)!), textLabelFrame!.height)
            self.detailTextLabel!.frame = CGRectMake(50 + (imageViewFrame?.origin.x)!, (detailTextLabelFrame?.origin.y)!, cellFrame.width-(70 + (imageViewFrame?.origin.x)!), detailTextLabelFrame!.height)
        }
    }
}

In cellForRowAtIndexPath , dequeue the cell as your new cell type: 在cellForRowAtIndexPath中,将单元格作为新单元格类型出列:

    let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyTableCell

Obviously change number values to suit your layout 显然,更改数字值以适合您的布局

The regular UITableViewCell works well to position things but the cell.imageView doesn't seem to behave like you want it to. 常规UITableViewCell可以很好地定位事物,但是cell.imageView似乎没有像你想要的那样。 I found that it's simple enough to get the UITableViewCell to lay out properly by first giving the cell.imageView a properly sized image like 我发现通过首先给cell.image查看正确大小的图像,让UITableViewCell正确布局是很简单的

// Putting in a blank image to make sure text always pushed to the side.
UIGraphicsBeginImageContextWithOptions(CGSizeMake(kGroupImageDimension, kGroupImageDimension), NO, 0.0);
UIImage *blank = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
cell.imageView.image = blank;

Then you can just connect up your own properly working UIImageView with 然后你就可以连接自己正常工作的UIImageView了

// The cell.imageView increases in size to accomodate the image given it.
// We don't want this behaviour so we just attached a view on top of cell.imageView.
// This gives us the positioning of the cell.imageView without the sizing
// behaviour.
UIImageView *anImageView = nil;
NSArray *subviews = [cell.imageView subviews];
if ([subviews count] == 0)
{
    anImageView = [[UIImageView alloc] init];
    anImageView.translatesAutoresizingMaskIntoConstraints = NO;
    [cell.imageView addSubview:anImageView];

    NSLayoutConstraint *aConstraint = [NSLayoutConstraint constraintWithItem:anImageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:cell.imageView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0];
    [cell.imageView addConstraint:aConstraint];

    aConstraint = [NSLayoutConstraint constraintWithItem:anImageView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:cell.imageView attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0];
    [cell.imageView addConstraint:aConstraint];

    aConstraint = [NSLayoutConstraint constraintWithItem:anImageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:kGroupImageDimension];
    [cell.imageView addConstraint:aConstraint];

    aConstraint = [NSLayoutConstraint constraintWithItem:anImageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:kGroupImageDimension];
    [cell.imageView addConstraint:aConstraint];
}
else
{
    anImageView = [subviews firstObject];
}

Set the image on anImageView and it will do what you expect a UIImageView to do. 在anImageView上设置图像,它将完成您对UIImageView的期望。 Be the size you want it regardless of the image you give it. 无论您提供的图像如何,都是您想要的尺寸。 This should go in tableView:cellForRowAtIndexPath: 这应该放在tableView:cellForRowAtIndexPath中:

This solution essentially draws the image as 'aspect fit' within the given rect. 该解决方案基本上将图像绘制为给定矩形内的“纵横拟合”。

CGSize itemSize = CGSizeMake(80, 80);
UIGraphicsBeginImageContextWithOptions(itemSize, NO, UIScreen.mainScreen.scale);
UIImage *image = cell.imageView.image;

CGRect imageRect;
if(image.size.height > image.size.width) {
    CGFloat width = itemSize.height * image.size.width / image.size.height;
    imageRect = CGRectMake((itemSize.width - width) / 2, 0, width, itemSize.height);
} else {
    CGFloat height = itemSize.width * image.size.height / image.size.width;
    imageRect = CGRectMake(0, (itemSize.height - height) / 2, itemSize.width, height);
}

[cell.imageView.image drawInRect:imageRect];
cell.imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Here is @germanattanasio 's working method, written for Swift 3 这是@germanattanasio的工作方法,为Swift 3编写

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    cell.imageView?.image = myImage
    let itemSize = CGSize(width:42.0, height:42.0)
    UIGraphicsBeginImageContextWithOptions(itemSize, false, 0.0)
    let imageRect = CGRect(x:0.0, y:0.0, width:itemSize.width, height:itemSize.height)
    cell.imageView?.image!.draw(in:imageRect)
    cell.imageView?.image! = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
}

If you use cell.imageView?.translatesAutoresizingMaskIntoConstraints = false you can set constraints on the imageView. 如果使用cell.imageView?.translatesAutoresizingMaskIntoConstraints = false ,则可以在cell.imageView?.translatesAutoresizingMaskIntoConstraints = false上设置约束。 Here's a working example I used in a project. 这是我在项目中使用的一个工作示例。 I avoided subclassing and didn't need to create storyboard with prototype cells but did take me quite a while to get running, so probably best to only use if there isn't a simpler or more concise way available to you. 我避免了子类化,并且不需要使用原型单元创建故事板,但确实花了我很长时间才能运行,所以最好只在没有更简单或更简洁的方式使用时使用。

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80
}



    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .subtitle, reuseIdentifier: String(describing: ChangesRequiringApprovalTableViewController.self))

    let record = records[indexPath.row]

    cell.textLabel?.text = "Title text"

    if let thumb = record["thumbnail"] as? CKAsset, let image = UIImage(contentsOfFile: thumb.fileURL.path) {
        cell.imageView?.contentMode = .scaleAspectFill
        cell.imageView?.image = image
        cell.imageView?.translatesAutoresizingMaskIntoConstraints = false
        cell.imageView?.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor).isActive = true
        cell.imageView?.widthAnchor.constraint(equalToConstant: 80).rowHeight).isActive = true
        cell.imageView?.heightAnchor.constraint(equalToConstant: 80).isActive = true
        if let textLabel = cell.textLabel {
            let margins = cell.contentView.layoutMarginsGuide
            textLabel.translatesAutoresizingMaskIntoConstraints = false
            cell.imageView?.trailingAnchor.constraint(equalTo: textLabel.leadingAnchor, constant: -8).isActive = true
            textLabel.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
            textLabel.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
            let bottomConstraint = textLabel.bottomAnchor.constraint(equalTo: margins.bottomAnchor)
            bottomConstraint.priority = UILayoutPriorityDefaultHigh
            bottomConstraint.isActive = true
            if let description = cell.detailTextLabel {
                description.translatesAutoresizingMaskIntoConstraints = false
                description.bottomAnchor.constraint(equalTo: margins.bottomAnchor).isActive = true
                description.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
                cell.imageView?.trailingAnchor.constraint(equalTo: description.leadingAnchor, constant: -8).isActive = true
                textLabel.bottomAnchor.constraint(equalTo: description.topAnchor).isActive = true
            }
        }
        cell.imageView?.clipsToBounds = true
    }

    cell.detailTextLabel?.text = "Detail Text"

    return cell
}

I had the same problem. 我有同样的问题。 Thank you to everyone else who answered - I was able to get a solution together using parts of several of these answers. 感谢所有回答的人 - 我能够使用其中几个答案的部分内容得到解决方案。

My solution is using swift 5 我的解决方案是使用swift 5

The problem that we are trying to solve is that we may have images with different aspect ratios in our TableViewCell s but we want them to render with consistent widths. 我们试图解决的问题是我们可能在TableViewCell使用不同宽高比的图像,但我们希望它们以一致的宽度进行渲染。 The images should, of course, render with no distortion and fill the entire space. 当然,图像应该呈现没有失真并填满整个空间。 In my case, I was fine with some "cropping" of tall, skinny images, so I used the content mode .scaleAspectFill 在我的情况下,我对一些高瘦的图像进行“裁剪”很好,所以我使用了内容模式.scaleAspectFill

To do this, I created a custom subclass of UITableViewCell . 为此,我创建了一个UITableViewCell的自定义子类。 In my case, I named it StoryTableViewCell . 在我的例子中,我将其命名为StoryTableViewCell The entire class is pasted below, with comments inline. 整个班级都粘贴在下面,内联评论。

This approach worked for me when also using a custom Accessory View and long text labels. 当使用自定义附件视图和长文本标签时,这种方法对我有用。 Here's an image of the final result: 这是最终结果的图像:

Rendered Table View with consistent image width 呈现具有一致图像宽度的表视图

class StoryTableViewCell: UITableViewCell {

    override func layoutSubviews() {
        super.layoutSubviews()

        // ==== Step 1 ====
        // ensure we have an image
        guard let imageView = self.imageView else {return}

        // create a variable for the desired image width
        let desiredWidth:CGFloat = 70;

        // get the width of the image currently rendered in the cell
        let currentImageWidth = imageView.frame.size.width;

        // grab the width of the entire cell's contents, to be used later
        let contentWidth = self.contentView.bounds.width

        // ==== Step 2 ====
        // only update the image's width if the current image width isn't what we want it to be
        if (currentImageWidth != desiredWidth) {
            //calculate the difference in width
            let widthDifference = currentImageWidth - desiredWidth;

            // ==== Step 3 ====
            // Update the image's frame,
            // maintaining it's original x and y values, but with a new width
            self.imageView?.frame = CGRect(imageView.frame.origin.x,
                                           imageView.frame.origin.y,
                                           desiredWidth,
                                           imageView.frame.size.height);

            // ==== Step 4 ====
            // If there is a texst label, we want to move it's x position to
            // ensure it isn't overlapping with the image, and that it has proper spacing with the image
            if let textLabel = self.textLabel
            {
                let originalFrame = self.textLabel?.frame

                // the new X position for the label is just the original position,
                // minus the difference in the image's width
                let newX = textLabel.frame.origin.x - widthDifference
                self.textLabel?.frame = CGRect(newX,
                                               textLabel.frame.origin.y,
                                               contentWidth - newX,
                                               textLabel.frame.size.height);
                print("textLabel info: Original =\(originalFrame!)", "updated=\(self.textLabel!.frame)")
            }

            // ==== Step 4 ====
            // If there is a detail text label, do the same as step 3
            if let detailTextLabel = self.detailTextLabel {
                let originalFrame = self.detailTextLabel?.frame
                let newX = detailTextLabel.frame.origin.x-widthDifference
                self.detailTextLabel?.frame = CGRect(x: newX,
                                                     y: detailTextLabel.frame.origin.y,
                                                     width: contentWidth - newX,
                                                     height: detailTextLabel.frame.size.height);
                print("detailLabel info: Original =\(originalFrame!)", "updated=\(self.detailTextLabel!.frame)")
            }

            // ==== Step 5 ====
            // Set the image's content modoe to scaleAspectFill so it takes up the entire view, but doesn't get distorted
            self.imageView?.contentMode = .scaleAspectFill;
        }
    }
}

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

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