UITableView中UIImageView的contentMode异常切换问题求助
我之前也碰到过类似的Cell复用结合SDWebImage的诡异布局问题,结合你的描述和代码,应该是Cell复用状态重置不彻底+SDWebImage异步加载时机与Cell布局回调的冲突导致的,给你几个针对性的解决方案:
1. 从Cell初始化阶段锁定ContentMode
首先检查你的CommentsCell.xib,如果xib里photoImageView的默认ContentMode是ScaleAspectFit,那即使你在cellForRow里设置,也可能被xib的初始化值或者布局回调覆盖。
在CommentsCell的awakeFromNib方法里强制设置默认ContentMode,同时开启clipsToBounds避免图片溢出:
- (void)awakeFromNib { [super awakeFromNib]; // 初始化时就锁定ContentMode self.photoImageView.contentMode = UIViewContentModeScaleAspectFill; self.photoImageView.clipsToBounds = YES; }
2. 完善Cell复用的状态重置逻辑
复用Cell时,一定要彻底重置所有可能影响布局的属性,避免残留状态干扰。在CommentsCell的prepareForReuse里补充重置:
- (void)prepareForReuse { [super prepareForReuse]; // 重置ImageView状态 self.photoImageView.contentMode = UIViewContentModeScaleAspectFill; self.photoImageView.hidden = NO; self.imageHeight.constant = 0; // 取消当前未完成的图片加载 [self.photoImageView sd_cancelCurrentImageLoad]; self.photoImageView.image = nil; // 重置TextView状态 self.textview.text = @""; }
3. 优化cellForRow中的逻辑,覆盖所有场景
在cellForRowAtIndexPath里,不管当前Cell是否需要显示图片,都先统一设置ContentMode,再处理具体的显示逻辑,同时在SDWebImage加载完成后再次确认:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *identifier = @"CommentsCell"; CommentsCell *cell =(CommentsCell *) [self.tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { NSArray *nib = [[NSBundle mainBundle] loadNibNamed:identifier owner:self options:nil]; cell = [nib objectAtIndex:0]; // 初始化Cell时额外设置一次,双重保险 cell.photoImageView.contentMode = UIViewContentModeScaleAspectFill; cell.photoImageView.clipsToBounds = YES; } CommentsModel *commentsModel =(CommentsModel *)commentsListArray[indexPath.row]; // 先重置基础状态,避免复用残留 cell.photoImageView.contentMode = UIViewContentModeScaleAspectFill; cell.photoImageView.hidden = NO; cell.textview.text = @""; if (commentsModel.hasImage) { cell.imageHeight.constant=150; NSString *imageUrl = commentsModel.commentImage; [cell.photoImageView setShowActivityIndicatorView:YES]; [cell.photoImageView setIndicatorStyle:UIActivityIndicatorViewStyleGray]; // 加载完成后再次确认ContentMode,防止布局回调修改 [cell.photoImageView sd_setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { cell.photoImageView.contentMode = UIViewContentModeScaleAspectFill; }]; } else { cell.imageHeight.constant=0; cell.photoImageView.hidden = YES; cell.textview.text=commentsModel.comments; [cell.textview sizeToFit]; } cell.transform = self.tableView.transform; return cell; }
4. 应对布局回调的兜底方案
因为你提到弹出UIAlertController时ContentMode会自动修正,这说明布局刷新(比如layoutSubviews)会触发正确的ContentMode设置。可以在CommentsCell的layoutSubviews里做最后兜底:
- (void)layoutSubviews { [super layoutSubviews]; // 每次布局都强制锁定ContentMode self.photoImageView.contentMode = UIViewContentModeScaleAspectFill; }
问题根源解释
弹出AlertController时,系统会触发当前ViewController的viewWillLayoutSubviews/viewDidLayoutSubviews,进而触发TableView和Cell的布局刷新,这时候你的ContentMode设置才真正生效——说明之前的设置被Cell的布局回调(比如xib初始化、复用后的布局更新)给覆盖了,所以需要在多个生命周期节点强制锁定ContentMode。
内容的提问来源于stack exchange,提问作者bjg

