UIKit中点击按钮导致拖动过的视图复位问题求助
UIKit中点击按钮导致拖动过的视图复位问题求助
嗨,我来帮你分析下这个问题的原因,然后给你两种可行的解决方案~
问题根源
你现在遇到的问题,核心在于Auto Layout和手动修改frame的冲突:
- 你给
littleView设置了translatesAutoresizingMaskIntoConstraints = false,这意味着这个视图的布局由Auto Layout来管理; - 但你拖动时直接修改了
littleView的frame,这只是临时改变了视图的位置,并没有更新Auto Layout的约束; - 当你点击按钮调用
self.view.layoutIfNeeded()时,系统会触发Auto Layout重新计算布局,它会完全忽略你手动修改的frame,按照约束定义的规则把视图放回初始位置(因为你只给littleView设置了宽高约束,位置相关的约束缺失,系统会默认它在左上角)。
解决方案1:让视图脱离Auto Layout管理
如果这个拖动视图不需要和其他Auto Layout元素联动,最简单的办法就是让它不受Auto Layout控制:
- 修改
littleView的初始化代码,把translatesAutoresizingMaskIntoConstraints改成true:
let littleView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = true // 这里改true view.layer.borderColor = UIColor.red.cgColor view.layer.borderWidth = 4 view.isUserInteractionEnabled = true view.backgroundColor = .red return view }()
- 在
viewDidLoad里手动设置它的初始位置和大小,替代原来的宽高约束:
override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(button) self.view.addSubview(littleView) // 设置初始位置和大小 let viewHeight = view.frame.height littleView.frame = CGRect(x: 0, y: 0, width: viewHeight/3, height: viewHeight/5) // 剩下的手势、按钮绑定代码不变... }
这样修改后,Auto Layout就不会再干预这个视图的位置,你拖动修改的frame会一直生效,点击按钮也不会复位了。
解决方案2:用Auto Layout约束控制位置(更规范的做法)
如果你的视图需要和其他Auto Layout元素配合,推荐用约束来管理位置,拖动时修改约束的constant值:
- 先给
littleView添加两个属性来保存位置约束:
final class SampleViewController: UIViewController { private var isTapped: Bool = false private var littleViewLeadingConstraint: NSLayoutConstraint! // 新增 private var littleViewTopConstraint: NSLayoutConstraint! // 新增 // 按钮、littleView的初始化代码不变...
- 在
viewDidLoad里完善littleView的约束,保存leading和top约束:
override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(button) self.view.addSubview(littleView) littleView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))) button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) NSLayoutConstraint.activate([ button.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), littleView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1/5), littleView.widthAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1/3), ]) // 绑定并激活位置约束 littleViewLeadingConstraint = littleView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0) littleViewTopConstraint = littleView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0) littleViewLeadingConstraint.isActive = true littleViewTopConstraint.isActive = true }
- 修改
handlePan方法,通过修改约束的constant来移动视图:
@objc private func handlePan(_ gesture: UIPanGestureRecognizer) { guard let viewToMove = gesture.view else { return } if gesture.state == .began || gesture.state == .changed { let translation = gesture.translation(in: view) // 更新约束的偏移值 littleViewLeadingConstraint.constant += translation.x littleViewTopConstraint.constant += translation.y // 限制视图不能超出父视图范围 let maxX = view.frame.width - viewToMove.frame.width let maxY = view.frame.height - viewToMove.frame.height littleViewLeadingConstraint.constant = max(0, min(maxX, littleViewLeadingConstraint.constant)) littleViewTopConstraint.constant = max(0, min(maxY, littleViewTopConstraint.constant)) gesture.setTranslation(CGPoint.zero, in: view) } }
这样修改后,拖动时是在修改Auto Layout的约束值,当点击按钮触发layoutIfNeeded时,系统会根据更新后的约束重新布局,视图不会复位,完全符合UIKit的布局规范。
备注:内容来源于stack exchange,提问作者mkemalgokce
相关产品推荐
相关产品推荐

