How to change center of object? - ios

This is the code I'm using to center my button to the bottom of the screen:
CGFloat centro = self.view.center.x;
CGFloat bottom = CGRectGetMaxY(self.view.frame);
_sendButton.center = CGPointMake(centro, bottom);
However, the actual center of the button is set to be at the bottom of the screen, which covers half the button. How can I set it so that the very lowest point on the button is set to:
CGPointMake(centro,bottom)
instead?

You need to subtract half the height of the button:
CGFloat centro = self.view.center.x;
CGFloat bottom = CGRectGetMaxY(self.view.frame) - _sendButton.frame.size.height / 2.0;
_sendButton.center = CGPointMake(centro, bottom);

Related

How to get button x,y coordinate in a textfield

I have 4 different buttons for every corner of the screen. Just need to show their coordinates for every device changes in a text field or a label.
“x0” - button x coordinate on the screen
“y0” - button y coordinate on the screen
i should show like x = "x0" ; y = "y0"
There is an easy built-in way to log frames. Use NSStringFromCGRect(frame); to show the coordinates of the button.
Although you can directly print a CGRect using NSStringFromCGRect, here is a sample of what you are looking for. I'm just putting button1's coordinates in text field.
UIButton *button1, *button2, *button3, *button4;
CGFloat button1X = button1.frame.origin.x;
CGFloat button1Y = button1.frame.origin.y;
CGFloat button2X = button2.frame.origin.x;
CGFloat button2Y = button2.frame.origin.y;
CGFloat button3X = button3.frame.origin.x;
CGFloat button3Y = button3.frame.origin.y;
CGFloat button4X = button4.frame.origin.x;
CGFloat button4Y = button4.frame.origin.y;
NSString *button1Coords = [NSString stringWithFormat:#"x = \"%f\" x = \"%f\"", button1X, button1Y];
self.textField.text = button1Coords;

How to find UIView origin using ratio?

I have 2 UIImageView. Both UIImageView has the same size proportion. The first UIImageView's size is always smaller or equal to the second UIImageView's size.
On the first UIImageView I have a UIView. This UIView the user can place it anywhere on the first UIImageView.
I want to find the x,y of the second UIView that will be on the second UIImageView with same proportion as the first UIView.
Please look at this image to be clear. Please note that Rectangle 1 is first UIImageView and Rectangle 2 is second UIImageView.
What I've tried:
CGFloat xMultiplier = imageView2.frame.size.width / imageView1.frame.size.width;
CGFloat yMultiplier = imageView2.frame.size.height / imageView1.frame.size.height
CGFloat view2x = view1.frame.origin.x * xMultiplier;
CGFloat view2y = view1.frame.origin.y * yMultiplier;
My application is an application that users can choose stickers (UIView) and place it anywhere on their photo. The stickerView on the second image is not in the same place as stickerView in the second image
The resulting x,y for my code is close to where it should be but its not exactly where it should be.
What am I missing?
Thanks!
First you should get the factor ( which you are already doing correctly ) , but then you have to calculate it proportionally to Point1 ( to some point in View1 ) , for example
CGFloat yFactor = view1.frame.size.height / view2.frame.size.height;
CGFloat xFactor = view1.frame.size.width / view2.frame.size.width;
CGPoint pointInView2 = CGPointMake(pointInView1.x / xFactor,pointInView1.y / yFactor);
pointInView1 is the origin of Sticker in View1
if sticker2 is subview of view2 , then origin will be pointInView2
if sticker2 is not subview of view2 , and they have the same superview , the origin will
CGPointMake(pointInView2.x + view2.frame.size.width,pointInView2.y + view2.frame.size.height);
if there is any other hierarchy , you can use UIVIews method convertPoint ...
[view2 convertPoint:pointInView2 toView:sticker2.superView]
assuming that the rectangle 2 is merely a rescaled version of rectangle 1. the position of view 2 is :
xpos_view2 = xpos_view1/xwidth_Rect1 * xwidth_Rect2
ypos_view2 = ypos_view1/ywidth_Rect1 * ywidth_Rect2
View2.position = CGPoint(x:xpos_view2, y:ypos_view2)
Calculate Ratio from smallest iPhone device
func ratioW(_ ofSize : CGFloat) -> CGFloat {
let bounds = UIScreen.main.bounds
let windowWidth = bounds.size.width
let temp = 320/ofSize
return windowWidth / temp
}
func ratioH(_ ofSize : CGFloat) -> CGFloat {
let bounds = UIScreen.main.bounds
let windowHeight = bounds.size.height
let temp = 480/ofSize
return windowHeight / temp
}

Scaling arc4random for different screen sizes

I'm making a game that doesn't use Autolayout, and have used constraints to scale everything and it worked perfectly. However I cant seem to figure this out, I'm using arc4random to randomly position X and Y coordinates of a UIButton on the 4.7 inch screen. When I try running it on the smaller screen it plots the UIButton off the screen at times. How can I scale arc4random up and down depending on screen size.
-(void)position{
Randompositionx = arc4random() %270;
Randompositionx = Randompositionx + 51;
Randompositiony = arc4random() %411;
Randompositiony = Randompositiony +163;
UIButton.center = CGPointMake(Randompositionx, Randompositiony);
}
You should be using arc4random_uniform rather than arc4random and the modulo operator. It gives numbers without "modulo bias".
You need to adapt the upper value of your random number based on screen size. T_77's answer was a step in the right direction, but still not right.
The code below assumes the button you want to move is called myButton.
It uses margin values of 20 all around. Change the values as desired.
EDIT: I updated it to use the height and width of the button in the position calculation. With the updated code the button should never be closer to any edge than the margin value, even if the button size changes. No magic numbers, either. It should adapt to the size of it's superview.
-(void)position
{
CGRect frame = myButton.superview.bounds;
CGFloat leftMargin = 20; //use whatever values you want for magins
CGFloat rightMargin = 20;
CGFloat topMargin = 20;
CGFloat bottomMargin = 20;
CGFloat randomX, randomY;
CGFloat xMax = frame.size.width-leftMargin-rightMargin-
button.bounds.size.width/2;
randomX = arc4random_uniform(xMax) + leftMargin;
CGFloat yMax = frame.size.height-topMargin-bottomMargin-
button.bounds.size.height/2;
randomY = arc4random_uniform(yMax) + topMargin;
myButton.center = CGPointMake(randomX, randomY);
}
Also note that if you're using auto layout you shouldn't move the button's position directly, and instead should have position constraints and modify their constants, then call layoutIfNeeded. Otherwise the first thing that causes your layout to change will cause your button to revert to it's previous position.
Try this
-(void)position{
CGRect frame = [self.view frame];
Randompositionx = arc4random() %270;
Randompositionx = Randompositionx + CGRectGetMinX(frame);
Randompositiony = arc4random() %411;
Randompositiony = Randompositiony +CGRectGetMinY(frame);
UIButton.center = CGPointMake(Randompositionx, Randompositiony);
}
Now you can position your UIButton within your view.

Find bounds of UIViewController's view not obscured by UINavigationBar, UITabBar, (etc)

I can configure my UIViewController's edgesForExtendedLayout so that it will extend underneath content such as the navigation bar or tab bar. If I do this, is there some way to determine the frame that is not obscured?
As a possible alternative, is there a way for a UIViewController to determine the default contentInset to apply to a UIScrollView it contains?
Use case
I have zoomable UIScrollView containing an image.
When it is fully zoomed out I want to adjust the content inset too allow the content to stay centred (details here). However, my modified insets don't take in to account the insets that the UIViewController applies automatically so that its content isn't obscured by navigation bars, etc.
I also need to compute the minimum zoom for the content – that at which the whole image will be visible and not obscured. To compute this, I need to know the size of the unobscured part of the content view.
You need this
-(CGRect) unobscuredBounds
{
CGRect bounds = [self.view bounds];
return UIEdgeInsetsInsetRect(bounds, [self defaultContentInsets]);
}
-(UIEdgeInsets) defaultContentInsets
{
const CGFloat topOverlay = self.topLayoutGuide.length;
const CGFloat bottomOverlay = self.bottomLayoutGuide.length;
return UIEdgeInsetsMake(topOverlay, 0, bottomOverlay, 0);
}
You could put this in a category for easy reusability.
These methods correctly handle the changes that occur when the view resizes after a rotation – the change to the UINavigationBar size is correctly handled.
Centring Content
To use this to centre content by adjusting insets, you'd do something like this:
-(void) scrollViewDidZoom:(UIScrollView *)scrollView
{
[self centerContent];
}
- (void)centerContent
{
const CGSize contentSize = self.scrollView.contentSize;
const CGSize unobscuredBounds = [self unobscuredBounds].size;
const CGFloat left = MAX(0, (unobscuredBounds.width - contentSize.width)) * 0.5f;
const CGFloat top = MAX(0, (unobscuredBounds.height - contentSize.height)) * 0.5f;
self.scrollView.contentInset = UIEdgeInsetsMake(top, left, top, left);
}
Your content insets will now reflect the default insets that they need (to avoid being covered up) and will also have the insets they need to be nicely centred.
Handling Rotation & Zoom
You probably also want to perform centring when animating between landscape and portrait. At the same time, you might want to adjust your minimum zoom scale so that your content will always fit. Try out something like this:
-(void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self centerContent];
const bool zoomIsAtMinimum = self.scrollView.zoomScale == self.scrollView.minimumZoomScale;
self.scrollView.minimumZoomScale = [self currentMinimumScale];
if(zoomIsAtMinimum)
{
self.scrollView.zoomScale = self.scrollView.minimumZoomScale;
}
}
-(CGFloat) currentMinimumScale
{
const CGFloat currentScale = self.scrollView.zoomScale;
const CGSize scaledContentSize = self.scrollView.contentSize;
const CGSize scrollViewSize = [self unobscuredBounds].size;
CGFloat scaleToFitWidth = currentScale * scrollViewSize.width / scaledContentSize.width;
CGFloat scaleToFitHeight = currentScale * scrollViewSize.height / scaledContentSize.height;
return MIN(scaleToFitWidth, scaleToFitHeight);
}
The willAnimateRotationToInterfaceOrientation:… method is called within the view animation block, so the changes that it applies will lead to nice smooth animated changes as you switch from landscape to portrait.

