J'ai un tas d'images que j'utilise pour les vues d'image de cellule, elles ne sont pas toutes plus grandes que 50x50. par exemple. 40x50, 50x32, 20x37 .....
Lorsque je charge la vue tabulaire, le texte ne s'aligne pas car la largeur des images varie. Aussi, j'aimerais que les petites images apparaissent au centre et non à gauche.
Voici le code que j'essaie dans ma méthode '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];
Comme vous pouvez le constater, j'ai essayé plusieurs solutions, mais aucune d'entre elles ne fonctionne.
Il n'est pas nécessaire de tout réécrire. Je recommande de faire ceci à la place:
Postez ceci dans votre fichier .m de votre cellule personnalisée.
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake(0,0,32,32);
}
Cela devrait faire l'affaire bien. :]
Pour ceux d'entre vous qui n'ont pas de sous-classe de 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;
}
Le code ci-dessus définit la taille à 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();
Ou vous pouvez utiliser une autre approche (non testée) suggérée par @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();
Le code ci-dessus est la version Swift 3+ de ce qui précède.
Voici comment je l'ai fait. Cette technique permet de déplacer le texte et les étiquettes de texte de détail de manière appropriée vers la gauche:
@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;
}
ajouter une vue en tant que vue secondaire à la cellule 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];
La cellule entière n'a pas besoin d'être refaite. Vous pouvez utiliser les propriétés indentationLevel et indentationWidth de tableViewCells pour déplacer le contenu de votre cellule. Ensuite, vous ajoutez votre imageView personnalisée sur le côté gauche de la cellule.
Un Simply Swift ,
Étape 1: Créer une sous-classe de UITableViewCell
Étape 2: Ajouter cette méthode à la sous-classe de UITableViewCell
override func layoutSubviews() {
super.layoutSubviews()
self.imageView?.frame = CGRectMake(0, 0, 10, 10)
}
Étape 3: Créer un objet de cellule à l'aide de cette sous-classe dans cellForRowAtIndexPath
,
Ex: let customCell:CustomCell = CustomCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell")
Étape 4: Profitez
Créez mieux une vue d’image et ajoutez-la en tant que sous-vue à la cellule. Vous pouvez ensuite obtenir la taille de cadre souhaitée.
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;
}
J'ai créé une extension en utilisant la réponse de @GermanAttanasio. Il fournit une méthode pour redimensionner une image à la taille souhaitée et une autre pour l’ajouter tout en ajoutant une marge transparente à l’image (cela peut être utile pour les vues sous forme de tableau où l’image doit également avoir une marge).
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
}
}
Cela a fonctionné pour moi à Swift:
Créez une sous-classe de UITableViewCell (assurez-vous de relier votre cellule au storyboard)
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)
}
}
}
Dans cellForRowAtIndexPath, retirez la cellule de votre nouveau type de cellule:
let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! MyTableCell
Évidemment, changez les valeurs numériques en fonction de votre mise en page
Cette solution dessine essentiellement l’image en "ajustement d’aspect" dans le rect donné.
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();
Si vous utilisez cell.imageView?.translatesAutoresizingMaskIntoConstraints = false
, vous pouvez définir des contraintes sur l'imageView. Voici un exemple de travail que j'ai utilisé dans un projet. J'évitais les sous-classes et je n'avais pas besoin de créer de story-board avec des cellules prototypes, mais cela me prenait un bon bout de temps avant de fonctionner. Il est donc préférable de ne l'utiliser que s'il n'existe pas de moyen plus simple ou plus concis.
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
}
Voici la méthode de travail de @germanattanasio, écrite pour 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()
}
UITableViewCell standard fonctionne bien pour positionner des objets, mais cell.imageView ne semble pas se comporter comme vous le souhaitez. J'ai trouvé qu'il était assez simple de placer correctement UITableViewCell en donnant d'abord à cell.imageView une image correctement dimensionnée comme
// 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;
Ensuite, vous pouvez simplement connecter votre propre UIImageView qui fonctionne correctement avec
// 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];
}
Définissez l'image sur une imageImageView et il fera ce que vous attendez d'un UIImageView. Soyez la taille que vous voulez, peu importe l'image que vous lui donnez. Cela devrait aller dans tableView: cellForRowAtIndexPath:
J'ai eu le même problème. Merci à tous ceux qui ont répondu - j'ai pu trouver une solution en utilisant des parties de plusieurs de ces réponses.
Ma solution utilise Swift 5
Le problème que nous essayons de résoudre est qu’il est possible que nous ayons des images avec différents formats d’image dans notre TableViewCell
s, mais nous voulons qu’elles rendent le rendu avec des largeurs cohérentes. Bien entendu, les images doivent être restituées sans distorsion et occuper tout l’espace. Dans mon cas, je me débrouillais bien avec quelques "recadrages" d'images hautes et maigres, alors j'ai utilisé le mode contenu .scaleAspectFill
Pour ce faire, j'ai créé une sous-classe personnalisée de UITableViewCell
. Dans mon cas, je l'ai nommé StoryTableViewCell
. La classe entière est collée ci-dessous, avec des commentaires en ligne.
Cette approche a fonctionné pour moi lorsque j'utilisais également une vue d'accessoire personnalisée et de longues étiquettes de texte. Voici une image du résultat final:
Affichage du tableau avec une largeur d'image constante
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;
}
}
}