You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 21:44:51