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

StackView中调整图片并保持比例:克隆Apple Maps按钮遇图标变形问题

解决SF Symbols图标变形&过大问题的方案

嘿,我来帮你搞定这个图标变形的问题!你之前尝试用UIGraphicsImageRenderer手动缩放图标的思路绕远了,而且没考虑到图像的比例适配,才导致了变形。其实SF Symbols本身就有一套完美的缩放方案,咱们直接用官方推荐的方式来调整就好。

问题根源分析

你之前用渲染器绘制图标时,直接基于视图的frame做 inset 绘制,既没有保持图标的原始宽高比,又混淆了frame和bounds的区别(初始化时视图的bounds可能还没正确设置),最终导致图标被强制拉伸变形。

修复后的完整代码

第一步:修改CustomView的核心实现

class CustomView: UIImageView { 
    init(frame: CGRect, corners: CACornerMask, systemName: String) { 
        super.init(frame: frame) 
        createBorders(corners: corners) 
        createImage(systemName: systemName) 
    } 
    
    required init?(coder: NSCoder) { 
        fatalError("init(coder:) has not been implemented") 
    } 
    
    func createBorders(corners: CACornerMask) { 
        self.contentMode = .center // 让图标居中,避免拉伸
        self.clipsToBounds = false 
        self.layer.cornerRadius = 10 
        self.layer.maskedCorners = corners 
        self.layer.masksToBounds = false 
        self.layer.shadowOffset = .zero 
        self.layer.shadowColor = UIColor.gray.cgColor 
        self.layer.shadowRadius = 10 
        self.layer.shadowOpacity = 0.2 
        self.backgroundColor = .white 
        self.tintColor = .systemBlue // 设置图标颜色,匹配Apple Maps风格
    } 
    
    func createImage(systemName: String) { 
        // 用官方SymbolConfiguration直接控制图标大小,保持矢量清晰度
        let iconSize = min(self.bounds.width, self.bounds.height) * 0.6 // 占视图60%的大小,可调整
        let config = UIImage.SymbolConfiguration(pointSize: iconSize, weight: .medium)
        guard let image = UIImage(systemName: systemName, withConfiguration: config) else {
            return
        }
        self.image = image.withRenderingMode(.alwaysTemplate)
    }
    
    // 重写layoutSubviews,确保视图大小变化时阴影路径正确
    override func layoutSubviews() {
        super.layoutSubviews()
        let shadowAmount: CGFloat = 2
        let rect = CGRect(x: 0, y: 2, width: self.bounds.width + shadowAmount * 0.1, height: self.bounds.height + shadowAmount * 0.1)
        self.layer.shadowPath = UIBezierPath(rect: rect).cgPath
    }
}

第二步:调整使用代码的视图尺寸

你原来设置的10x10尺寸太小了,Apple Maps的按钮大概是40x40左右,调整后显示更自然:

let size = CGSize(width: 40, height: 40) 
let frame = CGRect(origin: CGPoint(x: 360, y: 45), size: size) 
let infoView = CustomView(frame: frame, corners: [.layerMinXMinYCorner, .layerMaxXMinYCorner], systemName: "info.circle") 
let locationView = CustomView(frame: frame, corners: [], systemName: "location") 
let plusView = CustomView(frame: frame, corners: [.layerMinXMaxYCorner, .layerMaxXMaxYCorner], systemName: "plus.circle") 
let binocularsView = CustomView(frame: frame, corners: [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner], systemName: "binoculars.fill") 
let stackView = UIStackView(arrangedSubviews: [infoView, locationView, plusView, binocularsView]) 
stackView.frame = CGRect(origin: CGPoint(x: 360, y: 45), size: CGSize(width: 45, height: 180)) 
stackView.distribution = .fillEqually 
stackView.axis = .vertical 
stackView.setCustomSpacing(3, after: plusView) 
view.addSubview(stackView)

关键优化点说明

  1. 用SymbolConfiguration缩放图标:这是苹果官方推荐的SF Symbols缩放方式,既能精准控制大小,又能保持矢量图的清晰度,完全不会变形。
  2. 设置contentMode = .center:让图标在视图内居中显示,避免被强制拉伸填充整个视图。
  3. 在layoutSubviews中更新阴影路径:初始化时视图的bounds可能还未正确设置,重写这个方法能保证视图大小变化时阴影始终正确。
  4. 动态计算图标大小:通过min(self.bounds.width, self.bounds.height) * 0.6让图标大小随视图尺寸自适应,不用硬写固定值。

内容的提问来源于stack exchange,提问作者user12473575

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:07:16