简体   繁体   中英

iOS: dragging the copy of a button

I'm not sure whether this has been asked or not, but I failed to find a solution. I'm implementing panning gesture on a button, but the idea is: the button is fixed to a position, and when the user drags it, a copy of the button is created and moving with the gesture; the original one stays at its initial place (so there'll be 2 buttons in the view). When the panning ends, the new button is used for some processing, and after that it should disappear (the original one stays as it is; so this whole process can repeat). Currently what I have is as below:

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
}

But the new button doesn't show up in my view. May I know how to solve this?

Hard to say without debugging it, but a few things I see:

You create a new button every time through panDetected, and add it to the view each time. You should only create an add the button in the .began state.

You should use init(frame:) to create your button, and initialize it to the size of the image.

It looks like you're attaching the pan gestures to the buttons. Then you get the pan coordinates in the button's coordinate system, which doesn't make sense. You should be converting the pan gesture to the button's superview's coordinate system, and should not be calling setTranslation except when the pan gesture's state is .began .

You should be setting the button's coordinates to the new location of the pan gesture each time you get a 1st.changed` message.

  1. You need to create and add the new button as a subview only on .began and remove it on .ended .
  2. Therefore you need to keep a reference to the new button.
  3. You are setting the new button's center but not it's size. You might set its .frame .
  4. You do not need to set a translation to the pan gesture. When you get var translation = panGesture.translation(in: view) you get everything you need.
  5. I have wrote the below code for only one button, but if you are going to allow simultaneous dragging of buttons, you would need to keep a list of moving buttons instead of 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 } } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM