Reputation: 13
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
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
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
Reputation: 5186
You can do this with touchesMoved
event. But my recommendation is to use UIPanGestureRecognizer
.
UIPanGestureRecognizer
object and add it to your image view.Upvotes: 0
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