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)
关键优化点说明
- 用
SymbolConfiguration缩放图标:这是苹果官方推荐的SF Symbols缩放方式,既能精准控制大小,又能保持矢量图的清晰度,完全不会变形。 - 设置
contentMode = .center:让图标在视图内居中显示,避免被强制拉伸填充整个视图。 - 在
layoutSubviews中更新阴影路径:初始化时视图的bounds可能还未正确设置,重写这个方法能保证视图大小变化时阴影始终正确。 - 动态计算图标大小:通过
min(self.bounds.width, self.bounds.height) * 0.6让图标大小随视图尺寸自适应,不用硬写固定值。
内容的提问来源于stack exchange,提问作者user12473575
相关产品推荐
相关产品推荐

