I have a vertical line (UIView) which I need to resize. I currently do it using a pinch gesture but now I need to do it using a swipe gesture and increase or decrease the height from the side I swipe from. So for example, if I swipe down from the TOP END of the line, the line must decrease in size only from the top. The bottom must stay anchored to the original position.
How do I do this?
I also need to be able to move the image around, which I already have implemented using a UIPanGestureRecognizer as well.
Here's what I've playing around with:
I have a small UIView on top end of the vertical line and one on the bottom end of the line. I use these as markers. Now, I'm able to move the top marker up and down. I need to resize the line to the distance between the two markers AND keep the bottom end of the line at the same position as the bottom marker.
This is what I have
func draggedViewForTopMarker(sender: UIPanGestureRecognizer) {
//To move the top marker
var translation = sender.translationInView(self.view)
sender.view!.center = CGPointMake(sender.view!.center.x, sender.view!.center.y + translation.y)
sender.setTranslation(CGPointZero, inView: self.view)
//Find distance between the markers
var distanceBetweenMarkers = (sender.view!.center.y + translation.y) - self.bottomMarker.center.y
print(distanceBetweenMarkers)
if (distanceBetweenMarkers < 0) {
distanceBetweenMarkers = distanceBetweenMarkers*(-1)
}
//**TRYING** to resize the line to have the same height as the distance between the two markers AND make sure its positioned between the markers and the bottom end of the line is still in the same place as it was originally.
var newFrame = CGRectMake(sender.view!.center.x, distanceBetweenMarkers/2, vertical.frame.width, distanceBetweenMarkers)
vertical.frame = newFrame
}
I'm open to different approaches too, or a solution to the problem I have with this approach!
You may check out at Photo Measures Lite on the App Store to better understand what I mean when I say "resize the line from one side only".
Thanks so much!
instead of making a new frame you can just adjust y position of the line to be the same as the top marker, and the height to be the same as the distance between the two markers
func draggedViewForTopMarker(sender: UIPanGestureRecognizer) {
//To move the top marker
var translation = sender.translationInView(self.view)
sender.view!.center = CGPointMake(sender.view!.center.x, sender.view!.center.y + translation.y)
sender.setTranslation(CGPointZero, inView: self.view)
//Find distance between the markers
var distanceBetweenMarkers = self.topMarker.frame.origin.y - self.bottomMarker.frame.origin.y
vertical.frame.origin.y = self.topMarker.frame.origin.y
vertical.frame.size.height = distanceBetweenMarkers
}
But this will only work if the two markers and the vertical line are the subviews of the same superview
Related
I'm having a hard time setting boundaries and positioning camera properly inside my view after panning. So here's my scenario.
I have a node that is bigger than the screen and I want to let user pan around to see the full map. My node is 1000 by 1400 when the view is 640 by 1136. Sprites inside the map node have the default anchor point.
Then I've added a camera to the map node and set it's position to (0.5, 0.5).
Now I'm wondering if I should be changing the position of the camera or the map node when the user pans the screen ? The first approach seems to be problematic, since I can't simply add translation to the camera position because position is defined as (0.5, 0.5) and translation values are way bigger than that. So I tried multiplying/dividing it by the screen size but that doesn't seem to work. Is the second approach better ?
var map = Map(size: CGSize(width: 1000, height: 1400))
override func didMove(to view: SKView) {
(...)
let pan = UIPanGestureRecognizer(target: self, action: #selector(panned(sender:)))
view.addGestureRecognizer(pan)
self.anchorPoint = CGPoint.zero
self.cam = SKCameraNode()
self.cam.name = "camera"
self.camera = cam
self.addChild(map)
self.map.addChild(self.cam!)
cam.position = CGPoint(x: 0.5, y: 0.5)
}
var previousTranslateX:CGFloat = 0.0
func panned (sender:UIPanGestureRecognizer) {
let currentTranslateX = sender.translation(in: view!).x
//calculate translation since last measurement
let translateX = currentTranslateX - previousTranslateX
let xMargin = (map.nodeSize.width - self.frame.width)/2
var newCamPosition = CGPoint(x: cam.position.x, y: cam.position.y)
let newPositionX = cam.position.x*self.frame.width + translateX
// since the camera x is 320, our limits are 140 and 460 ?
if newPositionX > self.frame.width/2 - xMargin && newPositionX < self.frame.width - xMargin {
newCamPosition.x = newPositionX/self.frame.width
}
centerCameraOnPoint(point: newCamPosition)
//(re-)set previous measurement
if sender.state == .ended {
previousTranslateX = 0
} else {
previousTranslateX = currentTranslateX
}
}
func centerCameraOnPoint(point: CGPoint) {
if cam != nil {
cam.position = point
}
}
Your camera is actually at a pixel point 0.5 points to the right of the centre, and 0.5 points up from the centre. At (0, 0) your camera is dead centre of the screen.
I think the mistake you've made is a conceptual one, thinking that anchor point of the scene (0.5, 0.5) is the same as the centre coordinates of the scene.
If you're working in pixels, which it seems you are, then a camera position of (500, 700) will be at the top right of your map, ( -500, -700 ) will be at the bottom left.
This assumes you're using the midpoint anchor that comes default with the Xcode SpriteKit template.
Which means the answer to your question is: Literally move the camera as you please, around your map, since you'll now be confident in the knowledge it's pixel literal.
With one caveat...
a lot of games use constraints to stop the camera somewhat before it gets to the edge of a map so that the map isn't half off and half on the screen. In this way the map's edge is showing, but the furthest the camera travels is only enough to reveal that edge of the map. This becomes a constraints based effort when you have a player/character that can walk/move to the edge, but the camera doesn't go all the way out there.
In my application I have an UIView.I want functionality such that user can drag the view from its original position to particular limited position for this I have used **UIPanGestureRecognizer Class ** and in gestureRecognizer.state == .Changed condition I am changing the coordinates of view .I am able to drag the view to limited position when moving slowly but The problem is if the user drags the view very rapidly upward or downward the screen, then the view can be pulled beyond the limits I put on the Y position
if(upperLimit > (self.topbaseConstrant.constant * -1))
{
self.topbaseConstrant.constant += gestureRecognizer.translationInView(self.view!).y
gestureRecognizer.setTranslation(CGPointZero, inView: self.view!)
}
I have been trying to solve the issue since last three days .Please give me suggestion
Thanks in advance
Use the min function to determine upper limits
let newPosition = topbaseConstrant.constant + panGestureRecognizer.translationInView(nil).y
topbaseConstrant.constant = min(upperLimit, newPosition)
If you drag quickly and blow past your constraint, the min function will always return that upper constraint as your new position.
I have an UIImage in my viewController that I am using the UIPanGesture on. I am currently using the following code to move it around based on the RayWenderlich tutorial.
#IBAction func panImage(sender: UIPanGestureRecognizer) {
let translation = sender.translationInView(self.view)
if let view = sender.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
exitButton1.center = CGPoint(x:exitButton1.center.x + translation.x, y:exitButton1.center.y + translation.y)
}
sender.setTranslation(CGPointZero, inView: self.view)
}
I am using auto layout for this app and have been informed that moving the UIImage with autoLayoutConstraints should be done instead. I changed to the following code to move the image, however, the image is now jumping all over the screen.
let translation = sender.translationInView(self.view)
image1ConstraintX.constant = image1ConstraintX.constant + translation.x
image1ConstraintY.constant = image1ConstraintY.constant + translation.y
Is there a better way of moving the image using the constraints? Can the first method be used and then the constraints updated afterwards based on the final position? And how would the second method of moving the image look if done correctly?
Generally speaking, if a view has active auto layout constraints you should not set its frame directly. This is because your change will get overwritten the next time the layout engine makes a pass over the relevant views, and you cannot control when that will happen.
Your solution to update the constant of the relevant constraints is the correct one. If you find yourself doing this a lot, you may want to write a method that takes a CGPoint and a view, and updates the relevant constraints.
Can the first method be used and then the constraints updated afterwards based on the final position?
Yes, but you probably don't want to. To accomplish this, you would remove or disable the constraints, modify frame as the user pans, and once the user is done panning, set the constant on each constraint, and re-enable the layout constraints. This would be more complex than is necessary.
I add a pan gesture to a view, move the view while finger moved, but I found if I do not call recognizer.setTranslation(CGPointZero, inView: self.view), translation is not right. why ?
#IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
recognizer.view!.center = CGPoint(x:recognizer.view!.center.x + translation.x,
y:recognizer.view!.center.y + translation.y)
recognizer.setTranslation(CGPointZero, inView: self.view)// this line must need, why?
...
}
I don't speak English well, but I think it may be enough to explain this.
A translation in UIPanGestureRecognizer stands for a vector from where you started dragging to your current finger location, though the origin of this vector is {0, 0}. So all you need to determine the distance you dragged is another point of this vector. You get this point by calling :
recognizer.translationInView(self.view)
Then this point helped you setting a new location of your view.
But UIPanGestureRecognizer is indeed a "continuous" reporter, she will not forget the state after the last report. she didn't know that you have used up that part of translation(to re-locate your view), so the next time when "handlePan" is called, the translation is not calculated from previous location of your finger , it is from the original place where started your finger dragging!!
That's why you have to call:
recognizer.setTranslation(CGPointZero, inView: self.view)
every-time you used that translation to re-locate your view, as if you are telling the recognizer that you are going to start a new drag gesture.
I have a question.
I have 4 Image View objects is my storyboard. Those represents "corners". I'd like to have this option, when you move one of corners, and other three moves relatively.
Like on animated gif here
What I do now is applying Pan Gesture Recognizer to Image Views in storyboard. Then I add code to ViewController:
#IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(self.view)
recognizer.view!.center = CGPoint(x:recognizer.view!.center.x + translation.x,
y:recognizer.view!.center.y + translation.y)
recognizer.setTranslation(CGPointZero, inView: self.view)
}
But I'm not sure what to do next. I need to recognise which corner is tapped and moving, so I could apply special relation moving function for other corners.
Heyo,
One technique is to find a vector representing the pan gesture, and then using that vector to update the rest of the image views. For instance, UIPanGestureRecognizers extends from UIGestureRecognizer, which has the method:
func locationOfTouch(_ touchIndex: Int, inView view: UIView?) -> CGPoint
The pseudocode would go somewhat like this:
Get 1 imageView's last known location as a CGPoint
Detect the pan gesture
Retrieve the location of the touch, as a CGPoint
Now that you have two CGPoints, 1 representing the start position and 1 representing the end position, you can subtract the two points to form a vector with a length and direction. Using this information, you can come up with a formula to displace the other 3 imageViews.