user7062155
user7062155

Reputation: 13

UIImage goes where i tap (But i need it so you can ONLY drag it)

I have a UIImage and I linked it into my code and named it "Person" At the moment where ever I tap on the screen, the UIImage jumps to that position, but I want it so the image can ONLY move if I drag it. Here's my code:

var location = CGPointMake(0, 0)

@IBOutlet var Person: UIImageView!

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    let touch : UITouch = touches.first as UITouch!

    location = touch.locationInView(self.view)

    Person.center = location

}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

    let touch : UITouch = touches.first as UITouch!

    location = touch.locationInView(self.view)

    Person.center = location

}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    Person.center = CGPointMake(160, 330)


}

Upvotes: 1

Views: 45

Answers (4)

Joe
Joe

Reputation: 8986

Simple Approach to fix your problem:

    @IBOutlet weak var imageView: UIImageView!
    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    imageView.isUserInteractionEnabled = true
    let panGestureRecognizer = UIPanGestureRecognizer(target:self, action: #selector(panHandler(recognizer:)))
         imageView.addGestureRecognizer(panGestureRecognizer)
    }

    func panHandler(recognizer:UIPanGestureRecognizer) {
    let translation = recognizer.translation(in: view)
    recognizer.view!.center = CGPoint(x: recognizer.view!.center.x + translation.x, y: recognizer.view!.center.y + translation.y)
    recognizer.setTranslation(CGPoint.zero, in: view)
   }

Upvotes: 0

user7014451
user7014451

Reputation:

I'd use gesture recognizers - much less to code. Also, I use a "three step" gesture in case there is more than one element to move.

Step #1: The user taps on a subview and a dashed border indicates that the subview is in edit mode.

Step #2: The user pans the subview to a new location in the superview.

Step #3: The user taps anywhere else in the superview (including a new subview to edit it next) to take the first subview out of edit mode.

Subview code:

var _editMode = false
var editMode:Bool {
    return _editMode
}
var borderPath = UIBezierPath()
var dashedBorder = CAShapeLayer()

func drawDashedBorder() {
    borderPath = UIBezierPath()
    borderPath.move(to: CGPoint(x: 3, y: 3))
    borderPath.addLine(to: CGPoint(x: self.frame.width-3, y: 3))
    borderPath.addLine(to: CGPoint(x: self.frame.width-3, y: self.frame.height-3))
    borderPath.addLine(to: CGPoint(x: 3, y: self.frame.height-3))
    borderPath.close()
    dashedBorder = CAShapeLayer()
    dashedBorder.strokeColor = UIColor.white.cgColor
    dashedBorder.fillColor = UIColor.clear.cgColor
    dashedBorder.lineDashPattern = [2, 2]
    dashedBorder.lineDashPhase = 0.0
    dashedBorder.lineJoin = kCALineJoinMiter
    dashedBorder.lineWidth = 1.0
    dashedBorder.miterLimit = 10.0
    dashedBorder.path = borderPath.cgPath
    let animation = CABasicAnimation(keyPath: "lineDashPhase")
    animation.fromValue = 0.0
    animation.toValue = 15.0
    animation.duration = 0.75
    animation.repeatCount = 10000
    dashedBorder.add(animation, forKey: "linePhase")
    self.addSublayer(dashedBorder)
    _editMode = true
}

func removeDashedBorder() {
    dashedBorder.removeFromSuperlayer()
    _editMode = false
}

This is not production code, so I never did quite figure out how to make the "moving dashed" animation run forever (which may be good, as it could be a performance issue).But 10000 seconds seems to be pretty generous for editing.

Here's the superview code, with the assumption you have imageView1 and imageView2 as subviews:

var editMode = false

override func viewDidLoad() {
    super.viewDidLoad()
    let tapGesture = UITapGestureRecognizer()
    let panGesture = UIPanGestureRecognizer()
    tapGesture.numberOfTapsRequired = 1
    tapGesture.addTarget(self, action: #selector(editImage))
    self.addGestureRecognizer(tapGesture)
    panGesture.addTarget(self, action: #selector(moveImage))
    self.addGestureRecognizer(panGesture)
}

func editEye(_ recognizer:UITapGestureRecognizer) {
    let p = recognizer.location(in: self)
    if !editMode {
        if (imageView1.layer.hitTest(p) != nil) {
            imageView1.drawDashedBorder()
            self.editMode = true
        } else if (imageView2.layer.hitTest(p) != nil) {
            imageView2.drawDashedBorder()
            self.editMode = true
        }
    } else {
        if imageView1.editMode {
            imageView1.removeDashedBorder()
            self.editMode = false
        } else if imageView2.editMode {
            imageView2.removeDashedBorder()
            self.editMode = false
        }
    }
}

func moveEye(_ recognizer:UIPanGestureRecognizer) {
    let p = recognizer.location(in: self)
    if imageView1.editMode {
        imageView1.position = p
    }
    if imageView2.editMode {
        imageView2.position = p
    }
}

This may not fit your exact needs, but the combination of tap & pan over tap for editing seems more natural. I'm sure that at the very least, doing a "silent" tap & pan (where it appears to the user they are simply dragging something around but they still have to tap on it first) is a better fit.

Upvotes: 1

Muzahid
Muzahid

Reputation: 5186

You can do this with touchesMoved event. But my recommendation is to use UIPanGestureRecognizer.

  1. Declare a UIPanGestureRecognizer object and add it to your image view.
  2. User interaction enable for image view.
  3. Follow this nice apple documented sample code https://developer.apple.com/library/content/samplecode/Touches/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007435

Upvotes: 0

matthiaswitt
matthiaswitt

Reputation: 196

in the touchesBegan method: check if the touch hit the UIImageView and set a global boolean variable to true. Set it to false on touchesEnded, and check in touchesMoved if the variable is true before you move the UIImageview

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

let touch : UITouch = touches.first as UITouch!

location = touch.locationInView(self.view)
if(person.frame.origin.x<location.x&&person.frame.origin.x+person.frame.size.width>location.x{
    // x value for touch is inside uiimageview
if(person.frame.origin.y<location.y&&person.frame.origin.y+person.frame.size.height>location.y{
    //x&y value inside 
    personHit=true
    }
}

   // Person.center = location

}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if(personHit){
let touch : UITouch = touches.first as UITouch!

location = touch.locationInView(self.view)

Person.center = location
}

}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    personHit=false
}

Upvotes: 0

Related Questions