I am trying to move one image on base image.
If I am moving that UIView, it crosses UIImageView's image.
How to restrict UIView's move within UIImageView's image? It should supports for square and rectangle. Moving view should not cross its border.
Kindly guide me.
In the screen shots, UIImageView background color is black color.
Moving UIView is in white color. White color view is crossing its image [Screen Shot 2]. How to restrict within the image ?
Code:
#IBAction func panAcn(sender: UIPanGestureRecognizer) {
if sender.state == .Began || sender.state == .Changed {
let translation = sender.translationInView(self.myImgVw)
// note: 'view' is optional and need to be unwrapped
sender.view!.center = CGPointMake(sender.view!.center.x + translation.x, sender.view!.center.y + translation.y)
sender.setTranslation(CGPointMake(0,0), inView: self.myImgVw)
}
}
Need Output:
My Output
You may try this :
#IBAction func panAcn(sender: UIPanGestureRecognizer) {
if sender.state == .Began || sender.state == .Changed {
let translation = sender.translationInView(self.myImgVw)
// note: 'view' is optional and need to be unwrapped
guard let view = sender.view else { return }
var newFrame = view.frame
newFrame.origin.x = max(self.myImgVw.frame.origin.x, view.frame.origin.x + translation.y)
newFrame.origin.y = max(self.myImgVw.frame.origin.y, view.frame.origin.y + translation.y)
view.frame = newFrame
}
}
Related
I am working on a photo editor app. In this app an effect is something like a Ring shape.
I have two image views and I want to pinch zoom both image views in a way that shows like only one image view zooming. And the ring is completing by two image views.
So main issue is that the ring is behaving like half on one image view and half on other i want to attach them.
#objc func handlePan6(_ gestureRecognizer: UIPanGestureRecognizer) {
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
let translation = gestureRecognizer.translation(in: shapeImageView4)
let translation2 = gestureRecognizer.translation(in: shapeImageView2)
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation.x, y: gestureRecognizer.view!.center.y + translation.y)
gestureRecognizer.view!.center = CGPoint(x: gestureRecognizer.view!.center.x + translation2.x, y: gestureRecognizer.view!.center.y + translation2.y)
gestureRecognizer.setTranslation(CGPoint.zero, in: shapeImageView4)
gestureRecognizer.setTranslation(CGPoint.zero, in: shapeImageView2)
}
}
#objc func pinchRecognized(pinch: UIPinchGestureRecognizer) {
if let view = pinch.view {
view.transform = view.transform.scaledBy(x: pinch.scale, y: pinch.scale)
pinch.scale = 1
}
}
#objc func pinchRecognized2(pinch: UIPinchGestureRecognizer) {
if let view = pinch.view {
neonImageView2.transform = view.transform.scaledBy(x: pinch.scale, y: pinch.scale)
pinch.scale = 1
}
}
I have a rotateArt function that rotates a UIImage - my problem is when this function is called following a pan gesture the image snaps back to the views centre. I would like it to rotate around its current centre.
I have tried assigning a variable to hold its current centre but that did not work. What am I missing?
Thanks
extension MainViewController {
func imageCheck() {
pickedImage != nil ? addPainting() : print("image did not load")
}
func addPainting() {
pickedImageView = UIImageView(image: pickedImage)
pickedImageView.isUserInteractionEnabled = true
pickedImageView.contentMode = .scaleAspectFit
view.addSubview(pickedImageView)
pickedImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
pickedImageView.centerXAnchor.constraint(equalTo: userPickedRoom.centerXAnchor),
pickedImageView.centerYAnchor.constraint(equalTo: userPickedRoom.centerYAnchor, constant: -50),
pickedImageView.widthAnchor.constraint(equalToConstant: 150),
pickedImageView.heightAnchor.constraint(equalToConstant: 150)
])
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
pickedImageView.addGestureRecognizer(panGesture)
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch))
view.addGestureRecognizer(pinchGesture)
addShadow()
}
#objc func handlePan(_ sender: UIPanGestureRecognizer) {
let translation = sender.translation(in: view)
guard let gestureView = sender.view else {return}
gestureView.center = CGPoint(x: gestureView.center.x + translation.x, y: gestureView.center.y + translation.y)
sender.setTranslation(.zero, in: view)
}
#objc func handlePinch(_ sender: UIPinchGestureRecognizer) {
guard sender.view != nil else { return }
if sender.state == .began || sender.state == .changed {
pickedImageView.transform = (pickedImageView.transform.scaledBy(x: sender.scale, y: sender.scale))
sender.scale = 1.0
}
}
func rotateArt() { // pickedImageView.center returns to view.center when this functinon is called.
UIImageView.animate(withDuration: 0.1, animations: {
self.pickedImageView.transform = self.pickedImageView.transform.rotated(by: .pi / 2)
})
}
func addShadow() {
pickedImageView.layer.shadowColor = UIColor.black.cgColor
pickedImageView.layer.shadowOpacity = 1
pickedImageView.layer.shadowOffset = CGSize(width: 0.1, height: 0.5)
pickedImageView.layer.shadowRadius = 1
pickedImageView.layer.shouldRasterize = true
pickedImageView.layer.rasterizationScale = UIScreen.main.scale
}
}
The problem is these lines:
pickedImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate
You cannot position pickedImageView using constraints and also animate it by changing its center (as you do during the pan gesture).
Constraints are one thing. Frames/centers are a different thing. They are opposites. You have created a conflict here: you say one thing by changing the center during the pan, but the constraints say something else (they still want to put the image view where you told them to put it).
You need to resolve that conflict. The easiest way is not to use constraints at all, but there are other ways.
I made a simple app with Xcode in swift in which a circular Imageview in the middle of the screen can be moved with swipe-gesture and changes color when touching the outside of the bigger ring (image for reference) and at the same time changes location to the middle of the screen. Change of color and respawn is achieved by an if statement that changes the file of the picture when the euclidian distance between the middle-points of the smaller Imageview and the middle coordinates of the screen exceeds a certain length. However, when the Imageview spawns in what seems to me to be fixed middle coordinates, the spawning-position is slighty moved in the direction of the swipe. And even more so if the swipe-gesture is faster. Thanks for any hints.
Edit: I removed every part that keeps this from being a minimal example for the problem I have and also uploaded the files I for the colored balls. Can anyone tell me how else I could improve my question to get an answer?
Edit: Now I added an animated gif which firstly shows the functionality and later, when I increase dragging speed, also shows the problem that I'm facing.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet weak var colorImg: UIImageView!
#IBAction func panMade(_ sender: UIPanGestureRecognizer) {
if sender.state == .began || sender.state == .changed {
let translation = sender.translation(in: sender.view)
let changeX = (sender.view?.center.x)! + translation.x
let changeY = (sender.view?.center.y)! + translation.y
sender.view?.center = CGPoint(x: changeX, y: changeY)
sender.setTranslation(CGPoint.zero, in: sender.view)
}
let coordX = colorImg.frame.origin.x+60
let coordY = colorImg.frame.origin.y+60
let centerX = UIScreen.main.bounds.size.width*0.5
let centerY = UIScreen.main.bounds.size.height*0.5
let a = (coordX-centerX) ; let b = (coordY-centerY) ; let c = (a*a) ; let d = (b*b) ; let j = Double(c+d)
if (j.squareRoot() > 112) {
let n = Int.random(in: 1..<4)
colorImg.image = UIImage(named: String(n) + ".png")
sleep(1)
colorImg.center = CGPoint(x: centerX, y: centerY)
}
}
}
I'm trying to make a ball, SKSpriteNode, move in ALL directions including diagonals and all other directions. UIGesture doesn't work with it so I need to use UIPanGesture but I have no idea how to implement it into a SpriteKit file.
This is what I have so far. Any help?? The ball sprite node is called "ball".
func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translation(in: self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPoint.zero, in: self.view)
}
Note that SpriteKit and UIKit have totally different coordinate systems (Spritekit is Cartesian, UIKit is reflected about the X axis) so you cannot use UIKit coordinates in Spritekit without conversion. Fortunately SKScene and SKNode have methods to convert points from a SKView and from other SKNodes into a nodes local space.
#objc private func pan(_ recognizer: UIPanGestureRecognizer) {
let pointInView = recognizer.location(in: view)
let pointInScene = convertPoint(fromView: pointInView)
switch recognizer.state {
case .began:
//Start dragging on the ball, or ignore this gesture
isPanning = atPoint(pointInScene) == ball
case .changed:
//Move the ball
guard isPanning else {
return
}
let translation = recognizer.translation(in: view)
ball.position.x -= translation.x
ball.position.y += translation.y
recognizer.setTranslation(.zero, in: view)
case .cancelled, .ended:
//Stop dragging
isPanning == false
default:
break
}
I have a full example on my GitHub here: https://github.com/joshuajhomann/AngryBirdsClone
I am moving a label around the screen and I want it to go back to it's initial position after I remove my finger off it, for now it's stays there! Any help would be appreciated.
#IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x, y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPointZero, inView: self.view)
if recognizer.state == UIGestureRecognizerState.Ended {
//What code to add to return my Label to it's initial position??
}
}
Save in a variable your initial center position view.center at start dragging, and when you end up moving your UIView around set this value again.
Try this out:
import UIKit
class ViewController: UIViewController {
var initial : CGPoint?
#IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
if let view = recognizer.view {
if recognizer.state == UIGestureRecognizerState.Began {
initial = view.center
}
else if recognizer.state == UIGestureRecognizerState.Ended {
view.center = initial!
return
}
let translation = recognizer.translationInView(self.view)
view.center = CGPoint(x:view.center.x + translation.x, y:view.center.y + translation.y)
recognizer.setTranslation(CGPointZero, inView: self.view)
}
}
}
I believe inside the function touchesEnded you can reset the label's position.
Hope that helps :)