iOS: 拖动一个按钮的副本
iOS: dragging the copy of a button
我不确定是否有人问过这个问题,但我没有找到解决方案。我在按钮上实现平移手势,但想法是:按钮固定在一个位置,当用户拖动它时,会创建按钮的副本并随手势移动;原始按钮保留在其初始位置(因此视图中将有 2 个按钮)。当平移结束时,新按钮被用于一些处理,之后它应该消失(原来的按钮保持原样;所以整个过程可以重复)。目前我所拥有的如下:
private func addPanGesture() {
for btn in self.selectors { //selectors is a list of buttons which needs this gesture
let pan = UIPanGestureRecognizer(target: self, action:#selector(self.panDetected(_:)))
pan.minimumNumberOfTouches = 1
pan.maximumNumberOfTouches = 1
btn.addGesturerecognizer(pan)
}
}
@objc private func panDetected(_ panGesture: UIPanGestureRecognizer) {
var translation = panGesture.translation(in: view)
panGesture.setTranslation(CGPoint(x: 0, y: 0), in: view)
var newButton = UIButton()
if let initButton = panGesture.view as? UIButton {
print ("Button recognized!") // this msg is printed out
newButton.center = CGPoint(x: initButton.center.x + translation.x, y: initButton.center.y + translation.y)
newButton.setImage(UIImage(named: "somename"), for: .normal)
}
if panGesture.state == UIGestureRecognizerState.began {
self.view.addSubview(newButton)
}
if panGesture.state == UIGestureRecognizerState.ended {
//some other processing
}
if panGesture.state == UIGestureRecognizerState.changed {
self.view.addSubview(newButton)
}
// printed-out msgs show began, ended, changed states have all been reached
}
但是我的视图中没有显示新按钮。我可以知道如何解决这个问题吗?
不调试很难说,但我看到了一些事情:
你每次通过panDetected创建一个新按钮,每次都添加到视图中。您应该只在 .began 状态下创建一个添加按钮。
您应该使用 init(frame:)
创建您的按钮,并将其初始化为图像的大小。
您似乎正在将平移手势附加到按钮上。然后你在按钮的坐标系中得到了平移坐标,这是没有意义的。您应该将平移手势转换为按钮的超级视图的坐标系,并且不应调用 setTranslation 除非平移手势的状态为 .began
.
每次收到 1st.changed` 消息时,您应该将按钮的坐标设置为平移手势的新位置。
- 您只需要在
.began
上创建新按钮并将其添加为子视图,并在 .ended
上将其删除。
- 因此您需要保留对新按钮的引用。
- 您正在设置新按钮的中心,而不是它的大小。您可以设置它的
.frame
.
- 您不需要为平移手势设置翻译。当您获得
var translation = panGesture.translation(in: view)
时,您将获得所需的一切。
我只为一个按钮编写了以下代码,但是如果您要允许同时拖动按钮,则需要保留一个移动按钮列表而不是 var movingButton: UIButton?
private func addPanGesture() {
let pan = UIPanGestureRecognizer(target: self, action:#selector(self.panDetected(_:)))
pan.minimumNumberOfTouches = 1
pan.maximumNumberOfTouches = 1
btn.addGestureRecognizer(pan)
}
@objc private func panDetected(_ panGesture: UIPanGestureRecognizer) {
let translation = panGesture.translation(in: view)
let initButton = panGesture.view as! UIButton
if panGesture.state == UIGestureRecognizerState.began {
// this is just copying initial button
// this might be overkill
// just make sure you set the frame, title and image of the new button correctly
let initButtonData = NSKeyedArchiver.archivedData(withRootObject: initButton)
let newButton = NSKeyedUnarchiver.unarchiveObject(with: initButtonData) as! UIButton
// we store new button's reference since we will just move it while it is added to view
movingButton = newButton
self.view.addSubview(movingButton!)
}
if panGesture.state == UIGestureRecognizerState.ended {
//some other processing
// when we are done just we just remove it from superview
movingButton!.removeFromSuperview()
}
if panGesture.state == UIGestureRecognizerState.changed {
// at any change, all we need to do is update movingButton's frame
var buttonFrame = initButton.frame;
buttonFrame.origin = CGPoint(x: buttonFrame.origin.x + translation.x, y: buttonFrame.origin.y + translation.y)
movingButton!.frame = buttonFrame
}
}
我不确定是否有人问过这个问题,但我没有找到解决方案。我在按钮上实现平移手势,但想法是:按钮固定在一个位置,当用户拖动它时,会创建按钮的副本并随手势移动;原始按钮保留在其初始位置(因此视图中将有 2 个按钮)。当平移结束时,新按钮被用于一些处理,之后它应该消失(原来的按钮保持原样;所以整个过程可以重复)。目前我所拥有的如下:
private func addPanGesture() {
for btn in self.selectors { //selectors is a list of buttons which needs this gesture
let pan = UIPanGestureRecognizer(target: self, action:#selector(self.panDetected(_:)))
pan.minimumNumberOfTouches = 1
pan.maximumNumberOfTouches = 1
btn.addGesturerecognizer(pan)
}
}
@objc private func panDetected(_ panGesture: UIPanGestureRecognizer) {
var translation = panGesture.translation(in: view)
panGesture.setTranslation(CGPoint(x: 0, y: 0), in: view)
var newButton = UIButton()
if let initButton = panGesture.view as? UIButton {
print ("Button recognized!") // this msg is printed out
newButton.center = CGPoint(x: initButton.center.x + translation.x, y: initButton.center.y + translation.y)
newButton.setImage(UIImage(named: "somename"), for: .normal)
}
if panGesture.state == UIGestureRecognizerState.began {
self.view.addSubview(newButton)
}
if panGesture.state == UIGestureRecognizerState.ended {
//some other processing
}
if panGesture.state == UIGestureRecognizerState.changed {
self.view.addSubview(newButton)
}
// printed-out msgs show began, ended, changed states have all been reached
}
但是我的视图中没有显示新按钮。我可以知道如何解决这个问题吗?
不调试很难说,但我看到了一些事情:
你每次通过panDetected创建一个新按钮,每次都添加到视图中。您应该只在 .began 状态下创建一个添加按钮。
您应该使用 init(frame:)
创建您的按钮,并将其初始化为图像的大小。
您似乎正在将平移手势附加到按钮上。然后你在按钮的坐标系中得到了平移坐标,这是没有意义的。您应该将平移手势转换为按钮的超级视图的坐标系,并且不应调用 setTranslation 除非平移手势的状态为 .began
.
每次收到 1st.changed` 消息时,您应该将按钮的坐标设置为平移手势的新位置。
- 您只需要在
.began
上创建新按钮并将其添加为子视图,并在.ended
上将其删除。 - 因此您需要保留对新按钮的引用。
- 您正在设置新按钮的中心,而不是它的大小。您可以设置它的
.frame
. - 您不需要为平移手势设置翻译。当您获得
var translation = panGesture.translation(in: view)
时,您将获得所需的一切。 我只为一个按钮编写了以下代码,但是如果您要允许同时拖动按钮,则需要保留一个移动按钮列表而不是
var movingButton: UIButton?
private func addPanGesture() { let pan = UIPanGestureRecognizer(target: self, action:#selector(self.panDetected(_:))) pan.minimumNumberOfTouches = 1 pan.maximumNumberOfTouches = 1 btn.addGestureRecognizer(pan) } @objc private func panDetected(_ panGesture: UIPanGestureRecognizer) { let translation = panGesture.translation(in: view) let initButton = panGesture.view as! UIButton if panGesture.state == UIGestureRecognizerState.began { // this is just copying initial button // this might be overkill // just make sure you set the frame, title and image of the new button correctly let initButtonData = NSKeyedArchiver.archivedData(withRootObject: initButton) let newButton = NSKeyedUnarchiver.unarchiveObject(with: initButtonData) as! UIButton // we store new button's reference since we will just move it while it is added to view movingButton = newButton self.view.addSubview(movingButton!) } if panGesture.state == UIGestureRecognizerState.ended { //some other processing // when we are done just we just remove it from superview movingButton!.removeFromSuperview() } if panGesture.state == UIGestureRecognizerState.changed { // at any change, all we need to do is update movingButton's frame var buttonFrame = initButton.frame; buttonFrame.origin = CGPoint(x: buttonFrame.origin.x + translation.x, y: buttonFrame.origin.y + translation.y) movingButton!.frame = buttonFrame } }