如何维持已移动UILabel的位置?避免新增标签时约束影响
解决方案
问题核心:第一个标签拖动后,原有的center.equalToSuperview()约束仍然生效,添加新标签触发布局更新时,旧约束会将标签拉回初始位置。需要在拖动结束后移除或更新这些约束,让标签位置固定。
方法一:更新AutoLayout约束(推荐)
通过维护每个标签的约束引用,在拖动结束后替换为当前位置的固定约束,符合AutoLayout规范。
步骤1:定义结构体保存标签与约束
struct DraggableLabel { let label: UILabel var centerConstraints: [NSLayoutConstraint]? } // 替换原有的labelList var draggableLabels: [DraggableLabel] = []
步骤2:修改添加标签的代码,保存约束
@IBAction func touchAddText(_ sender: Any) { logp("touchAddText") let newLabel = UILabel() newLabel.text = "Text" newLabel.isUserInteractionEnabled = true newLabel.tag = self.draggableLabels.count + 1 let panGesture = self.setGesture() newLabel.addGestureRecognizer(panGesture) self.containerMain.addSubview(newLabel) // 创建并保存初始center约束 let constraints = newLabel.snp.makeConstraints { $0.center.equalToSuperview() } self.draggableLabels.append(DraggableLabel(label: newLabel, centerConstraints: constraints)) }
步骤3:修改手势处理逻辑,拖动结束时更新约束
func setGesture() -> UIPanGestureRecognizer { let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))) return pan } @objc func handlePan(_ gesture: UIPanGestureRecognizer) { guard let label = gesture.view as? UILabel else { return } let translation = gesture.translation(in: containerMain) label.center = CGPoint(x: label.center.x + translation.x, y: label.center.y + translation.y) gesture.setTranslation(.zero, in: containerMain) if gesture.state == .ended { // 找到对应标签的约束引用 guard let index = draggableLabels.firstIndex(where: { $0.label == label }) else { return } // 禁用旧约束 draggableLabels[index].centerConstraints?.forEach { $0.isActive = false } // 添加当前位置的固定约束 let newConstraints = label.snp.makeConstraints { $0.center.equalTo(label.center) } // 更新约束引用 draggableLabels[index].centerConstraints = newConstraints } }
方法二:切换为Frame控制(简单场景)
拖动开始时禁用AutoLayout,让标签直接通过Frame控制位置,无需维护约束。
@objc func handlePan(_ gesture: UIPanGestureRecognizer) { guard let label = gesture.view as? UILabel else { return } switch gesture.state { case .began: // 启用Frame控制,禁用AutoLayout约束 label.translatesAutoresizingMaskIntoConstraints = true label.removeConstraints(label.constraints) case .changed: let translation = gesture.translation(in: containerMain) label.center = CGPoint(x: label.center.x + translation.x, y: label.center.y + translation.y) gesture.setTranslation(.zero, in: containerMain) default: break } }
两种方法对比
- 方法一:完全遵循AutoLayout规则,后续容器尺寸变化时可灵活调整标签位置,适合复杂布局场景。
- 方法二:实现简单,无需维护约束引用,适合不需要AutoLayout联动的基础场景。
内容的提问来源于stack exchange,提问作者Furang Moon
相关产品推荐
相关产品推荐

