如何缩放容器UIView而不影响内部子视图?附代码实现
解决容器视图缩放时内部视图不受影响的问题
我懂你的需求:长按缩放蓝色容器视图时,中间的红色视图要保持原尺寸不变。目前的问题在于,当你给viewIWantToScale应用CGAffineTransform缩放时,它的子视图viewIDontWantToScale会自动继承这个变换——哪怕你设置了autoresizesSubviews = false也没用,因为transform是视图层级的几何变换,和自动布局的 autoresizing 机制完全是两回事。
下面给你两种可行的解决方案:
方案一:将内部视图移到容器视图的同级(推荐)
这种方式最直接,把红色视图从蓝色视图的子视图改成父视图的同级,再用约束绑定到蓝色视图的中心和固定尺寸。这样蓝色视图缩放时,红色视图完全不受影响,因为它不在蓝色视图的层级里。
修改后的完整代码示例:
let viewIWantToScale = UIView() let viewIDontWantToScale = UIView() private func configureViewIWantToScale() { let tabDetector = UILongPressGestureRecognizer(target: self, action: #selector(gestureAction(_:))) viewIWantToScale.translatesAutoresizingMaskIntoConstraints = false; viewIWantToScale.addGestureRecognizer(tabDetector) // 红色视图不再是子视图,这个设置可以去掉 // viewIWantToScale.autoresizesSubviews = false view.addSubview(viewIWantToScale) NSLayoutConstraint.activate([ viewIWantToScale.centerYAnchor.constraint(equalTo: view.centerYAnchor), viewIWantToScale.centerXAnchor.constraint(equalTo: view.centerXAnchor), viewIWantToScale.widthAnchor.constraint(equalToConstant: 300), viewIWantToScale.heightAnchor.constraint(equalToConstant: 300) ]) viewIWantToScale.backgroundColor = .blue } private func configureViewIDontWantToScale() { viewIDontWantToScale.translatesAutoresizingMaskIntoConstraints = false; viewIDontWantToScale.isUserInteractionEnabled = false view.addSubview(viewIDontWantToScale) // 和蓝色视图同级添加到父视图 NSLayoutConstraint.activate([ viewIDontWantToScale.centerYAnchor.constraint(equalTo: viewIWantToScale.centerYAnchor), viewIDontWantToScale.centerXAnchor.constraint(equalTo: viewIWantToScale.centerXAnchor), viewIDontWantToScale.widthAnchor.constraint(equalToConstant: 150), viewIDontWantToScale.heightAnchor.constraint(equalToConstant: 150) ]) viewIDontWantToScale.backgroundColor = .red } @objc private func gestureAction(_ sender: UILongPressGestureRecognizer) { switch sender.state { case .began, .changed: // 示例缩放1.5倍,你可以根据需求调整倍数 UIView.animate(withDuration: 1) { self.viewIWantToScale.transform = CGAffineTransform(scaleX: 1.5, y: 1.5) } case .ended, .cancelled: // 恢复原尺寸 UIView.animate(withDuration: 1) { self.viewIWantToScale.transform = .identity } default: break } }
方案二:给内部视图应用反向变换(适合必须保留父子层级的场景)
如果因为某些业务限制,必须把红色视图放在蓝色视图内部,那你可以在蓝色视图缩放的同时,给红色视图应用反向的缩放变换,抵消父视图的缩放效果。
修改后的手势处理代码示例:
@objc private func gestureAction(_ sender: UILongPressGestureRecognizer) { let targetScale: CGFloat = 1.5 // 容器视图的目标缩放倍数 switch sender.state { case .began, .changed: UIView.animate(withDuration: 1) { self.viewIWantToScale.transform = CGAffineTransform(scaleX: targetScale, y: targetScale) // 用1/目标倍数做反向缩放,抵消父视图的缩放 self.viewIDontWantToScale.transform = CGAffineTransform(scaleX: 1/targetScale, y: 1/targetScale) } case .ended, .cancelled: UIView.animate(withDuration: 1) { self.viewIWantToScale.transform = .identity self.viewIDontWantToScale.transform = .identity } default: break } }
注意:这种方式要确保红色视图的约束是绑定到父视图的中心,这样反向变换后它的位置不会偏移。
内容的提问来源于stack exchange,提问作者Omar Ghanem
相关产品推荐
相关产品推荐

