I am trying to make a square appear on a random CGPoint in Swift every time I click the screen. Below is what I have done with no compiler errors, but once I run the application, I can click or drag to move my "person," but every time I do that, a smaller square does not appear. Any advice or solutions are great. Thank you! by the way, person, a UIImageView is no image but has a viable backgroundColor.`
`
#IBOutlet weak var person: UIImageView!
var location = CGPoint(x: 0,y: 0)
var randomPoint = CGPoint(x:Int(arc4random()%1000),y:Int(arc4random()%1000))
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
location = touch!.locationInView(self.view)
person.center = location
for _ in touches {
let mySquare: UIView = UIView(frame: CGRect(x: 0,y: 0,width: 20,height: 20))
mySquare.backgroundColor = UIColor.cyanColor()
mySquare.center = randomPoint
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
location = touch!.locationInView(self.view)
person.center = location
for _ in touches {
let mySquare: UIView = UIView(frame: CGRect(x: 0,y: 0,width: 20,height: 20))
mySquare.backgroundColor = UIColor.cyanColor()
mySquare.center = randomPoint
}
}`
For every touch, you just need create and add(you missed this step) square in touch begin (or touch end), don't do in touch move.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
location = touch!.locationInView(self.view)
person.center = location
for _ in touches {
let mySquare: UIView = UIView(frame: CGRect(x: 0,y: 0,width: 20,height: 20))
mySquare.backgroundColor = UIColor.cyanColor()
mySquare.center = randomPoint
view.addSubview(mySquare) // add square to the view
}
}
You didn't add mySquare view onto any view.
self.view.addSubview(mySquare)
Related
I have created Circle using "draw" and can place it anywhere on view. but when I want to move a specific circle by clicking it. it selects "LAST" created circle.
how can I select a specific circle? please guide me for the same.
if anything else you need let me know.
**CircleView**
import UIKit
class CircleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
}
required init(coder aDecoder : NSCoder) {
fatalError("init(coder : ) has not been implemented")
}
override func draw(_ rect: CGRect) {
if let context = UIGraphicsGetCurrentContext(){
context.setLineWidth(2)
UIColor.yellow.set()
let circleCenter = CGPoint(x: frame.size.width / 2, y: frame.self.height / 2)
let circleRadius = (frame.size.width - 10) / 2
context.addArc(center: circleCenter, radius: circleRadius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
context.strokePath()
}
}
}
**ViewController**
import UIKit
class ViewController: UIViewController {
var circleView = CircleView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
let circleWidth = CGFloat(100)
var lastCircleCenter = CGPoint()
var currentCenter = CGPoint()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
circleView.isUserInteractionEnabled = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
lastCircleCenter = touch.location(in: view)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let circleCenter = touch.location(in: view)
if circleCenter == lastCircleCenter{
let circleHeight = circleWidth
circleView = CircleView(frame: CGRect(x: circleCenter.x - circleWidth / 2, y: circleCenter.y - circleWidth / 2, width: 100, height: 100))
view.addSubview(circleView)
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {
return
}
let location = touch.location(in: view)
circleView.center = location
}
}
how can I select a specific circle? please guide me for the same.
if anything else you need let me know.
how can I select a specific circle? please guide me for the same.
if anything else you need let me know.
If you are creating multiple circles and adding them to your view, I would suggest to keep track of the created circles in a collection. That way on each touch you can check if the coordinate matches any of the created circles. Based on that you can determine if to create a new circle or to move an existing one.
Example:
class ViewController: UIViewController {
var circleViews: [CircleView] = []
let circleWidth = CGFloat(100)
var draggedCircle: CircleView?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Do nothing if a circle is being dragged
// or if we do not have a coordinate
guard draggedCircle == nil, let point = touches.first?.location(in: view) else {
return
}
// Do not create new circle if touch is in an existing circle
// Keep the reference of the (potentially) dragged circle
if let draggedCircle = circleViews.filter({ UIBezierPath(ovalIn: $0.frame).contains(point) }).first {
self.draggedCircle = draggedCircle
return
}
// Create new circle and store in an array
let offset = circleWidth / 2
let rect = CGRect(x: point.x - offset, y: point.y - offset, width: circleWidth, height: circleWidth)
let circleView = CircleView(frame: rect)
circleViews.append(circleView)
view.addSubview(circleView)
// The newly created view can be immediately dragged
draggedCircle = circleView
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// If touches end then a circle is never dragged
draggedCircle = nil
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let draggedCircle = draggedCircle, let point = touches.first?.location(in: view) else {
return
}
draggedCircle.center = point
}
}
I´m making an app that draw lines between points to make a figure. The first thing is to draw points using touches but i´ve tried a lot and i still can´t find the way to draw the points firstly. Here is my code:
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var xpoint: CGFloat = 0
var ypoint: CGFloat = 0
var opacity: CGFloat = 1.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
xpoint = location.x
ypoint = location.y
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Now, you just need to take that location and add a view there. Try to update touchesBegan to look something like this:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
xpoint = location.x
ypoint = location.y
//Initialize the view at the correct spot
//We set the view's frame by giving it an origin (that's the CGPoint we build from the x and y coordinates) and giving it a size, which can be anything really
let pointView = UIView(frame: CGRect(origin: CGPoint(x: xpoint, y: ypoint), size: CGSize(width: 25, height: 25))
//Round the view's corners so that it is a circle, not a square
view.layer.cornerRadius = 12.5
//Give the view a background color (in this case, blue)
view.backgroundColor = .blue
//Add the view as a subview of the current view controller's view
self.view.addSubview(view)
}
}
override func didMove(to view: SKView) {
view.scene?.anchorPoint = CGPoint(x: 0,y : 0)
castle = SKShapeNode(circleOfRadius: ballRadius1)
castle.physicsBody = SKPhysicsBody(circleOfRadius:ballRadius1)
castle.fillColor = .white
castle.name = "castle"
castle.position = CGPoint(x: 0, y: 0)
castle.physicsBody?.isDynamic = false
castle.physicsBody?.affectedByGravity = false;
castle.isUserInteractionEnabled = true
self.addChild(castle)
I have a circle in the middle of the screen, I want to make it disappear when I tap it. Can you please help me? It is an SKShapeNode and has a PhysicsBody with the same radius
You could use touchesBegan and make it look like so
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let nodeITapped = atPoint(pointOfTouch)
let nameOfTappedNode = nodeITapped.name
if nameOfTappedNode == "castle"{
//make it do whatever you want
castle.removeFromParent()
}
}
}
you could also implement it in touchesEnded instead if you want the node to disappear as soon as the user releases the touch.
I want to move this boat image with touches. It needs to move only left and right but not up and down. The problem is with this basic code setup, The image is moving all around.
I have the following code
import UIKit
class ViewController: UIViewController {
var boat:UIImageView!
var stone:UIImageView!
#IBOutlet weak var myView: UIView!
var location = CGPoint(x: 0, y: 0)
func start() {
boat = UIImageView(image: UIImage(named: "boat"))
boat.frame = CGRect(x: 0, y: 0, width: 60, height: 90)
boat.frame.origin.y = self.view.bounds.height - boat.frame.size.height - 10
boat.center.x = self.view.bounds.midX
self.view.addSubview(boat)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
start()
movingStone()
intersectsAt()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch : UITouch = touches.first as UITouch!
location = touch.location(in: self.view)
boat.center = location
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch : UITouch = touches.first as UITouch!
location = touch.location(in: self.view)
boat.center = location
}
func movingStone() {
stone = UIImageView(image: UIImage(named: "stones.png"))
stone.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
var stone2 = 10 + arc4random() % 20
stone.bounds = CGRect(x:10, y:10, width:40.0, height:40.0)
stone.contentMode = .center;
stone.layer.position = CGPoint(x: Int(stone2), y: 10)
stone.transform = CGAffineTransform(rotationAngle: 3.142)
self.view.insertSubview(stone, aboveSubview: myView)
UIView.animate(withDuration: 5, delay: 0, options: UIViewAnimationOptions.curveLinear, animations: { () -> Void in
self.stone.frame.origin.y = self.view.bounds.height + self.stone.frame.height + 10
}) { (success:Bool) -> Void in
self.stone.removeFromSuperview()
self.movingStone()
}
}
func intersectsAt() {
if(boat.layer.presentation()?.frame.intersects
((stone.layer.presentation()?.frame)!))! {
boat.image = UIImage(named: "wreckboat.png")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You need to update only the x coordinate of the image not the y coordinate.
Try this:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch : UITouch = touches.first as UITouch!
let loc_tmp = touch.location(in: self.view)
// only use the x coordinate of the touch location
location = CGPoint(x: loc_tmp.x, y: boat.center.y)
boat.center = location
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch : UITouch = touches.first as UITouch!
let loc_tmp = touch.location(in: self.view)
// only use the x coordinate of the touch location
location = CGPoint(x: loc_tmp.x, y: boat.center.y)
boat.center = location
}
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)
}
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.
You can do this with touchesMoved event. But my recommendation is to use UIPanGestureRecognizer.
Declare a UIPanGestureRecognizer object and add it to your image view.
User interaction enable for image view.
Follow this nice apple documented sample code https://developer.apple.com/library/content/samplecode/Touches/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007435
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
}
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)
}