UITabBar服务器下载图标模糊,本地资源图标显示正常
解决方案:UITabBar 网络下载图标模糊问题
核心问题分析
问题根源在于图片缩放未适配Retina屏幕、循环变量捕获逻辑错误,同时图片渲染模式设置不统一,以下是具体修复步骤:
1. 修复图片缩放方法(适配Retina屏幕)
原代码使用UIGraphicsBeginImageContext创建绘图上下文,默认采用非Retina的scale(1.0),导致生成的图片分辨率不足,在Retina屏上显示模糊。替换为UIGraphicsBeginImageContextWithOptions并传入当前屏幕的scale值:
Objective-C 修复版
-(UIImage*) resizeImageForTabbarItem:(UIImage*)image scaledToSize:(CGSize)newSize { CGFloat scale = [UIScreen mainScreen].scale; CGSize retinaSize = CGSizeMake(newSize.width * scale, newSize.height * scale); UIGraphicsBeginImageContextWithOptions(retinaSize, NO, scale); CGRect rect = CGRectMake(0, 0, retinaSize.width, retinaSize.height); CGFloat widthRatio = image.size.width / retinaSize.width; CGFloat heightRatio = image.size.height / retinaSize.height; CGFloat divisor = widthRatio > heightRatio ? widthRatio : heightRatio; CGFloat drawWidth = image.size.width / divisor; CGFloat drawHeight = image.size.height / divisor; // 居中绘制图片 rect.size.width = drawWidth; rect.size.height = drawHeight; rect.origin.x = (retinaSize.width - drawWidth) / 2; rect.origin.y = (retinaSize.height - drawHeight) / 2; [image drawInRect:rect]; UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return smallImage; }
Swift 修复版
func resizeImageForTabbarItem(_ image: UIImage, scaledToSize newSize: CGSize) -> UIImage { let scale = UIScreen.main.scale let retinaSize = CGSize(width: newSize.width * scale, height: newSize.height * scale) UIGraphicsBeginImageContextWithOptions(retinaSize, false, scale) let rect = CGRect(x: 0, y: 0, width: retinaSize.width, height: retinaSize.height) let widthRatio = image.size.width / retinaSize.width let heightRatio = image.size.height / retinaSize.height let divisor = max(widthRatio, heightRatio) let drawWidth = image.size.width / divisor let drawHeight = image.size.height / divisor var drawRect = rect drawRect.size.width = drawWidth drawRect.size.height = drawHeight drawRect.origin.x = (retinaSize.width - drawWidth) / 2 drawRect.origin.y = (retinaSize.height - drawHeight) / 2 image.draw(in: drawRect) let smallImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() return smallImage }
2. 修复循环变量捕获问题
原循环中异步任务的completion block捕获的是循环变量i的引用,当任务完成时循环可能已经结束,i的值会超出数组范围,导致错误设置TabBarItem。通过创建局部变量或枚举遍历解决:
Objective-C 修复版(局部变量捕获)
for (int i=0; i<[tabbarItemImageArray count]; i++) { // 创建局部变量保存当前索引,避免block捕获引用导致的索引错误 NSInteger currentIndex = i; NSURL *imageURL = tabbarItemImageArray[currentIndex]; NSURLSession *session = [NSURLSession sharedSession]; [[session dataTaskWithURL:imageURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) return; // 直接设置图片的scale为屏幕scale,提升初始清晰度 UIImage *imagemain = [UIImage imageWithData:data scale:[UIScreen mainScreen].scale]; dispatch_async(dispatch_get_main_queue(), ^(){ if (currentIndex >= self.tabBarController.tabBar.items.count) return; if (imagemain != nil && currentIndex < 5) { UIImage *resizedImage = [[WSUtils sharedObject] resizeImageForTabbarItem:imagemain scaledToSize:CGSizeMake(25,25)]; // 统一设置渲染模式为AlwaysOriginal,避免系统tint影响 self.tabBarController.tabBar.items[currentIndex].image = [resizedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; self.tabBarController.tabBar.items[currentIndex].selectedImage = [resizedImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; } self.tabBarController.tabBar.items[currentIndex].title = tabbarItemNameArray[currentIndex]; self.tabBarController.tabBar.unselectedItemTintColor = [UIColor colorWithRed:35/255.0 green:63/255.0 blue:136/255.0 alpha:1.0]; }); }] resume]; }
Swift 修复版(枚举遍历)
for (currentIndex, imageURL) in tabbarItemImageArray.enumerated() { let session = URLSession.shared session.dataTask(with: imageURL) { data, response, error in guard let data = data, error == nil else { return } // 直接设置图片scale为屏幕scale let imagemain = UIImage(data: data, scale: UIScreen.main.scale) DispatchQueue.main.async { guard currentIndex < self.tabBarController.tabBar.items?.count ?? 0 else { return } guard currentIndex < 5, let imagemain = imagemain else { self.tabBarController.tabBar.items?[currentIndex].title = self.tabbarItemNameArray[currentIndex] return } let resizedImage = self.resizeImageForTabbarItem(imagemain, scaledToSize: CGSize(width:25, height:25)) self.tabBarController.tabBar.items?[currentIndex].image = resizedImage.withRenderingMode(.alwaysOriginal) self.tabBarController.tabBar.items?[currentIndex].selectedImage = resizedImage.withRenderingMode(.alwaysOriginal) self.tabBarController.tabBar.items?[currentIndex].title = self.tabbarItemNameArray[currentIndex] self.tabBarController.tabBar.unselectedItemTintColor = UIColor(red: 35/255.0, green: 63/255.0, blue: 136/255.0, alpha: 1.0) } }.resume() }
3. 额外优化建议
- 对下载的图片做本地缓存,避免重复下载,同时提升页面加载速度
- 确保服务器返回的图片本身分辨率足够(建议至少为目标尺寸的2-3倍,适配不同屏幕)
内容的提问来源于stack exchange,提问作者nadim
相关产品推荐
相关产品推荐

