如何在 panGesture 之后修复新的 textField 位置?

Posted

技术标签:

【中文标题】如何在 panGesture 之后修复新的 textField 位置?【英文标题】:How to fix a new textField position after panGesture? 【发布时间】:2019-01-12 20:59:42 【问题描述】:

我需要一些帮助来解决我的代码中的垃圾问题。 我有一个视图,顶部有两个 textField,底部有另一个,都在 imageView 上。 我在两个文本字段中都应用了平移手势,以允许在用户加载图像后更改它们的位置。 但是当我显示一个活动视图来共享新图像时,文本字段会返回以前的位置。 我想在 panGesture 之后将它们修复到新位置。 我能做些什么?或者我忘了做什么?

   This is my Pan Gesture Action
@IBAction func didPanTfTop(_ sender: UIPanGestureRecognizer) 

    let translation = sender.translation(in: self.view)

    if sender.state == .began 
        print("Gesture began")
        textFieldOriginalCenter = tfTop.center
     else if sender.state == .changed 
        print("Gesture is changed")
        tfTop.center = CGPoint(x: textFieldOriginalCenter.x + translation.x, y: textFieldOriginalCenter.y + translation.y)
     else if sender.state == .ended 
        print("Gesture ended")

    

这是我的 activityView 方法...

@IBAction func share(_ sender: UIBarButtonItem) 
    Feedback.share.hapticFeedback()
    let memeImage = generateMemedImage()
    let activityView = UIActivityViewController(activityItems: [memeImage], applicationActivities: nil)
    activityView.completionWithItemsHandler =  (activityType: UIActivity.ActivityType?, completed: Bool, returnedItems: [Any]?, error: Error?) -> Void in

        if completed 
            self.save()
            print("Image has saved")
        
    
    present(activityView, animated: true, completion: nil)

【问题讨论】:

你能给我一些提示吗?我尝试了一些选项,但以我目前的知识有点困难但我仍在尝试。 :) 好的,Rob,非常感谢您的关注。 【参考方案1】:

一般来说,看到视图快速回到其原始位置的这种行为是以下因素组合的结果: (a) 使用自动布局约束; (b) 做一些触发重新应用约束的事情。这种重新应用约束的过程有时可以由最无害的 UI 操作触发。最重要的是,与其担心是什么触发了重新应用约束,最好确保您的视图将保持在您想要的位置,即使发生这种情况。

一种解决方案是更新视图的transform 而不是center,例如:

var originalTransform: CGAffineTransform!

@IBAction func handlePan(_ gesture: UIPanGestureRecognizer) 
    switch gesture.state 
    case .began:
        originalTransform = gesture.view!.transform

    case .changed, .ended:
        let translation = gesture.translation(in: gesture.view)
        gesture.view?.transform = originalTransform.translatedBy(x: translation.x, y: translation.y)

    default:
        break
    

这种技术有效,但也感觉有点脆弱,依赖于约束和视图转换之间记录不充分的行为。

另一种更健壮但更复杂的方法是调整约束的constant 属性。例如,您可以为约束本身创建 @IBOutlet 引用,在 IB 中连接这些出口,然后您的手势识别器可以相应地更新它们的 constant 属性:

@IBOutlet weak var horizontalConstraint: NSLayoutConstraint!
@IBOutlet weak var verticalConstraint: NSLayoutConstraint!

private var originalHorizontalConstant: CGFloat!
private var originalVerticalConstant: CGFloat!

@IBAction func handlePan(_ gesture: UIPanGestureRecognizer) 
    switch gesture.state 
    case .began:
        originalHorizontalConstant = horizontalConstraint.constant
        originalVerticalConstant = verticalConstraint.constant

    case .changed, .ended:
        let translation = gesture.translation(in: gesture.view)
        horizontalConstraint.constant = originalHorizontalConstant + translation.x
        verticalConstraint.constant = originalVerticalConstant + translation.y

    default:
        break
    

现在,很明显,如果您可能在此周围拖动不同的视图可能会变得有点混乱,但希望以上说明了基本想法。

无论您应用哪种技术,基本概念是避免更新其位置由自动布局约束决定的视图的centerframe

【讨论】:

第一个解决方案对我来说效果很好,但我对第二个解决方案有疑问。我的代码中的每个 TextField 都有三个约束(顶部或底部,左右)。我相信要按照您的建议实现@IBOutlets 水平约束和垂直约束,我必须删除原始约束,只保留这两个新约束。我说的对吗? 不,你总是想更新 constant(Apple 不鼓励添加和删除约束)如果这些是你的约束,你可以用 translation.x 和 top 更改左右约束的常量和底部约束的常量为translation.y。在我的示例中,我有顶部、高度、左侧和宽度,因此我只需要调整顶部和左侧即可达到相同的效果。 很棒的罗伯。我现在明白你的建议了。我使用了这两个选项,一切都运行良好。非常感谢!!!

以上是关于如何在 panGesture 之后修复新的 textField 位置?的主要内容,如果未能解决你的问题,请参考以下文章

如何取消 LongPressGesture 以便 PanGesture 可以识别

如何允许在某个区域拖动 UIView (PanGesture ..)

如何实现多个 PanGestures(可拖动视图)?

如何将按钮中的 panGesture 传递给 tableView? (斯威夫特 4)

如何使用 panGesture 从 firstViewController 的顶部移动 secondViewController?

如何以编程方式快速发送 pangesture