UIImage in scrollview too big - ios

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];

Related

Autoresizing not working for UIView added programatically

I have followed this SO link for autoresizing, but Autoresizing not working.
How to set frame programmatically with autoresizing?
I have set frame for iPhone 4
UIView *box = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 120)];
[box setBackgroundColor:[UIColor redColor]];
[box setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[box setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[box setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin];
[box setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
[box setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
[self.view addSubview:box];
But it is not working in iPad or iPhone 6
First thing first : As per open suggestion, you should use constraints.
Add autoresizing mask after adding it to view.
UIView *box = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 120)];
[box setBackgroundColor:[UIColor redColor]];
[self.view addSubview:box];
[box setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
[box setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[box setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin];
[box setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
[box setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
If I understand you question correctly you're trying to set red view on top with height = 120
ADD EXPLANATION
You could achieve it with using constraints:
UIView *box = [[UIView alloc] init];
// Prevent creating constraints from masks automatically
box.translatesAutoresizingMaskIntoConstraints = NO;
box.backgroundColor = [UIColor redColor];
[self.view addSubview:box];
// Define metrics (constants) which will be used to create constraints.
// Key #"boxSize" - name which will be used in constraints, Value - constant
NSDictionary *metrics = #{#"boxSize" : #(120)};
// Define views that will participate in auto layout constraints.
// Key #"readBox" - name which will be used in constraints, Value - real UIView object
NSDictionary *views = #{ #"redBox" : box };
// Here we create constraints. For Vertical, and for Horizontal
// I'm using Visual language format (you can find it in Apple Documentation
// In a few words:
// H:|-0-[redBox]-0-|
// "H" - means horizontal
// "|" - short cut for parent view (in our case it is UIViewController.view)
// "[redBox]" - view name from view's dictionary
// "-0-" - gap between views (you could set number), in our case it is "|" and "[redBox]"
// "[redBox(boxSize)]" - means that view (redBox) size should be qual to "boxSize" from metrics' dictionary
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-0-[redBox]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-0-[redBox(boxSize)]" options:NSLayoutFormatAlignAllCenterY metrics:metrics views:views]];
Apple Documentation
You are setting a UIView with a frame (0, 0, 320, 120). This frame will fit the iPhone 4 screen, as the phone screen width is 320 pixels. But you cant expect same when you run the code in iPhone 6/6s. Setting Autoresizing will not handle this. You need to use constraints/autolayout for that.
Autoresizing masks describe how a subview will resize or move when its superview is resized.
So after adding this view, if you change the phone orientation, this will resize the view in position accordingly. But you need to set the frame according to the superview first. You can set the width dynamically, like: (0, 0, self.view.frame.size.width, 120).

How to create three views using autolayout, with one fix width height and other two growing height

I am trying to create a view setup vertically where i have one UIView (fixed width, height) at the top and two UILabels (fixed width, dynamic height) at the bottom. Padding all around the view (aView) is 5. Padding all around of _mylabel is 5. Padding on left and right of _yourLable is 5. _yourLable will grow as based on text, but when text content is too large, it will just stop to grow for maintain padding from superview of 5.
This is what i have tried:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *superview = self.view;
UIView *aView = [UIView new];
[aView setBackgroundColor:[UIColor blackColor]];
[aView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:aView];
_mylabel = [[UILabel alloc]init];
[_mylabel setNumberOfLines:0];
[_mylabel setBackgroundColor:[UIColor redColor]];
[_mylabel setTranslatesAutoresizingMaskIntoConstraints:NO];
_mylabel.text = #"i am trying to create a view setup vertically where i have one UIView(fix width, height) at top and other two UILables(fix width, dynamic height) at bottom respectively. Padding on allaround of view/lables is 5. this is what i have tried:";
[self.view addSubview:_mylabel];
_yourLable = [[UILabel alloc]init];
[_yourLable setNumberOfLines:0];
[_yourLable setBackgroundColor:[UIColor redColor]];
[_yourLable setTranslatesAutoresizingMaskIntoConstraints:NO];
_yourLable.text = #"i am trying to create a view setup vertically where i have one UIView(fix width, height) at top and other two UILables(fix width, dynamic height) at bottom respectively. Padding on allaround of view/lables is 5. this is what i have tried:";
[self.view addSubview:_yourLable];
NSDictionary * views = NSDictionaryOfVariableBindings(aView,_mylabel, _yourLable, superview);
NSArray * heightConstraintforLabel = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|-5-[aView(==200)]-5-[_mylabel]-5-[_yourLable]-5-|" options:0 metrics:nil views:views];
NSArray * widthConstraintforView = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[aView]-5-|" options:0 metrics:nil views:views];
NSArray * widthConstraintformylabel = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[_mylabel]-5-|" options:0 metrics:nil views:views];
NSArray * widthConstraintforyourLable = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|-5-[_yourLable]-5-|" options:0 metrics:nil views:views];
[superview addConstraints:heightConstraintforLabel];
[superview addConstraints:widthConstraintforView];
[superview addConstraints:widthConstraintformylabel];
[superview addConstraints:widthConstraintforyourLable];
}
and
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
// Your layout logic here
CGFloat availableLabelWidth = _mylabel.frame.size.width;
_mylabel.preferredMaxLayoutWidth = availableLabelWidth;
availableLabelWidth = _yourLable.frame.size.width;
_yourLable.preferredMaxLayoutWidth = availableLabelWidth;
}
This is what i am getting, without warnings:
I want both labels to resize based on exact text height.
I want last red label to grow as per text written in it, but never go beyond bottom space of 5. That is it should grow but maintain bottom padding of 5.
I have tried various combination with vertical content compression for labels..., but not got exact solution.
Help :)
Just in case you have not set the priorities, use
[_mylabel setContentCompressionResistancePriority:751 forAxis:UILayoutConstraintAxisVertical];
[_mylabel setContentHuggingPriority:252 forAxis:UILayoutConstraintAxisVertical];
You don't need to set any priorities for _yourLable.
And you don't need to set the preferredMaxLayoutWidth for any of the labels in viewWillLayoutSubviews, hence you don't need to override viewWillLayoutSubviews. You can comment the whole method.
Verified on iOS 7 and iOS 9 devices.
Simulator screenshot looks like this,

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.

UIImage moves right on rotation - wrong center point?

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

Resources