我是一名新的 uikit 开发人员。我的应用程序有问题。应用程序有 2 个不同的部分。矩形视图和按钮。矩形视图可以通过平移触摸手势进行拖动。按钮可以通过点击手势更改自己的图像。当用户点击按钮时,它会改变自己的图像。但是当我点击按钮时,矩形视图移动到开始位置。(视图确实加载位置)。
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 方法被调用。我该如何处理这个问题,有人帮助我吗?非常感谢。
您不能使用显式框架设置“混合匹配”约束。
两种选择...
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)
}
}