swift touchesBegan and show it on the touched object - ios

I want show the x corrdinate of a touched and moved object.
Try it out:
import UIKit
class ViewController: UIViewController {
var location = CGPoint(x: 0, y: 0)
#IBOutlet weak var viewBox: UIView!
#IBOutlet weak var cntInViewBox: UILabel!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first! as UITouch
location = touch.locationInView(self.view)
viewBox.center = location
/*cntInViewBox.text=String(location.x)*/
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first! as UITouch
location = touch.locationInView(self.view)
viewBox.center = location
/*cntInViewBox.text=String(location.x)*/
}
override func viewDidLoad() {
super.viewDidLoad()
viewBox.center = CGPoint(x:0, y: 0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Without the Line
cntIntViewBox.text=String(location.x)
it works great. Touching on the sceen, the viewBox jumps, starting Touching, the box is moving.
But if I activate the line to show the coordinate (for example, I mean any dynamic text), moving and jumping is not working anymore.
why does this issue arise?

The problem is that your line changes the text of a label. This causes Auto Layout to be performed throughout your interface. Your viewBox view is positioned by Auto Layout constraints, so those constraints take over and are used to position the view. The constraints didn't change so the view doesn't move.

Related

How to Get the Coordinates of a Touch Gesture on a PKCanvasView using PencilKit? Swift 5 & Xcode 11

NOTE that I looked a lot everywhere but couldn't find a solution.
Using the Storyboard, I have a ViewController, with a View (UIView) and a Subview (PKCanvasView) where I want to use PencilKit to draw on the latter.
_
My objectives are:
Draw only on this PKCanvasView
Get the coordinates in real time of where I'm drawing on the PKCanvasView
My results:
I can draw on the PKCanvasView only if I start from this view, and I can only draw within the frame of this PKCanvasView. That's good.
I can only manage to get the coordinates of where I'm touching the screen IF I start the gesture on the UIView. BUT Not if I touch the PKCanvasView first.
My problem:
How do I get the coordinates of where I'm drawing on the PKCanvasView?
–
Below is my code:
import UIKit
import PencilKit
class ViewController: UIViewController {
#IBOutlet weak var labelText: UILabel! //Label object to display the coordinates
#IBOutlet weak var canvasView: PKCanvasView! //Subview to draw on
override func viewDidAppear(_ animated: Bool) {
canvasView.tool = PKInkingTool(.pen, color: .black, width: 10)
}
// MARK: FUNCTIONS //
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
touches.forEach { (touch) in
updateGagues(with: touch)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
touches.forEach { (touch) in
updateGagues(with: touch)
}
}
private func updateGagues(with touch: UITouch) {
let location = touch.preciseLocation(in: view)
labelText.text = location.debugDescription
}
}
I recently experienced the same problem of getting touch coordinates from my PKCanvasView. To do this, I created a subclass of PKCanvasView and overrode the touchesBegan function:
class Canvas: PKCanvasView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
touches.forEach { touch in
print("touch location \(touch.location(in: self))")
}
}
}

Drag UIButton without it shifting to center [Swift 3]

