IOS UIkit ViewDidLayout 调用手柄拖动

问题描述 投票:0回答:1

我是一名新的 uikit 开发人员。我的应用程序有问题。应用程序有 2 个不同的部分。矩形视图和按钮。矩形视图可以通过平移触摸手势进行拖动。按钮可以通过点击手势更改自己的图像。当用户点击按钮时,它会改变自己的图像。但是当我点击按钮时,矩形视图移动到开始位置。(视图确实加载位置)。

App recording

import UIKit

final class SampleViewController:    UIViewController {
    private var isTapped: Bool = false
    
    let button: UIButton = {
        let button = UIButton()
        let image = UIImageView(image: UIImage(systemName: "play"))
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = .yellow
        return button
    }()
    
    let littleView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.layer.borderColor = UIColor.red.cgColor
        view.layer.borderWidth = 4
        view.isUserInteractionEnabled = true
        view.backgroundColor = .red
        return view
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(button)
        self.view.addSubview(littleView)
        
        littleView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:))))
        
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        
        NSLayoutConstraint.activate([
            button.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
            button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            littleView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1/5),
            littleView.widthAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1/3),
        
        ])
    }

    override func viewDidLayoutSubviews() {
        //littleView.frame = CGRect(x: 0, y: 0, width: littleView.frame.width, height: littleView.frame.height)
    }
    
    override func viewWillLayoutSubviews() {
        //littleView.frame = CGRect(x: 0, y: 0, width: littleView.frame.width, height: littleView.frame.height)
    }

    @objc private func buttonTapped() {
        button.setImage(UIImage(systemName: isTapped ? "play.slash" : "play"), for: .normal)
        self.view.layoutIfNeeded()
        isTapped.toggle()
        print("Button tapped")
    }
    
    @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
        guard let viewToMove = gesture.view else { return }
        if gesture.state == .began || gesture.state == .changed {
            let translation = gesture.translation(in: view)
            
            let newX = max(0, min(view.frame.width - viewToMove.frame.width, viewToMove.frame.origin.x + translation.x))
            let newY = max(0, min((view.frame.height - viewToMove.frame.height), viewToMove.frame.origin.y + translation.y))
            
            viewToMove.frame.origin = CGPoint(x: newX, y: newY)
            gesture.setTranslation(CGPoint.zero, in: view)
            
        }
    }
}

我检查了日志,当我点击按钮时,我看到 viewDidLayout 方法被调用。我该如何处理这个问题,有人帮助我吗?非常感谢。

ios swift uikit autolayout
1个回答
0
投票

您不能使用显式框架设置“混合匹配”约束。

两种选择...

1 - 不要对 littleView 使用

any
约束:

littleView.translatesAutoresizingMaskIntoConstraints = true
littleView.frame = .init(x: 0.0, y: 0.0, width: 160.0, height: 120.0)

2 - 使用约束,但跟踪顶部和前导约束并在拖动时更新它们的常量:

// add these as class properties
var lvTop: NSLayoutConstraint!
var lvLeading: NSLayoutConstraint!

viewDidLoad()
中设置 widthAnchor 和 heightAnchor 后,添加以下行:

lvTop = littleView.topAnchor.constraint(equalTo: view.topAnchor, constant: 0.0)
lvLeading = littleView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0)
lvTop.isActive = true
lvLeading.isActive = true

将您的

handlePan
更改为:

@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
    guard let viewToMove = gesture.view else { return }
    if gesture.state == .began || gesture.state == .changed {
        let translation = gesture.translation(in: view)

        lvTop.constant += translation.y
        lvLeading.constant += translation.x
        
        gesture.setTranslation(CGPoint.zero, in: view)
        
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.