swift 保存按钮中心位置并将其加载到视图控制器中已加载

gjmwrych  于 2022-10-31  发布在  Swift
关注(0)|答案(1)|浏览(134)

大家好,对不起我的英语,我正在开发一个应用程序,它能够移动一堆按钮,每个按钮在屏幕上都有UIPanGestureRecognizer,保存中心位置(x,y)和Core Data中的标签。
当应用程序从零开始,并且我从Core Data加载位置时:

if let c = ButtonEntity.getButton(tag: self.tag)
    {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5)
    {
            self.center = CGPoint(x: CGFloat( c.xPoint ?? 0), y: CGFloat( c.yPoint ?? 0))
    }

这来自自定义UIButton类,默认情况下,按钮放置在auto layout的特定位置
问题是,在某些情况下,某些按钮会返回到其auto layout位置,而不是返回到viewDidLoad上分配的coreData中心位置
有什么解决方案或其他方法来做到这一点吗?谢谢

vkc1a9a2

vkc1a9a21#

为了帮助理解为什么我们不能将约束与.center(帧)更改混合...
下面是两个几乎相同的视图控制器。
每个都添加一个按钮,并将按钮的.centerXAnchor.centerYAnchor设置为视图的.centerXAnchor.centerYAnchor
我们将平移手势添加到按钮,以便可以四处拖动它。
我们还实现了touchesBegan(...),我们所做的只是改变按钮标题,这样做将触发一个自动布局通道。
在第一个示例的平移函数中,我们使用了一个典型的“获取平移位置并更新.center属性:

@objc func pan(_ sender: UIPanGestureRecognizer) {
    guard let v = sender.view, let sv = v.superview else { return }
    if sender.state == .changed {
        let pt: CGPoint = sender.location(in: sv)
        // update the button's .center property (changes the frame)
        v.center = pt
    }
}

这样做很好,直到我们点击按钮的任何位置。在这一点上,我们改变按钮的标题和自动布局移动按钮回到它的中心X和Y约束。
在第二个示例中,我们将X和Y约束作为var /属性添加到控制器:

// btn center constraints
//  we will modify the .constants when panning
var xConstraint: NSLayoutConstraint!
var yConstraint: NSLayoutConstraint!

viewDidLoad()中设置它们,然后在平移手势中 * 移动按钮 *,如下所示:

@objc func pan(_ sender: UIPanGestureRecognizer) {
    guard let v = sender.view, let sv = v.superview else { return }
    if sender.state == .changed {
        let pt: CGPoint = sender.location(in: sv)
        let xOff = pt.x - sv.center.x
        let yOff = pt.y - sv.center.y
        // update the .constant values for the btn center x/y
        xConstraint.constant = xOff
        yConstraint.constant = yOff
    }
}

现在,点击其他任何地方将更改按钮标题,但它将保持不变,因为我们已经更改了X和Y约束的.constant值。

设置.center--问题

class DemoVC: UIViewController {

    let btnToMove = UIButton()

    var tapCounter: Int = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        btnToMove.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(btnToMove)

        btnToMove.setTitle("Test", for: [])
        btnToMove.backgroundColor = .red

        NSLayoutConstraint.activate([
            btnToMove.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            btnToMove.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        ])

        let p = UIPanGestureRecognizer(target: self, action: #selector(pan(_:)))
        btnToMove.addGestureRecognizer(p)
    }

    @objc func pan(_ sender: UIPanGestureRecognizer) {
        guard let v = sender.view, let sv = v.superview else { return }
        if sender.state == .changed {
            let pt: CGPoint = sender.location(in: sv)
            // update the button's .center property (changes the frame)
            v.center = pt
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // update the button title - which will trigger an auto-layout pass
        tapCounter += 1
        btnToMove.setTitle("Test \(tapCounter)", for: [])
    }

}

更新约束.constant值--没有问题

class DemoVC: UIViewController {

    let btnToMove = UIButton()

    var tapCounter: Int = 0

    // btn center constraints
    //  we will modify the .constants when panning
    var xConstraint: NSLayoutConstraint!
    var yConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()

        btnToMove.setTitle("Test", for: [])
        btnToMove.backgroundColor = .red

        btnToMove.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(btnToMove)

        xConstraint = btnToMove.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0)
        yConstraint = btnToMove.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0)

        NSLayoutConstraint.activate([
            xConstraint, yConstraint,
        ])

        let p = UIPanGestureRecognizer(target: self, action: #selector(pan(_:)))
        btnToMove.addGestureRecognizer(p)
    }

    @objc func pan(_ sender: UIPanGestureRecognizer) {
        guard let v = sender.view, let sv = v.superview else { return }
        if sender.state == .changed {
            let pt: CGPoint = sender.location(in: sv)
            let xOff = pt.x - sv.center.x
            let yOff = pt.y - sv.center.y
            // update the .constant values for the btn center x/y
            xConstraint.constant = xOff
            yConstraint.constant = yOff
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // update the button title - which will trigger an auto-layout pass
        tapCounter += 1
        btnToMove.setTitle("Test \(tapCounter)", for: [])
    }

}

相关问题