Confused about plotting origin in iOS - ios

Code
self.view.frame.origin.y = self.view.frame.origin.y - keyboardSize.height
Here I am trying to set my views origin to my view-height of the keyboard
My output
My Doubt
my view has to go below the keyboard according to math, what is happening?

The coordinate space that UIViews are in is not exactly the same as the cartesian coordinate plane you learned in math class, which might look something like this:
In UIKit, the positive y direction is downwards, and the negative y direction is upwards. This means that a view with a small y coordinate will be at the top of its superview. As you increase its y coordinate, it moves downwards. It looks something like this:
This line of code:
self.view.frame.origin.y=self.view.frame.origin.y-keyboardSize.height
decreases the y coordinate of self.view, hence moving it up. By how much? Well, the keyboard's height.

View coordinate system increaes from top (0) to bottom (device height) , so this
self.view.frame.origin.y=self.view.frame.origin.y-keyboardSize.height
raises the view as it decrease it's y origin position

Related

Swift sprite kit vertical background infinite image

I have 3 images:
topBg.png
midBg.png
botBg.png
I want to set topBg.png at top scene and height = 200
middleBg.png should be infinite scale or repeat vertically
botBg.png - should be in bottom and height = 200
i have next code:
override func didMove(to view: SKView) {
self.bgTopSpriteNode = self.childNode(withName: "//bgTopNode") as? SKSpriteNode
self.bgMiddleSpriteNode = self.childNode(withName: "//bgMiddleNode") as? SKSpriteNode
self.bgBottomSpriteNode = self.childNode(withName: "//bgBottomNode") as? SKSpriteNode
if let bgTopSpriteNode = self.bgTopSpriteNode,
let bgMiddleSpriteNode = self.bgMiddleSpriteNode,
let bgBottomSpriteNode = self.bgBottomSpriteNode {
bgTopSpriteNode.size.width = self.frame.width
bgTopSpriteNode.size.height = 200
bgTopSpriteNode.position.x = 0
bgMiddleSpriteNode.size.width = self.frame.width
bgMiddleSpriteNode.size.height = self.frame.height-400
bgMiddleSpriteNode.position.x = 0
bgBottomSpriteNode.size.width = self.frame.width
bgBottomSpriteNode.size.height = 200
bgBottomSpriteNode.position.x = 0
}
}
But how to set Y position of images. Because coordinates begin from center of screen, not from left top and i don't know how to convert them.
There are a couple of different ways to achieve what you're looking to do.
First, you can compute the y position of the top and the bottom of the screen using simply size.height / 2 if you have the anchorPoint of your scene at (0.5,0.5). (Don't use frame - use size. That way, you take into account the scaleMode of the scene.)
It sounds like you are frustrated that the origin of the scene is in the center. If you'd like to move it to the corner, you can easily do so by setting the scene's anchorPoint property, say, to (0.0, 0.0) for the lower left corner. Then, your y-values are 0 and size.height. If you are using the .sks editor, this is exposed in the interface - you can just set it there. Otherwise, you can set it programmatically.
Finally, you can set the scaleMode of your scene to something like .aspectFill, set the size of the scene directly (say, to 1024x768 for an iPad), and just place the images wherever they need to go. This approach works particularly well with .sks files, if you are using them; when you load up a scene, you can set the size of the scene based on the aspect ratio of the view it's in to accommodate different aspect ratios. For instance, you could adopt a 320x480 "reference size" for your iPhone scenes. Whenever you load up the scene, you could set the size of the scene to be 320 points wide and however many points tall to match the aspect ratio of the device. Then, all your graphics would be produced at 320pt wide, and you could slide them up or down proportionally across the scene's size for layout. This is a little more complicated, but it's a lot easier than trying to deal with separate layout considerations for multiple devices.
I should also point out a couple of things.
You can use the anchorPoint property of a sprite to dictate where the sprite's coordinates are measured from. This is handy for cases where you want images to be flush up against something. For instance, if you want an image flush against the left side of the screen, set its position to be exactly the left side of the screen, and then set its anchorPoint.x to 0.0; this will put the left edge of the sprite against the left edge of the screen. This also works for scenes, as you encountered - moving the anchorPoint of the scene moves everything in the scene relative to its size.
You don't need three images for what you're describing. You can use a single sprite and just set its centerRect property to tell it to use the top and bottom of an image and stretch the center part vertically. You have to do a little math to set the right xScale and yScale (not width and height, IIRC), but then you can draw all of that with one sprite instead of three. This would be really handy in your case, because you could just leave the sprite at (0,0), set its scale to match the size of the entire scene, and set the centerRect property - you wouldn't have to do any positioning math at all.

Use UIPanGestureRecognizer to drag view from one position to limited position

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.

Swift: Which direction a UIView is being intersected from?

I am using CGRectIntersectsRect to test if blueView (being dragged) has intersected with redView (stationary). However, I need to know if redView was intersected by blueView from red's top, bottom, right or left?
Is there a CG method to accomplish this?
I'm not aware of any CG Method to accomplish this.
The way I'd go about this is using CGRectIntersectsRect to check if they intersect at all, then if they do intersect, measure from the center of redView to blueView which would return the distance between them (X and Y), from that you could possibly tell from which angle the intersection was coming from?
If you wanted a little more accuracy you could measure from redView top center, to blueView bottom center, and the same for all 4 edges? Then work out which is the closest?
There are multiple ways you could approach this problem but I'm not aware of a 'one method fits all' solution.
Edit:
Was still thinking about this, I think the most accurate way would be something like this:
let leftDistance = blue.origin.x - (red.origin.x + red.width)
let rightDistance = (blue.origin.x + blue.width) - red.origin.x
let topDistance = blue.origin.y - (red.origin.y + red.height)
let bottomDistance = (blue.origin.y + blue.height) - red.origin.y
The the lowest of those distance = coming from the left, right, top or bottom.
(P.s. I might have gotten blue + Red the wrong way around, as well as top and bottom. I'd recommend just having a play around and logging these values while dragging the item)
Here is the solution I finally used, In case someone else is looking for it. Below line of code test if the intersection is vertical (top & bottom views intersected), where a and b are view.frame for each of the two view intersecting.
if ((a.maxY > q.maxY) && (b.minY < q.minY)) || ((a.maxY < q.maxY) && (b.minY > q.minY))

Detect rotation of subviews

I have a view containing several subviews. I can detect and let the user rotate just one subview or the containing view using UIRotationGestureRecognizer. But I would like to be able to rotate any square collection of subviews, like so:
Initial state:
Rotating upper right square counter-clockwise
To get here
How can I achieve this behavior?
How should I nest my view hierarchy?
Any pointers are appreciated :)
here's what I would do (pseudocode):
when rotation recognized:
create new_layer
new_layer.bounds = union_rect( frames of tiles to be rotated )
new_layer addSublayers:(tiles to be rotated)
while rotation in progress:
new_layer.transform = CATransform3DMakeRotation( angle, 0, 0, 1 )
when rotation complete:
(original view).layer addSublayers:(tiles to be rotated)
(tiles to be rotated) rearrange after rotation

Positioning a view after transform rotation

I'm creating a custom popover background, so I subclassed the UIPopoverBackground abstract class. While creating the layout function I came across a problem with placing and rotating the arrow for the background.
The first picture shows the arrow at the desired position. In the following code I calculated the origin I wanted but the rotation seemed to have translated the new position of the image off to the side about 11 points. As you can see, I created a hack solution where I shifted the arrow over 11 points. But that still doesn't cover up the fact that I have a gapping hole in my math skills. If someone would be so kind as to explain to me what's going on here I'd be eternally grateful. What also would be nice is a solution that would not involve magic numbers, so that I could apply this solution to the cases with the up, down and right arrow
#define ARROW_BASE_WIDTH 42.0
#define ARROW_HEIGHT 22.0
case UIPopoverArrowDirectionRight:
{
width -= ARROW_HEIGHT;
float arrowCenterY = self.frame.size.height/2 - ARROW_HEIGHT/2 + self.arrowOffset;
_arrowView.frame = CGRectMake(width,
arrowCenterY,
ARROW_BASE_WIDTH,
ARROW_HEIGHT);
rotation = CGAffineTransformMakeRotation(M_PI_2);
//rotation = CGAffineTransformTranslate(rotation, 0, 11);
_borderImageView.frame = CGRectMake(left, top, width, height);
[_arrowView setTransform:rotation];
}
break;
Well, if the rotation is applied about the center of the arrow view (as it is), that leaves a gap of (ARROW_BASE_WIDTH - ARROW_HEIGHT) / 2 to the post-rotation left of the arrow, which is what you have to compensate for, it seems. By offsetting the center of the arrow view by this much, it should come back into alignment.

Resources