UIView中使用CGAffineTransform缩放不生效问题排查
为什么修改CGAffineTransform的缩放参数后视图显示无变化?
在以下Swift代码中,无论给CGAffineTransform(scaleX:y:)传入任何缩放参数,最终视图的绘制结果都完全一致,请问这一现象的原因是什么?
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .gray } override func viewWillAppear(_ animated: Bool) { let scalingView = ScalingView(frame: self.view.bounds) self.view.addSubview(scalingView) } }
import UIKit class ScalingView: UIView { let subview: UIView! override init(frame: CGRect) { subview = UIView() super.init(frame: frame) addSubview(subview) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { subview.backgroundColor = .white let subviewSize = 100 subview.frame.size = CGSize(width: subviewSize, height: subviewSize) subview.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) subview.transform = CGAffineTransform(scaleX: 1, y: 1) } }
现象
分别设置以下缩放参数时,视图显示结果没有差异:
subview.transform = CGAffineTransform(scaleX: 1, y: 1)subview.transform = CGAffineTransform(scaleX: 2, y: 2)subview.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
原因分析
核心问题出在设置transform前直接修改了subview的frame属性。
在UIKit的布局逻辑里,frame是一个复合计算属性,它由视图的bounds(原始尺寸)、center(位置)和transform(变换)共同决定。当你先固定frame.size和center,再应用transform时,UIKit会自动反向调整视图的bounds来抵消变换的影响——因为frame代表的是视图在父视图中最终显示的区域范围,为了维持你设置的frame大小,UIKit会修改未变换前的原始尺寸,最终导致视觉上看不到缩放效果。
举个实际例子:当你设置缩放倍数为2时,UIKit会把subview的原始尺寸自动改成50x50,经过2倍缩放后,最终显示的尺寸还是100x100,和缩放倍数为1时的视觉效果完全一致。
修正方案
想要让缩放变换正常生效,应该用bounds设置视图的原始尺寸,再应用transform;或者先设置transform,再调整center(不要直接修改frame)。比如修改layoutSubviews方法如下:
override func layoutSubviews() { subview.backgroundColor = .white let subviewSize = 100 // 使用bounds定义原始尺寸,而非frame subview.bounds = CGRect(x: 0, y: 0, width: subviewSize, height: subviewSize) subview.center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) subview.transform = CGAffineTransform(scaleX: 2, y: 2) }
这样修改后,缩放变换就能正常起作用,视图会显示为200x200的大小。
内容的提问来源于stack exchange,提问作者Kentaro Kawai
相关产品推荐
相关产品推荐

