UIImage moves right on rotation - wrong center point? - ios

When I rotate an image it moves right. It shouldn't. It seems like the center is set to the wrong point. See screenshot: In both states - rotated and not - the center of the "+" shouldn't change.
I am positioning a UIImageView using auto layout like this:
- (void)viewDidLoad {
...
addIconImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"AddCardIcon.png"]];
[addIconImageView setContentMode:UIViewContentModeCenter];
[addIconImageView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:addIconImageView];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:[addIconImageView]-(10)-|"
options:nil
metrics:nil
views:NSDictionaryOfVariableBindings(addIconImageView)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat: #"V:|-[addIconImageView]-|"
options:NSLayoutFormatAlignAllCenterY
metrics:nil
views:NSDictionaryOfVariableBindings(addIconImageView)]];
...
}
And here's what I do to rotate the image
[UIView animateWithDuration:0.2
animations:^{
addIconImageView.transform = CGAffineTransformRotate(addIconImageView.transform, M_PI/4);
} completion:^(BOOL finished) {
}
];
How come the move right on rotation and how can I avoid it?

My first guess is that your image asset isn't perfectly square.
Resize AddCardIcon.png so that it has identical width and height and doesn't have any transparent padding on any side.
Otherwise, manually determine the center of the + and set addIconImageView.layer.anchorPoint

Related

UIImage in scrollview too big

I am trying to show a UIImage inside a scrollview. The image is much larger in size than the scrollview, so it displays only the top-left corner of the image. I can then zoom / rearrange the image to fit a little better, but i want it to display the WHOLE image, centered and fitting inside. The user can then zoom around if he wants to, but the default should show entire image.
Here is my code (it downloads the image):
UIImage *trackImg = [UIImage imageWithContentsOfFile:trackImagePath];
/* Scrollview! */
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[imgView setImage:trackImg];
[[self scrImageViewer] addSubview:imgView];
_scrImageViewer.delegate = self;
_scrImageViewer.contentSize = trackImg.size;
_scrImageViewer.contentOffset = CGPointMake(trackImg.size.width/2, trackImg.size.height/2);
_scrImageViewer.minimumZoomScale = 1;
_scrImageViewer.maximumZoomScale = 4;
_scrImageViewer.zoomScale = 2;
_scrImageViewer.clipsToBounds = YES;
CGFloat newContentOffsetX = (_scrImageViewer.contentSize.width - _scrImageViewer.frame.size.width) / 2;
CGFloat newContentOffsety = (_scrImageViewer.contentSize.height - _scrImageViewer.frame.size.height) / 2;
_scrImageViewer.contentOffset = CGPointMake(newContentOffsetX, newContentOffsety);
Again, it shows only the top-left corner of image. I want it to display the whole image.
Thanks :)
In this image you can see a small scrollView (that square is the size of the scrollview) with a really big image inside (height is 1280 and the scroll view is only 100). The only thing you need to do is to add the constraints of your image to its superview (scrollView), in my case I added all 0 (top, leading, trailing and bottom) and the imageView mode is Center. Of course you need to add constraints from your scrollview to its superView, in this case the View.
If you need to add the imageView also programatically, if you can't use an outlet, you can make these changes on your code, but I would strongly recommend you use the storyboard solution:
imgView = [[UIImageView alloc] initWithImage:trackImg];
[self.scrImageViewer addSubview:imgView];
[imgView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.scrImageViewer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[view]|" options:0 metrics:nil views:#{ #"view": imgView }]];
[self.scrImageViewer addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[view]|" options:0 metrics:nil views:#{ #"view": imgView }]];
[self.view layoutIfNeeded];

Locating an image to centre of a view with auto layout programatically

I'm trying to locate a picture to centre of an view using NSLayoutConstraint like below:
NSInteger userPictureRadius = 50.0F;
UIImageView *imgv = [[UIImageView alloc] initWithFrame:CGRectMake(self.view.bounds.size.width / 2 - userPictureRadius,
self.topArea.bounds.size.height / 2 - userPictureRadius + 20,
userPictureRadius * 2,
userPictureRadius * 2)];
NSString *urlString= [NSString stringWithFormat:#"%#%#",[[Parameters sharedInstance] BASE_URL], [[MyCredentialStore sharedInstance] getPicturePath]] ;
[imgv sd_setImageWithURL:[NSURL URLWithString:urlString] placeholderImage:nil];
imgv.layer.cornerRadius = imgv.frame.size.height / 2;
imgv.layer.masksToBounds = YES;
imgv.layer.borderWidth = 0;
[imgv.layer setBorderColor: [[UIColor blackColor] CGColor]];
[imgv.layer setBorderWidth: 2.0];
[imgv setTranslatesAutoresizingMaskIntoConstraints:NO];
...
[self.topArea addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[imgv(100)]-|"
options:0
metrics:nil
views:elementsDictionary]];
[self.topArea addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[imgv(100)]-|"
options:0
metrics:nil
views:elementsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[_topArea]-|"
options:0
metrics:nil
views:elementsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[_topArea]-[_tableView]-|"
options:0
metrics:nil
views:elementsDictionary]];
I have two problems here:
The image appears on the top left side of the screen.
There is a blank space between top area and the screen borders.
Could you tell me what's wrong with my code?
Centering as such can't be done using the auto layout Visual Format Language (VFL). The VFL strings you've provided relate the edges of the image view to its superview by the standard distance. For example, H:|-[imgv(100)]-| establishes three constraints: the image view's leading edge equals its superview's leading edge plus the standard distance, the image view's width is 100 points, and the superview's trailing edge equals the image view's trailing edge plus the standard distance. That will have the result of dictating the size of both the image view and its superview. I guess the image view will be centered in its superview, but its superview may not be the size that you were expecting.
To center one view within another horizontally, use something like:
NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem:imgv
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:imgv.superview
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0];
[imgv.superview addConstraint:constraint];
You would do something similar for the vertical orientation. If you want to force the image view to a particular size, you can use separate constraints for that. (You could use VFL for that, if you prefer. It would be something like H:[imgv(100)]. Note that there's no relation to another view in there, just the width.)
If you are choosing Autolayouting makes no sense to use the manual coordinates
UIImageView *imgv = [[UIImageView alloc] initWithFrame:CGRectMake(self.view.bounds.size.width / 2 - userPictureRadius,
self.topArea.bounds.size.height / 2 - userPictureRadius + 20,
userPictureRadius * 2,
userPictureRadius * 2)];
Should become just
UIImageView *imgv = [[UIImageView alloc] init];
Show the code how you construct the elementsDictionary so I can try to help further.
Also would be better to post a small screenshot of what visual issue you are facing.

Use one background image programatically for both iPhone4 and iPhone5 with NSLayoutConstraint

I'm trying to avoid detecting whether I'm on iPhone 4 or 5 screen size by using NSLayoutConstraint. This is my code:
UIImageView *backgroundImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Flow-02"]];
[self.view addSubview:backgroundImage];
[self.view sendSubviewToBack:backgroundImage];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[backgroundImage]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(backgroundImage)]];
but it doesn't work.
My Flow-02 image has a resolution of 640x1136, so I was thinking this would make it fit the screen, but it doesn't. Is there a way to do it?
EDIT: Following rmaddy's answer below I added the line that sets the image's frame like this:
backgroundImage.frame = self.view.bounds;
It does set my image correctly on the iPhone 5 simulator, but on my iPhone 4s it's still stretched sideways.
Neither the autoresizingMask approach, nor the setting of V and H to the constraintsWithVisualFormat, suggested by Anindya Sengupta, have any effect.
Another option would be something like this:
UIImageView *backgroundImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Flow-02"]];
backgroundImage.contentMode = UIViewContentModeScaleToFill;
backgroundImage.frame = self.view.bounds;
backgroundImage.autoResizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:backgroundImage];
[self.view sendSubviewToBack:backgroundImage];
Keep in mind that either approach is only a good idea of the image looks OK when scaled as needed.
The problem is in the Visual Format you are setting.
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"|[backgroundImage]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(backgroundImage)]];
The above code it pinning the backgroundImage to the left and right side of the container. But the iPhone is not getting fat, right? So, lets do this additionally
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[backgroundImage]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(backgroundImage)]];
I just added V: which will tell the compiler to consider it vertically. For Horizontal it would have been H:
If you don't mention anything, by default it is "Horizontal" but it is a good practice to mention it always to make the code more understandable.