So I found out how to make a button draggable using the UIPanGestureRecognizer. But the only way I know how to do it is by storing and dragging the button by the center. The problem with this is if you try and drag the button from a corner, the button instantly shifts from the corner to the center. What I'm looking for is a solution that would keep my finger on a selected place while moving without instantly locking onto the center.
The code I'm currently using:
func buttonDrag(pan: UIPanGestureRecognizer) {
print("Being Dragged")
if pan.state == .began {
print("panIF")
buttonCenter = button.center // store old button center
}else {
print("panELSE")
let location = pan.location(in: view) // get pan location
button.center = location // set button to where finger is
}
}
Thanks in advance.
This can be done at least in two different ways, one using GestureRecognizer your question way and other way is subclassing the UIView and implementing the touchesBegan, touchesMoved , touchesEnded, touchesCancelled in general will work for any UIView subclass can be UIButton or UILabel or UIImageView etc...
In your way, using GestureRecognizer I make a few changes you still require a var to keep the origin CGPoint of the touch in your UIButton so we get the touch position relative to the UIButton and when the drag continue adjust the UIButton origin according to the origin touch position and the positions of the movement
Method 1 GestureRecognizer
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
var buttonOrigin : CGPoint = CGPoint(x: 0, y: 0)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let gesture = UIPanGestureRecognizer(target: self, action: #selector(buttonDrag(pan:)))
self.button.addGestureRecognizer(gesture)
}
func buttonDrag(pan: UIPanGestureRecognizer) {
print("Being Dragged")
if pan.state == .began {
print("panIF")
buttonOrigin = pan.location(in: button)
}else {
print("panELSE")
let location = pan.location(in: view) // get pan location
button.frame.origin = CGPoint(x: location.x - buttonOrigin.x, y: location.y - buttonOrigin.y)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Method 2 UIView subclass in this case UIButton subclass
Use this UIButton subclass
import UIKit
class DraggableButton: UIButton {
var localTouchPosition : CGPoint?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let touch = touches.first
self.localTouchPosition = touch?.preciseLocation(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
let touch = touches.first
guard let location = touch?.location(in: self.superview), let localTouchPosition = self.localTouchPosition else{
return
}
self.frame.origin = CGPoint(x: location.x - localTouchPosition.x, y: location.y - localTouchPosition.y)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
self.localTouchPosition = nil
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
self.localTouchPosition = nil
}
}
Result
Hope this helps you

Moving an object back and forth with touch

I need to move an object side to side on the screen with the users touch. I have already made the object move with the users touch but I want to make it so the object or image can only be moved right or left. What code should I use to do this? Here is what I have right now.
import UIKit
class ViewController: UIViewController {
#IBOutlet var Person: UIImageView!
var location = CGPoint (x: 0, y: 0)
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()
Person.center = CGPointMake(160, 330)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
This should work. You can change the y to change how you want the UIImageView to always stay on but make sure both are same! At the least, this should give you an idea or put you in the right direction.
import UIKit
class ViewController: UIViewController {
#IBOutlet var Person: UIImageView!
var location = CGPoint(x: 0, y: 0)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch : UITouch! = touches.first! as UITouch
location = touch!.locationInView(self.view)
let point = location.x
Person.center = CGPoint(x: point, y: 160) // change 160 to set vertical height you desire
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch : UITouch! = touches.first! as UITouch
location = touch!.locationInView(self.view)
let point = location.x
Person.center = CGPoint(x: point, y: 160) // change 160 to set vertical height you desire
}
override func viewDidLoad() {
super.viewDidLoad()
Person.center = CGPointMake(160, 330)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I am sure there are better ways but I am still a beginner so...

let user to draw rectangle to select an area

I'm new in Swift and I'm trying to let the user draw a rectangle (touching and dragging) to select an area of an image just like when cropping but I don't want to crop I just want to know the CGRect the user created.
So far I have a .xib with a UIImage inside and its ViewController. I want to draw above the image but every tutorial I found about drawing is about subclassing UIView, override drawRect and put that as the xib class.
I figured it out. I just created a uiview and change its frame depending on the touches events
let overlay = UIView()
var lastPoint = CGPointZero
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
overlay.layer.borderColor = UIColor.blackColor().CGColor
overlay.backgroundColor = UIColor.clearColor().colorWithAlphaComponent(0.5)
overlay.hidden = true
self.view.addSubview(overlay)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//Save original tap Point
if let touch = touches.first {
lastPoint = touch.locationInView(self.view)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
//Get the current known point and redraw
if let touch = touches.first {
let currentPoint = touch.locationInView(view)
reDrawSelectionArea(lastPoint, toPoint: currentPoint)
}
}
func reDrawSelectionArea(fromPoint: CGPoint, toPoint: CGPoint) {
overlay.hidden = false
//Calculate rect from the original point and last known point
let rect = CGRectMake(min(fromPoint.x, toPoint.x),
min(fromPoint.y, toPoint.y),
fabs(fromPoint.x - toPoint.x),
fabs(fromPoint.y - toPoint.y));
overlay.frame = rect
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
overlay.hidden = true
//User has lift his finger, use the rect
applyFilterToSelectedArea(overlay.frame)
overlay.frame = CGRectZero //reset overlay for next tap
}

Adjust UIView frame on dragging

I am trying to change UIView frame on dragging. I subclassed UIView and wrote touchesBegan and touchesMoved methods. Here they are:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
startPosition = touch?.locationInView(self)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let endPosition = touch?.locationInView(self)
let difference = endPosition!.y - startPosition.y
let newFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.width, self.frame.height + difference)
self.frame = newFrame
}
But as a result I got unexpected behaviour. It is a little bit hard to describe it. Here's video how it works.. Small drag(about 20px) makes frame bigger on approximately 100px.
I also have some constraints on my custom view. Image at the bottom of custom view should stay always there:
So questions are:
How to make view bigger on distance user dragged.
And why constraints do not apply after changing frame and how to apply them again?
The reason your view is growing quickly is that you are always updating the current view height with the distance you have moved since your first touch down. Instead of modifying the current height, you should always add the distance moved to the original height of the view.
Add another property to your custom view to keep track of the original height of the view. Set it in touchesBegan and then use that originalHeight when computing the frame in touchesMoved:
class CustomView: UIView {
var startPosition: CGPoint?
var originalHeight: CGFloat = 0
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
startPosition = touch?.locationInView(self)
originalHeight = self.frame.height
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let endPosition = touch?.locationInView(self)
let difference = endPosition!.y - startPosition!.y
let newFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.width, originalHeight + difference)
self.frame = newFrame
}
}
And why constraints do not apply after changing frame and how to apply
them again?
You really shouldn't be updating frames when using Auto Layout. The correct way to do this is to add an #IBOutlet to the height constraint for your view and then update the constant property of the constraint when you wish to change the height of your view.
When you do that, Auto Layout will correctly position the subviews of your custom view using the updated height.
To add an #IBOutlet to the height constraint to your code, Control-drag from the height constraint in the Document Outline to your viewController. Give it a name such as customViewHeight.
Since your code for updating the height of the view is in the view code itself, have the viewController assign the height constraint to the custom view in viewDidLoad. Then the custom view can update the constant property of the height constraint to resize the view.
class ViewController: UIViewController {
#IBOutlet weak var customViewHeight: NSLayoutConstraint!
#IBOutlet weak var customView: CustomView!
override func viewDidLoad() {
super.viewDidLoad()
// Assign the layout constraint to the custom view so that it can update it itself
customView.customViewHeight = customViewHeight
}
}
class CustomView: UIView {
var startPosition: CGPoint?
var originalHeight: CGFloat = 0
var customViewHeight: NSLayoutConstraint!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
startPosition = touch?.locationInView(self)
originalHeight = customViewHeight.constant
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let endPosition = touch?.locationInView(self)
let difference = endPosition!.y - startPosition!.y
customViewHeight.constant = originalHeight + difference
}
}
In your case, I think you should change the constant of the bottom constraints instead of changing the frame of the view. And by the way, you'd better use gestures instead of overriding touch methods since gestures are higher level API and easier to maintain
Basically, projects using Autolayout should avoid changing views with frame.

Resources