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

后端 未结 16 2429
不思量自难忘°
不思量自难忘° 2020-11-27 10:27

I have a bunch of images I am using for cell\'s image views, they are all no bigger than 50x50. e.g. 40x50, 50x32, 20x37 .....

When I load the table view, the tex

相关标签:
16条回答
  • 2020-11-27 10:43

    The regular UITableViewCell works well to position things but the cell.imageView doesn't seem to behave like you want it to. 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

    // 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

    // 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. Be the size you want it regardless of the image you give it. This should go in tableView:cellForRowAtIndexPath:

    0 讨论(0)
  • 2020-11-27 10:46

    A Simply Swift,

    Step 1: Create One SubClass of UITableViewCell
    Step 2: Add this method to SubClass of UITableViewCell

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

    Step 3: Create cell object using that SubClass in cellForRowAtIndexPath,

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

    Step 4: Enjoy

    0 讨论(0)
  • 2020-11-27 10:46

    I've created an extension using @GermanAttanasio 's answer. 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
        }
    }
    
    0 讨论(0)
  • 2020-11-27 10:47

    For those of you who don't have a subclass of 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.

    Swift 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:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     [...]
    
          CGSize itemSize = CGSizeMake(40, 40);
          UIGraphicsBeginImageContextWithOptions(itemSize, NO, 0.0)          
     [...]
         return cell;
    }
    

    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.

    0 讨论(0)
  • 2020-11-27 10:51

    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;
    }
    
    0 讨论(0)
  • 2020-11-27 10:51

    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

    The problem that we are trying to solve is that we may have images with different aspect ratios in our TableViewCells but we want them to render with consistent widths. 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

    To do this, I created a custom subclass of UITableViewCell. In my case, I named it 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;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题