custom map annotation callout - how to control width

I've successfully implemented the custom map annotation callout code from the asynchrony blog post .
(When user taps a map pin, I show a customized image instead of the standard callout view).
The only remaining problem is that the callout occupies the entire width of the view, and the app would look much better if the width corresponded to the image I'm using.
I have subclassed MKAnnotationView, and when I set it's contentWidth to the width of the image, the triangle does not always point back to the pin, or the image is not even inside it's wrapper view.
Any help or suggestions would be great.
Thanks.
I ran into a similar problem when implementing the CalloutMapAnnotationView for the iPad. Basically I didn't want the iPad version to take the full width of the mapView.
In the prepareFrameSize method set your width:
- (void)prepareFrameSize {
// ...
// changing frame x/y origins here does nothing
frame.size = CGSizeMake(320.0f, height);
self.frame = frame;
}
Next you'll have to calculate the xOffset based off the parentAnnotationView:
- (void)prepareOffset {
// Base x calculations from center of parent view
CGPoint parentOrigin = [self.mapView convertPoint:self.parentAnnotationView.center
fromView:self.parentAnnotationView.superview];
CGFloat xOffset = 0;
CGFloat mapWidth = self.mapView.bounds.size.width;
CGFloat halfWidth = mapWidth / 2;
CGFloat x = parentOrigin.x + (320.0f / 2);
if( parentOrigin.x < halfWidth && x < 0 ) // left half of map
xOffset = -x;
else if( parentOrigin.x > halfWidth && x > mapWidth ) // right half of map
xOffset = -( x - mapWidth);
// yOffset calculation ...
}
Now in drawRect:(CGRect)rect before the callout bubble is drawn:
- (void)drawRect:(CGRect)rect {
// ...
// Calculate the carat lcation in the frame
if( self.centerOffset.x == 0.0f )
parentX = 320.0f / 2;
else if( self.centerOffset.x < 0.0f )
parentX = (320.0f / 2) + -self.centerOffset.x;
//...
}
Hope this helps put you on the right track.

Resources