提问人:mkemalgokce 提问时间:8/10/2023 最后编辑:pkambmkemalgokce 更新时间:8/11/2023 访问量:38
iOS UIkit ViewDidLayout 调用句柄拖动
iOS UIkit ViewDidLayout Calls On Handle Drag
问:
应用程序有 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 方法在调用。我该如何处理这个问题,有人帮助我吗?多谢。
答:
0赞
DonMag
8/11/2023
#1
不能将约束与显式框架设置“混合搭配”。
两个选项...
1 - 不要对以下方面使用任何约束:littleView
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!
在 中设置 widthAnchor 和 heightAnchor 后,添加以下行:viewDidLoad()
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)
}
}
评论
viewDidLayoutSubviews
当您点击按钮时被调用,因为您正在调用您的方法。self.view.layoutIfNeeded()
buttonTapped