【问题标题】:Entering text into textfield causing uipangesture object to move back to its orginal position在文本字段中输入文本导致 uipan 手势对象移回其原始位置
【发布时间】:2020-06-01 22:06:15
【问题描述】:

我下面的 swift 代码有一个连接到 pangesture 的图像视图。当图像视图移动后在文本字段中输入内容时。图像视图恢复到其原始位置。gif 表示正在发生的事情。我只是不希望在文本输入到文本字段后使 pangesutre 的效果无效。

链接到 GITHUB https://github.com/redrock34/sse

import UIKit

class ViewController: UIViewController {

    var pic = UIImageView()
    let fight = (0..<10).map { _ in UIImageView() }
    var textEnter = UITextField()
    var g2 = UIPanGestureRecognizer()

    var slider = UISlider()

    override func viewDidLoad() {
        super.viewDidLoad()

        fight[0].image  = UIImage(named: "a.png")

        fight.forEach{
            $0.isUserInteractionEnabled = true
        }
        [slider,textEnter].forEach{
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)

            $0.backgroundColor = .blue
        }

        slider.backgroundColor = .clear

        g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
        fight[0].addGestureRecognizer(g2)

        pic.backgroundColor = .clear
        pic.backgroundColor = .systemGreen

        fight.forEach{
            $0.backgroundColor = .clear
            view.addSubview($0)
            $0.translatesAutoresizingMaskIntoConstraints = false
        }            

        [pic].forEach{

            view.addSubview($0)
            $0.translatesAutoresizingMaskIntoConstraints = false                
        }

        // Do any additional setup after loading the view.
        NSLayoutConstraint.activate ([

            pic.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
            pic.topAnchor.constraint(equalTo: fight[0].bottomAnchor, constant : 0),

            pic.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.62, constant: 0),
            pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),

            textEnter.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
            textEnter.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
            textEnter.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0),
            textEnter.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),

            fight[0].trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
            fight[0].topAnchor.constraint(equalTo: textEnter.bottomAnchor, constant : 0),

            fight[0].heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10, constant: 0),
            fight[0].widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.10, constant: 0),
            fight[0].leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),

            slider.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0),

            slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.08, constant: 0),
            slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1, constant: 0),
            slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),

        ])
        textEnter.textAlignment = .center

        self.view.sendSubviewToBack(pic)
    }

    @objc func g1Method(_ sender: UIPanGestureRecognizer){

        let tranistioon = sender.translation(in: self.view)
        sender.view!.center = CGPoint(x: sender.view!.center.x + tranistioon.x, y: sender.view!.center.y + tranistioon.y)
        sender.setTranslation(CGPoint.zero,in: self.view)    }
}

【问题讨论】:

  • 我会使用 transform 属性来移动组件,而不是直接应用约束并激活/停用它们。会更优雅。
  • 如何在 uipangesture 中使用 transform 属性
  • 我不确定我是否理解您的问题。您是说文本字段已经在执行您想要的操作,但是您还希望能够移动图像视图吗?图像视图应用了哪两个约束?您希望能够像 textview 一样拖动它吗?或不同的东西?请澄清。

标签: swift uitextfield nslayoutconstraint uipangesturerecognizer sender


【解决方案1】:

改用这个方法

  var existingTransition : CGAffineTransform?
    @objc func g1Method(_ sender: UIPanGestureRecognizer){
        guard let child = sender.view else{return}
        let transitionPoint = sender.translation(in: self.view)
        let newTransition = CGAffineTransform(translationX: transitionPoint.x, y: transitionPoint.y)
        switch sender.state {
        case .ended,.cancelled:// on End
            if let existing = existingTransition{
                self.existingTransition = newTransition.concatenating(existing)
            }else{
                self.existingTransition = newTransition
            }
        default://on change and other states
            if let existing = existingTransition{
                child.transform = newTransition
                    .concatenating(existing)
            }else{
                child.transform = newTransition
            }
        }
        self.view.layoutIfNeeded()
    }

对不起,如果我的代码很乱。但我检查了一些场景,它工作正常。

愉快的编码

