使用平移手势对象将文本输入文本字段以移回其原始位置

Entering text into textfield causing uipangesture object to move back to its orginal position

我的 swift 下面的代码有一个连接到手势的图像视图。在移动图像视图后将内容输入文本字段时。图像视图恢复为原始 position.The gif 表示正在发生的事情。我只是不想在文本字段中输入文本后取消 pangesutre 的效果。

LINK 至 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{
            [=10=].isUserInteractionEnabled = true
        }
        [slider,textEnter].forEach{
            [=10=].translatesAutoresizingMaskIntoConstraints = false
            view.addSubview([=10=])

            [=10=].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{
            [=10=].backgroundColor = .clear
            view.addSubview([=10=])
            [=10=].translatesAutoresizingMaskIntoConstraints = false
        }            

        [pic].forEach{

            view.addSubview([=10=])
            [=10=].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)    }
}

请改用此方法

  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()
    }

抱歉,如果我的代码很乱。但是我检查了一些场景它工作正常。

编码愉快

您好尝试创建一个 class 的 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?) {

    }

}

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

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

例如,如果您:

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

然后,通过代码...

  • 更改标签的.center属性

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

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

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

注意:在任何一种情况下,您 而不是 想要约束与 fight 对象相关的任何其他元素,或者它们会在您移动时移动 fight[0].

这是对 ViewController class 的修改(来自 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{
            [=10=].isUserInteractionEnabled = true
        }
        [slider,textEnter].forEach{
            [=10=].translatesAutoresizingMaskIntoConstraints = false
            view.addSubview([=10=])
            [=10=].backgroundColor = .blue
        }

        slider.backgroundColor = .clear

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

        pic.backgroundColor = .systemGreen

        fight.forEach{
            [=10=].backgroundColor = .clear
            view.addSubview([=10=])
            // do NOT use auto-layout for fight views
            //[=10=].translatesAutoresizingMaskIntoConstraints = false
        }

        [pic].forEach{
            view.addSubview([=10=])
            [=10=].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)

    }

}