trying to specify MKMapView to within a frame but not working

I'm trying the simplest thing but it's not working correctly. I have a MKMapView called mapView in a controller and in the viewDidLoad, I'm doing:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect myRect=CGRectMake(10.0f, 10.0f, 100.0f, 100.0f);
self.mapView.frame = myRect;
}
but the MKMapView is still taking up the whole controller screen. What am I doing wrong?
thx
If you have autolayout enabled, it will not pay attention to the frame. If you want to adjust the mapView size and/or position, I would turn off autolayout or add constraints in code.
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(10)-[mapView(100)]" options:0 metrics:nil views:#{#"mapView" : self.mapView}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(10)-[mapView(100)]" options:0 metrics:nil views:#{#"mapView" : self.mapView}]];

Resizing UITextView Without Losing Constraints

I'm trying to figure out how to resize UITextView (and everything actually) without losing constraints. Basically, I'm trying to layout a page where most components can have variable sizes (like description). I tried doing it with a simple use case where I have a UITextView and a UIButton underneath. I want to make sure that the position of the button is relative to the bottom of the UITextView.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGRect frame = self.textView.frame;
int height = self.textView.contentSize.height;
frame.size.height = height;
self.textView.frame = frame;
}
What I ended up with is UITextView overlapping with UIButton. After doing a bit of research, it seems that if I replace the frame, all constraints are gone also. I tried copying the constraints over, but of course the pointer is still pointing at the old frame so that didn't help at all.
Is there a good way to solve a very dynamically laid out page? I'm trying to at least use interface builder rather than code everything.
EDITED
I tried updating the constraint as suggested, but that didn't actually resize the UITextView. Did I do it incorrectly? When I get the constant again, it's updated, but the height isn't changed visually. I did simplify my code by adding an IBOutlet for the constraint. Still no luck however.
int height = self.textView.contentSize.height;
self.textViewHeightConstraint.constant = height;
EDITED 2
I figured it out now. I had an extra constraint for the bottom and that was stopping me from actually resizing the UITextView.
The issue is how you've defined your button's top constraint. If it's to the label, when you adjust the label's height constraint, the button will move. For example, if doing it programmatically:
UILabel *label = [[UILabel alloc] init];
label.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:label];
label.text = #"Hello world";
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Submit" forState:UIControlStateNormal];
button.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:button];
NSDictionary *views = NSDictionaryOfVariableBindings(label, button);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[label]" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[button]" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-[label]-[button]" options:0 metrics:nil views:views]];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:20];
[label addConstraint:heightConstraint];
Then, if you change the label's height constraint, the button will move:
heightConstraint.constant = 100;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
}];
If you've defined your UI in Interface Builder, select the button and check the top constraint of the button and make sure it's to the label, not the superview:
But, again, if the button's top constraint is to the label, when the label's height constraint changes, the button will move.

Resources