【讨论】:

    【解决方案2】:

    你好尝试创建一个 UIImageVIew 类并在下面编写以下代码:

    import UIKit
    
    class draggableImage:UIImageView {
    
    
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            self.layer.borderWidth = 1
            self.layer.borderColor = UIColor.red.cgColor
            self.isUserInteractionEnabled = true
        }
    
    
    
        override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
            let touch = touches.first;
            let location = touch?.location(in: self.superview);
            if(location != nil)
            {
            self.frame.origin = CGPoint(x: location!.x-self.frame.size.width/2, y: location!.y-self.frame.size.height/2);
            }
        }
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    
        }
    
    }
    

    不要忘记将类 draggableImage 分配给属性菜单中的图像视图!希望这对你有用 ~ BY DEV

    【讨论】:

    • 在代码部分我应该在 var pic = draggableImage(coder: ) 中放什么?
    【解决方案3】:

    您不能将显式框架设置与同一对象的自动布局约束混合使用。

    例如,如果您:

    • 向主视图添加标签
    • 设置label.translatesAutoresizingMaskIntoConstraints = false
    • 为标签设置约束

    然后,通过代码...

    • 更改标签的.center 属性

    您会看到标签移动,但是当下一次 UI 更新发生时(您编辑文本字段、点击按钮、旋转设备等),自动布局将根据其约束重置标签的框架。

    因此,在平移手势处理程序中,您可以更新 fight[0] 对象的 .constant 值(而不是更改其 .center),或者...

    您可以为您的fight 对象保留label.translatesAutoresizingMaskIntoConstraints = true,并明确设置它们的框架和中心。

    注意:在任何一种情况下,您确实想要约束相对于fight 对象的任何其他元素,否则它们会在您移动fight[0] 时移动.

    这是对您的 ViewController 类的修改(来自您的 GitHub zip),在您的战斗对象上使用自动布局约束来实现 not 的方法。

    class ViewController: UIViewController {
    
        var pic = UIImageView()
        let fight = (0..<10).map { _ in UIImageView() }
        var textEnter = UITextField()
        var g2 = UIPanGestureRecognizer()
    
        var slider = UISlider()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            fight[0].image  = UIImage(named: "a.png")
    
            fight.forEach{
                $0.isUserInteractionEnabled = true
            }
            [slider,textEnter].forEach{
                $0.translatesAutoresizingMaskIntoConstraints = false
                view.addSubview($0)
                $0.backgroundColor = .blue
            }
    
            slider.backgroundColor = .clear
    
            g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
            fight[0].addGestureRecognizer(g2)
    
            pic.backgroundColor = .systemGreen
    
            fight.forEach{
                $0.backgroundColor = .clear
                view.addSubview($0)
                // do NOT use auto-layout for fight views
                //$0.translatesAutoresizingMaskIntoConstraints = false
            }
    
            [pic].forEach{
                view.addSubview($0)
                $0.translatesAutoresizingMaskIntoConstraints = false
            }
    
            // need a non-rendering "spacer" to vertically separate textEnter from Pic
            let spacer = UILayoutGuide()
            view.addLayoutGuide(spacer)
    
            // NOTE: do NOT constrain any elements relative to fight views
    
            NSLayoutConstraint.activate ([
    
                // constrain textEnter top / leading / trailing to view
                textEnter.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
                textEnter.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
                textEnter.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
                // constrain textEnter height to 0.1 * view height
                textEnter.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0),
    
                // constrain spacer top to bottom of textEnter
                spacer.topAnchor.constraint(equalTo: textEnter.bottomAnchor, constant: 0.0),
                // constrain spacer leading to view leading
                spacer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0),
                // constrain spacer height to 0.1 * view height
                spacer.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10),
                // spacer width doesn't matter
                spacer.widthAnchor.constraint(equalToConstant: 1.0),
    
                // constrain pic Top to spacer bottom
                pic.topAnchor.constraint(equalTo: spacer.bottomAnchor, constant: 0.0),
                // constrain pic leading / trailing to view
                pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
                pic.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
    
                // constrain pic height as you had it
                pic.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.62, constant: 0),
    
                // slider constraints
                slider.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0),
                slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.08, constant: 0),
                slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1, constant: 0),
                slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
    
            ])
    
            textEnter.textAlignment = .center
    
            self.view.sendSubviewToBack(pic)
    
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            // set fight[0] frame *after* textEnter has been laid-out
            fight[0].frame.size = CGSize(width: view.frame.width * 0.10, height: view.frame.height * 0.10)
            let x = view.frame.origin.x
            let y = textEnter.frame.origin.y + textEnter.frame.size.height
            fight[0].frame.origin = CGPoint(x: x, y: y)
        }
    
        @objc func g1Method(_ sender: UIPanGestureRecognizer){
    
            let tranistioon = sender.translation(in: self.view)
            sender.view!.center = CGPoint(x: sender.view!.center.x + tranistioon.x, y: sender.view!.center.y + tranistioon.y)
            sender.setTranslation(CGPoint.zero,in: self.view)
    
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 2014-02-02
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      • 2018-07-29
      • 1970-01-01
      相关资源
      最近更新 更多