UIStackView 和手势
UIStackView & Gestures
我正在尝试 get/keep 在使用平移手势移动 UIStackView 中的元素后对其进行处理。
例如,我试图抓住句柄的元素是按钮标签或文本标签文本。
代码解释...
我正在通过函数 func createButtonStack(label: String, btnTag: Int) -> UIStackView
创建一个 UIStackView
它包含一个按钮和一个文本标签。
创建按钮堆栈后,我将平移手势附加到它,这样我就可以在屏幕上移动按钮。以下3点有效。
- 我创建了按钮堆栈
- 我可以按下按钮并调用 fun 来打印我的消息。
- 我可以移动按钮堆栈。
我遇到的问题是……
一旦我第一次移动按钮堆栈并触发 if 语句 gesture.type == .ended
行,我就失去了对按钮堆栈的控制。
也就是说,按钮不再起作用,我也不能再移动它了。
有人可以帮忙吗?谢谢
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
let ButtonStack = createButtonStack(label: “Button One”, btnTag: 1)
view.addSubview(ButtonStack)
ButtonStack.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
ButtonStack.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
let panGuesture = UIPanGestureRecognizer(target: self, action: #selector(pan(guesture:)))
ButtonStack.isUserInteractionEnabled = true
ButtonStack.addGestureRecognizer(panGuesture)
}
func createButtonStack(label: String, btnTag: Int) -> UIStackView {
let button = UIButton()
button.setImage( imageLiteral(resourceName: "star-in-circle"), for: .normal)
button.heightAnchor.constraint(equalToConstant: 100.0).isActive = true
button.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
button.contentMode = .scaleAspectFit
button.tag = btnTag
switch btnTag {
case 1:
button.addTarget(self, action: #selector(printMessage), for: .touchUpInside)
case 2:
break
default:
break
}
//Text Label
let textLabel = UILabel()
textLabel.backgroundColor = UIColor.green
textLabel.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
textLabel.heightAnchor.constraint(equalToConstant: 25.0).isActive = true
textLabel.font = textLabel.font.withSize(15)
textLabel.text = label
textLabel.textAlignment = .center
//Stack View
let buttonStack = UIStackView()
buttonStack.axis = UILayoutConstraintAxis.vertical
buttonStack.distribution = UIStackViewDistribution.equalSpacing
buttonStack.alignment = UIStackViewAlignment.center
buttonStack.spacing = 1.0
buttonStack.addArrangedSubview(button)
buttonStack.addArrangedSubview(textLabel)
buttonStack.translatesAutoresizingMaskIntoConstraints = false
return buttonStack
}
@objc func printMessage() {
print(“Button One was pressed”)
}
@objc func pan(guesture: UIPanGestureRecognizer) {
let translation = guesture.translation(in: self.view)
if let guestureView = guesture.view {
guestureView.center = CGPoint(x: guestureView.center.x + translation.x, y: guestureView.center.y + translation.y)
if guesture.state == .ended {
print("Guesture Center - Ended = \(guestureView.center)")
}
}
guesture.setTranslation(CGPoint.zero, in: self.view)
}
如果您在 buttonStack 上使用自动布局,则无法直接操作 guestureView.center
centerX。您必须使用约束才能实现拖动效果。
因此,您应该按照以下方式做一些事情,而不是 ButtonStack.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
:
let centerXConstraint = ButtonStack.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
centerXConstraint.isActive = true
ButtonStack.centerXConstraint = centerXConstraint
要这样做,您应该在 ButtonStack
class 上声明一个 NSLayoutConstraint
类型的弱 属性。您可以对 centerY 约束做同样的事情。
之后,在 func pan(guesture: UIPanGestureRecognizer)
方法中,您可以直接在 ButtonStack 视图上操作 centerXConstraint
和 centerYConstraint
属性。
此外,我看到您没有在 ButtonStack 上将 translatesAutoresizingMaskIntoConstraints
属性 设置为 false。每当您以编程方式使用自动布局时,您都应该这样做。
感谢 PGDev 和 marosoaie 的投入。两者都为我提供了解决这个问题的见解。
我的代码只使用一个按钮,但我的项目在 UIStackView 中有三个按钮。
一旦我移动了一个按钮,它实际上破坏了 UIStackView,我失去了对移动按钮的控制。
此处的修复是将三个按钮从 UIStackView 中移除,我现在可以毫无问题地移动和控制所有三个按钮。
至于在按钮/文本字段 UIStackView 上保留句柄,这是通过向 UIStackView 添加 .tag
来实现的。
一旦我移动了元素,平移的 .ended
动作就可以访问 .tag
,因此我可以识别哪个按钮堆栈被移动了。
再次感谢所有的输入。
我正在尝试 get/keep 在使用平移手势移动 UIStackView 中的元素后对其进行处理。
例如,我试图抓住句柄的元素是按钮标签或文本标签文本。
代码解释...
我正在通过函数 func createButtonStack(label: String, btnTag: Int) -> UIStackView
它包含一个按钮和一个文本标签。
创建按钮堆栈后,我将平移手势附加到它,这样我就可以在屏幕上移动按钮。以下3点有效。
- 我创建了按钮堆栈
- 我可以按下按钮并调用 fun 来打印我的消息。
- 我可以移动按钮堆栈。
我遇到的问题是……
一旦我第一次移动按钮堆栈并触发 if 语句 gesture.type == .ended
行,我就失去了对按钮堆栈的控制。
也就是说,按钮不再起作用,我也不能再移动它了。
有人可以帮忙吗?谢谢
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
let ButtonStack = createButtonStack(label: “Button One”, btnTag: 1)
view.addSubview(ButtonStack)
ButtonStack.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
ButtonStack.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
let panGuesture = UIPanGestureRecognizer(target: self, action: #selector(pan(guesture:)))
ButtonStack.isUserInteractionEnabled = true
ButtonStack.addGestureRecognizer(panGuesture)
}
func createButtonStack(label: String, btnTag: Int) -> UIStackView {
let button = UIButton()
button.setImage( imageLiteral(resourceName: "star-in-circle"), for: .normal)
button.heightAnchor.constraint(equalToConstant: 100.0).isActive = true
button.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
button.contentMode = .scaleAspectFit
button.tag = btnTag
switch btnTag {
case 1:
button.addTarget(self, action: #selector(printMessage), for: .touchUpInside)
case 2:
break
default:
break
}
//Text Label
let textLabel = UILabel()
textLabel.backgroundColor = UIColor.green
textLabel.widthAnchor.constraint(equalToConstant: 100.0).isActive = true
textLabel.heightAnchor.constraint(equalToConstant: 25.0).isActive = true
textLabel.font = textLabel.font.withSize(15)
textLabel.text = label
textLabel.textAlignment = .center
//Stack View
let buttonStack = UIStackView()
buttonStack.axis = UILayoutConstraintAxis.vertical
buttonStack.distribution = UIStackViewDistribution.equalSpacing
buttonStack.alignment = UIStackViewAlignment.center
buttonStack.spacing = 1.0
buttonStack.addArrangedSubview(button)
buttonStack.addArrangedSubview(textLabel)
buttonStack.translatesAutoresizingMaskIntoConstraints = false
return buttonStack
}
@objc func printMessage() {
print(“Button One was pressed”)
}
@objc func pan(guesture: UIPanGestureRecognizer) {
let translation = guesture.translation(in: self.view)
if let guestureView = guesture.view {
guestureView.center = CGPoint(x: guestureView.center.x + translation.x, y: guestureView.center.y + translation.y)
if guesture.state == .ended {
print("Guesture Center - Ended = \(guestureView.center)")
}
}
guesture.setTranslation(CGPoint.zero, in: self.view)
}
如果您在 buttonStack 上使用自动布局,则无法直接操作 guestureView.center
centerX。您必须使用约束才能实现拖动效果。
因此,您应该按照以下方式做一些事情,而不是 ButtonStack.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
:
let centerXConstraint = ButtonStack.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
centerXConstraint.isActive = true
ButtonStack.centerXConstraint = centerXConstraint
要这样做,您应该在 ButtonStack
class 上声明一个 NSLayoutConstraint
类型的弱 属性。您可以对 centerY 约束做同样的事情。
之后,在 func pan(guesture: UIPanGestureRecognizer)
方法中,您可以直接在 ButtonStack 视图上操作 centerXConstraint
和 centerYConstraint
属性。
此外,我看到您没有在 ButtonStack 上将 translatesAutoresizingMaskIntoConstraints
属性 设置为 false。每当您以编程方式使用自动布局时,您都应该这样做。
感谢 PGDev 和 marosoaie 的投入。两者都为我提供了解决这个问题的见解。
我的代码只使用一个按钮,但我的项目在 UIStackView 中有三个按钮。
一旦我移动了一个按钮,它实际上破坏了 UIStackView,我失去了对移动按钮的控制。
此处的修复是将三个按钮从 UIStackView 中移除,我现在可以毫无问题地移动和控制所有三个按钮。
至于在按钮/文本字段 UIStackView 上保留句柄,这是通过向 UIStackView 添加 .tag
来实现的。
一旦我移动了元素,平移的 .ended
动作就可以访问 .tag
,因此我可以识别哪个按钮堆栈被移动了。
再次感谢所有的输入。