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
}
}
Related
Hello I'm trying to draw some rectangles on a UIImageView but when I add the background image the rectangle drawing is not working anymore:
This is the code:
import UIKit
class DrawView: UIView {
var startPos: CGPoint?
var endPos: CGPoint?
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
if startPos != nil && endPos != nil {
print("both there")
drawRectangle(context: context, startPoint: startPos!, endPoint: endPos!, isFilled: false)
}
}
public func drawRectangle(context: CGContext, startPoint: CGPoint, endPoint: CGPoint, isFilled: Bool) {
let xx = startPoint
let xy = CGPoint(x:endPoint.x, y:startPoint.y)
let yx = CGPoint(x:startPoint.x, y:endPoint.y)
let yy = endPoint
print("draw rectangle")
context.move(to: xx)
context.addLine(to: xx)
context.addLine(to: xy)
context.addLine(to: yy)
context.addLine(to: yx)
context.addLine(to: xx)
context.setLineCap(.square)
context.setLineWidth(8)
if isFilled {
context.setFillColor(UIColor.purple.cgColor)
context.fillPath()
} else {
context.setStrokeColor(UIColor.red.cgColor)
context.strokePath()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: self)
print(position)
startPos = position
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: self)
print(position)
endPos = position
setNeedsDisplay()
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: self)
print(position)
endPos = position
setNeedsDisplay()
}
}
func addBackground() {
// screen width and height:
let width = UIScreen.main.bounds.size.width
let height = UIScreen.main.bounds.size.height
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
imageView.image = UIImage(named: "img1.jpg")
// you can change the content mode:
imageView.contentMode = UIView.ContentMode.scaleAspectFill
self.addSubview(imageView)
self.sendSubviewToBack(imageView)
}
}
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var drawView: DrawView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
drawView.addBackground()
}
}
Im suspecting that I'm not using the correct UIGraphicsGetCurrentContext after setting the image but I was not able to figure it out how to fix it.
I am trying to make a game that has five simple objects that the user can touch and move these have physics on them but having trouble getting them to move separately any help would be appreciated.
This is what I have so far:
import SpriteKit
class GameScene: SKScene {
let starSprite = SKSpriteNode(imageNamed: "starSprite")
let circleSprite = SKSpriteNode(imageNamed: "circleSprite")
let squareSprite = SKSpriteNode(imageNamed: "squareSprite")
let triangleSprite = SKSpriteNode(imageNamed: "triangleSprite")
let moonSprite = SKSpriteNode(imageNamed: "moonSprite")
var touchLocation = CGPoint()
override func didMove(to view: SKView) {
layoutScene()
}
func layoutScene() {
backgroundColor = UIColor(red: 44/255, green: 62/255, blue:
80/255, alpha: 1.0)
starSprite.size = CGSize(width: 350, height: 350)
starSprite.position = CGPoint(x: frame.midX, y: frame.midY)
starSprite.physicsBody = SKPhysicsBody(texture:
starSprite.texture!, size: starSprite.size)
addChild(starSprite)
circleSprite.size = CGSize(width: 350, height: 350)
circleSprite.position = CGPoint(x: 0, y: 100)
circleSprite.physicsBody = SKPhysicsBody(texture:
circleSprite.texture!, size: circleSprite.size)
addChild(circleSprite)
squareSprite.size = CGSize(width: 350, height: 350)
squareSprite.position = CGPoint(x: 0, y: 200)
squareSprite.physicsBody = SKPhysicsBody(texture:
squareSprite.texture!, size: squareSprite.size)
addChild(squareSprite)
triangleSprite.size = CGSize(width: 350, height: 350)
triangleSprite.position = CGPoint(x: 0, y: 300)
triangleSprite.physicsBody = SKPhysicsBody(texture:
triangleSprite.texture!, size: triangleSprite.size)
addChild(triangleSprite)
moonSprite.size = CGSize(width: 350, height: 350)
moonSprite.position = CGPoint(x: 0, y: 400)
moonSprite.physicsBody = SKPhysicsBody(texture:
moonSprite.texture!, size: moonSprite.size)
addChild(moonSprite)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
touchLocation = touch.location(in: self)
moonSprite.position.x = (touchLocation.x)
moonSprite.position.y = (touchLocation.y)
starSprite.position.x = (touchLocation.x)
starSprite.position.y = (touchLocation.y)
}
}
}
you should first detect which object has been selected in touchDown, then change the position in touchesMoved, and release the object in touchUp!
define a value as a temp and use that!
In addition , and you don't need to use this
moonSprite.position.x = (touchLocation.x)
moonSprite.position.y = (touchLocation.y)
it's better
moonSprite.position = touchLocation
Edited Code
//
// GameScene.swift
// aa
//
// Created by ehsan on 1/30/19.
// Copyright © 2019 ehsan. All rights reserved.
//
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var spinnyNode1 = SKSpriteNode(imageNamed: "1")
private var spinnyNode2 = SKSpriteNode(imageNamed: "2")
private var movingSprite:SKSpriteNode?
override func didMove(to view: SKView) {
addChild(spinnyNode1)
addChild(spinnyNode2)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let location = t.location(in: self)
let node = self.atPoint(location)
if node is SKSpriteNode
{
movingSprite = node as? SKSpriteNode
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if movingSprite != nil
{
movingSprite!.position = touchLocation
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
movingSprite = nil
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
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
}
My first post and I am currently making an app in Xcode 8.1 using Swift 3
I have 9 images that I have made draggable with touchesBegan and touchesMoved functions.
However they are able to be dragged ANYWHERE on the screen and this can cause them to cover up other images I have. I would like to limit their movement by setting a boundary for them so that even when the user tries to drag the images out of that boundary they wont be able to.
I have created this code in draggedimageview.swift this allows the Image views to be dragged.
I have been spending a long time trying to figure out how to do this and if anyone can help I would appreciate it.
Thanks...
import UIKit
class DraggedImageView: UIImageView {
var startLocation: CGPoint?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
startLocation = touches.first?.location(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let currentLocation = touches.first?.location(in: self)
let dx = currentLocation!.x - startLocation!.x
let dy = currentLocation!.y - startLocation!.y
self.center = CGPoint(x: self.center.x+dx, y: self.center.y+dy)
}
}
You can do this:
let cx = self.center.x+dx
if (cx > 100) {
cx = 100
}
self.center = CGPoint(x: cx, y: self.center.y+dy)
But alter the if based on what you are trying to do. This clamps it so that it cannot be moved to a position where center.x > 100
Try to define your "allowed area" in a rect, such as:
import UIKit
class DraggedImageView: UIImageView {
var startLocation: CGPoint?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
startLocation = touches.first?.location(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let currentLocation = touches.first?.location(in: self)
let dx = currentLocation!.x - startLocation!.x
let dy = currentLocation!.y - startLocation!.y
// This is the area in which the dragging is allowed
let coolArea = CGRect(x: 0, y: 0, width: 100, height: 100)
let newCenter = CGPoint(x: self.center.x+dx, y: self.center.y+dy)
// If the allowed area contains the new point, we can assign it
if coolArea.contains(newCenter) {
self.center = newCenter
}
// else {
// print("Out of boundaries!")
// }
self.center = CGPoint(x: self.center.x+dx, y: self.center.y+dy)
}
}
You may want to change the code if you want something different to happen when user is dragging out of the bounds.
Taking the "allowed area" from the view that contains the UIImageView
import UIKit
class DraggedImageView: UIImageView {
var startLocation: CGPoint?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
startLocation = touches.first?.location(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let currentLocation = touches.first?.location(in: self)
let dx = currentLocation!.x - startLocation!.x
let dy = currentLocation!.y - startLocation!.y
let coolArea = (self.superview?.bounds)!
let newCenter = CGPoint(x: self.center.x+dx, y: self.center.y+dy)
// If the allowed area contains the new point, we can assign it
if coolArea.contains(newCenter) {
self.center = newCenter
print("touchesMoved")
}
else {
print("Out of boundaries!")
}
}
}
I was learning about SKNodes in Swift and have encountered a problem. App was supposed to be very simple: touching screen and getting node to appear in the touched position. I don't know why but the rectangle keeps showing in different place on the screen but sn.position is the same as touch.location(in: view) position. What's wrong?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var spinnyNode : SKShapeNode?
private var touchPoint : CGPoint!
override func didMove(to view: SKView) {
let size = CGSize(width: 50, height: 50)
spinnyNode = SKShapeNode(rectOf: size, cornerRadius: CGFloat(0.6)) //init
if let spinnyNode = self.spinnyNode{
spinnyNode.lineWidth = 3
let rotate = SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI), duration: 1))
let fade = SKAction.fadeOut(withDuration: 0.5)
let remove = SKAction.removeFromParent()
spinnyNode.run(rotate)
spinnyNode.run(SKAction.sequence([fade, remove]))
}
}
func touchDown(point pos : CGPoint){
if let sn = self.spinnyNode?.copy() as! SKShapeNode? {
sn.position = CGPoint(x: touchPoint.x , y: touchPoint.y)
print("touchDown x:\(touchPoint.x), y:\(touchPoint.y)")
self.addChild(sn)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard touches.count == 1 else{
return
}
if let touch = touches.first{
touchPoint = touch.location(in: view)
touchDown(point: touchPoint)
print("touchesBegan -> x: \(touchPoint.x) y: \(touchPoint.y)")
}
}
Try doing something like this
import SpriteKit
import GameplayKit
class GameScene: SKScene {
//use whichever image for your node
var ballNode = SKSpriteNode(imageNamed: "ball")
var fingerLocation = CGPoint()
override func didMove(to view: SKView) {
ballNode.size = CGSize(width: 100, height: 100)
ballNode.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if let location = touches.first?.location(in: self){
if let copy = ballNode.copy() as? SKSpriteNode {
copy.position = location
addChild(copy)
}
}
}
}
Every time I click on a random spot, the ball appears. Hope this helps.