拖动后的UICollectionView按钮随滚动复位问题求助
解决拖动按钮滚动UICollectionView或视图切换后位置重置的问题
问题出在两个核心点:一是直接修改按钮的center会被Auto Layout约束覆盖(滚动或视图布局更新时,约束会强制按钮回到初始位置);二是没有持久化拖动后的位置,视图切换后无法恢复状态。
以下是完整解决方案:
1. 核心修改思路
- 放弃直接修改
center,改为修改按钮的位置约束,让布局系统认可新位置 - 用
UserDefaults持久化按钮的最终位置,确保视图切换后能恢复
2. 修改后的代码
首先添加必要属性:
var panGesture = UIPanGestureRecognizer() // 关联按钮的位置约束(Storyboard创建的话直接拖线关联,代码创建则手动初始化) private var buttonCenterXConstraint: NSLayoutConstraint! private var buttonCenterYConstraint: NSLayoutConstraint! // 存储位置的UserDefaults键 private let buttonPositionStorageKey = "DraggedRightMenuBtnCenter"
初始化视图和手势:
override func viewDidLoad() { super.viewDidLoad() // --- 代码创建按钮时的约束设置(Storyboard创建可跳过,直接拖线关联约束)--- rightMenuColllapsedBtn.translatesAutoresizingMaskIntoConstraints = false view.addSubview(rightMenuColllapsedBtn) buttonCenterXConstraint = rightMenuColllapsedBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor) buttonCenterYConstraint = rightMenuColllapsedBtn.centerYAnchor.constraint(equalTo: view.centerYAnchor) NSLayoutConstraint.activate([buttonCenterXConstraint, buttonCenterYConstraint]) // --- 约束设置结束 --- // 初始化拖拽手势 panGesture = UIPanGestureRecognizer(target: self, action: #selector(draggedView(_:))) panGesture.delegate = self rightMenuColllapsedBtn.isUserInteractionEnabled = true rightMenuColllapsedBtn.addGestureRecognizer(panGesture) // 恢复上次保存的按钮位置 restoreButtonPosition() }
更新拖拽处理方法,修改约束而非直接改center:
@objc func draggedView(_ sender: UIPanGestureRecognizer) { view.bringSubviewToFront(rightMenuColllapsedBtn) let translation = sender.translation(in: view) // 通过修改约束的constant值来更新位置,避免被布局系统覆盖 buttonCenterXConstraint.constant += translation.x buttonCenterYConstraint.constant += translation.y sender.setTranslation(CGPoint.zero, in: view) // 拖拽结束时保存当前位置 if sender.state == .ended { saveButtonPosition() } }
添加位置持久化和恢复方法:
private func saveButtonPosition() { let center = rightMenuColllapsedBtn.center UserDefaults.standard.setValue(center.x, forKey: "\(buttonPositionStorageKey)_x") UserDefaults.standard.setValue(center.y, forKey: "\(buttonPositionStorageKey)_y") } private func restoreButtonPosition() { guard let x = UserDefaults.standard.value(forKey: "\(buttonPositionStorageKey)_x") as? CGFloat, let y = UserDefaults.standard.value(forKey: "\(buttonPositionStorageKey)_y") as? CGFloat else { return } // 计算相对于初始约束的偏移量,更新约束constant let initialCenterX = view.center.x let initialCenterY = view.center.y buttonCenterXConstraint.constant = x - initialCenterX buttonCenterYConstraint.constant = y - initialCenterY }
关键说明
- 约束修改:直接修改
center只是临时改变视图位置,Auto Layout在布局更新(比如滚动UICollectionView触发的layoutSubviews)时会重新应用约束,导致按钮回到初始位置。修改约束的constant值是让布局系统认可新位置的正确方式。 - 持久化存储:
UserDefaults可以简单实现跨视图生命周期的位置保存,如果你需要更复杂的存储逻辑,也可以换成Core Data或文件存储。
内容的提问来源于stack exchange,提问作者NickCoder
相关产品推荐
相关产品推荐

