UIImageView and autolayout - uiview

I have a view that is set up nicely using autolayout. The view contains a series of labels stacked from top to bottom. I am allowing the intrinsic size of these labels to determine the size of the view.
The final step is to add a background from an image. I started by trying the colorWithPatternImage method on UIColor but this isn't quite what I am looking for. I do not want to tile the image, and I can not guarantee it will always be larger than the intrinsic size of the view.
Similarly, adding a uiImageView to the view itself doesn't quite work. The view will expand to accommodate the image when I want to keep the intrinsic size based on the labels.
I guess what I am looking for is the following.
1) The background should have no effect on the size of the view.
2) The image should be scaled to fill the view but in it's original aspect ration (so cropping edges if necessary).
Any ideas appreciated.

In my case, I needed it for a UIImageView inside a dynamically-sized view in a UITableViewCell, but the image refused to shrink below its instristic size and instead worked as a minimum-size constraint for the superview. The only way I could get it ignore the intristic size is by lowering the priority at which it is enforced, right after creating the cell:
[imageView setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisHorizontal];
[imageView setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
forAxis:UILayoutConstraintAxisVertical];
After this, all my constraints magically started working. In the OP's case, setting UIViewContentModeScaleAspectFill is also required, as per Mundi's answer.

In Interface Builder, add a UIImageView as the first subview to the view. Make sure its size always matches the view.
Then, in Interface Builder or code, set the contentMode:
backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;

Here's how I would approach this. Hopefully it helps. :)
CGRect contentFrame = CGRectMake(0, 0, self.view.frame.size.width, 0); // This will be the frame used to create the background image view.
UIEdgeInsets contentInsets = UIEdgeInsetsMake(20, 20, 20, 20); // The margins by which the labels will be inset from the edge of their parent view.
CGFloat labelHeight = 21;
CGFloat verticalGap = 8; // The vertical space between labels
CGFloat y = contentInsets.top;
int numberOfLabels = 10;
for (int i = 0; i < numberOfLabels; i++) {
CGRect frame = CGRectMake(contentInsets.left, y, self.view.frame.size.width - (contentInsets.left + contentInsets.right), labelHeight);
UILabel *label = [[[UILabel alloc] initWithFrame: frame] autorelease];
// customize the label here
[self.view addSubview: label];
contentFrame = CGRectUnion(contentFrame, label.frame);
y += labelHeight + verticalGap;
}
contentFrame.size.height += contentInsets.bottom;
UIImageView *backgroundImageView = [[[UIImageView alloc] initWithFrame: contentFrame] autorelease];
[backgroundImageView setClipsToBounds: YES];
[backgroundImageView setContentMode: UIViewContentModeScaleAspectFill];
[backgroundImageView setImage: [UIImage imageNamed: #"background_image.png"]];
[self.view insertSubview: backgroundImageView atIndex: 0];

Related

UIButton Title Label Not Filling When Text Alignment Is Centered

I have a UIButton and am trying to center the text. The below works, but it cuts off my button's titleLabel way before the end of the button. I want it to grow until the edge of the subview, i.e. a CGRect frame of (8+9,button height ,button width - 8 - 9, button height)
self.setDestinationButton.titleLabel.textAlignment = NSTextAlignmentCenter;
self.setDestinationButton.layer.masksToBounds = NO;
self.setDestinationButton.titleLabel.adjustsFontSizeToFitWidth = YES;
self.setDestinationButton.titleLabel.minimumScaleFactor = .75;
self.setDestinationButton.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
UIImageView *destinationIcon = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"grey_dot"]];
destinationIcon.frame = CGRectMake(8, 18 ,9, 9);//choose values that fit properly inside the frame of your baseButton
//or grab the width and height of yourBaseButton and change accordingly
destinationIcon.contentMode=UIViewContentModeScaleAspectFill;//or whichever mode works best for you
[self.setDestinationButton addSubview:destinationIcon];

Rotate a UIlabel to make it vertical

I have a UILabel. I need to rotate it programmatically.
I have my horizontal UILabel, for example with frame: x:0, y:0, w: 200, h:80.
Now I would like to rotate the label to make it vertical:
I try this code:
[self setTransform:CGAffineTransformMakeRotation(M_PI_2 / 2)];
I can see the contained text rotated. But I would like to rotate the whole frame: With my code, the UILabel continues to have the same frame.
Try this working code:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 100, 200, 80)];
//set background color to see if the frame is rotated
[label setBackgroundColor:[UIColor redColor]];
[label setText:#"Text Here"];
label.transform=CGAffineTransformMakeRotation( ( 90 * M_PI ) / 180 );
[self.view addSubview:label];
Hope it helps
If you prefer set the label position and size visually in you xib or storyboard do the following:
Set the labels position and size in the interface builder like you want them to stay after the rotation.
Rotate the label and set the frame again:
-(void)rotateLabel:(UILabel*) label
{
CGRect orig = label.frame;
label.transform=CGAffineTransformMakeRotation(M_PI * 3/2);//270º
label.frame = orig;
}
Your Label is a square(w:100,h:100).So your label has transformed, but you can't see the change,because the width is equal to the height.

UIScrollView and UIImageView - move horizontally

I have UIScrollView with UIImageView on it. I set image in code and it can have different width (height is always the same). I want to do it scrollable (eg. see only part of it and drag it to left / right to see the rest).
I have this code performed after image change:
float x = self.imageView.frame.origin.x;
float y = self.imageView.frame.origin.y;
float w = scaleImg.size.width;
float h = scaleImg.size.height;
self.imageView.frame = CGRectMake(x, y, w, h);
self.imageView.bounds = CGRectMake(0, 0, w, h);
w = self.frame.size.width;
h = self.scrollView.frame.size.height;
[self.scrollView setContentSize: CGSizeMake(w + 20, h)];
Problem is, that it didn't scroll correctly (I think it didn't scroll at all). And after I scroll, my image is resized, not respecting the frame I have set above.
I am using iOS7, storyboard, autolayout.
If you want the image to fit the scrollview and be scrollable left and right only you should create the image view with height same as the scrollview and width scaled accordingly to the image. Try something like this:
UIImage *image;
UIScrollView *scrollView;
UIImageView *imageView;
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(.0f,
.0f,
scrollView.frame.size.height*image.size.width/image.size.height,
scrollView.frame.size.height)];//fixed height
imageView.image = image;
imageView.contentMode = UIViewContentModeScaleToFill;
[scrollView addSubview:imageView];
scrollView.contentSize = imageView.frame.size;
scrollView.contentOffset = CGPointMake((scrollView.contentSize.width-scrollView.frame.size.width)*.5f, .0f);//scroll to center
Note I designed this only for images which have proportionally larger width then scrollview. If that is not always the case you should create a specific logic for other images (either background is visible or it is scrollable in Y coordinate).
I guess you should remove the following lines:
w = self.frame.size.width;
h = self.scrollView.frame.size.height;
scrollView's content size should reflect size of enclosed content, i.e. it should be scaleImg.size.width & scaleImg.size.height.
you given the w as the width for both scrollview and imageview....content size should be more than scroll view.Try giving imageview width more than scrollview.

Stopping UIScrollView at specific place while scrolling with pagingEnabled

I have the following code to create a scroll view with additional area at the beginning and the end of the images (50 points).
UIScrollView* scroll = [[UIScrollView alloc] initWithFrame: CGRectMake(0,0,200,100)];
scroll.contentSize = CGSizeMake(400,100);
UIImageView* img1 = [[UIImageView alloc] initWithFrame: CGRectMake(50,0,100,100);
UIImageView* img2 = [[UIImageView alloc] initWithFrame: CGRectMake(150,0,100,100);
UIImageView* img3 = [[UIImageView alloc] initWithFrame: CGRectMake(250,0,100,100);
//Adding images to ImageViews
scroll.pagingEnabled = YES;
[scroll addSubView:img1];
[scroll addSubView:img2];
[scroll addSubView:img3];
The first time I see the view, I will see the additional area on the left (0-50), then the first image (50-150) and then half of the second image (150-200).
When I swipe left, I want to see half of the first image on the right, the second image at the center, and half of the third image on the right.
When I swipe left again, I want to see the third image at center, with half of the second image on the left, and the additional area on the right.
Can it be possible?
It's possible as long as you define everything correctly. Make sure that the assigned content size is equal to the overall size that you wish to scroll through. Make sure that each page size is equal to the scroll view's frame. You can set the clipsToBounds to NO if the frame clips your subviews.
You can do this by adjusting the contentSize of UIScrollView
- (void)addImagesToScrollView{
//An offset from where imageViewStarts
CGFloat xOffset = 50.0f;
CGRect imageViewFrame = CGRectMake(xOffset, 0.0f, 100.0f, 100.0f);
for (NSString *imageName in #[#"image1.jpg",#"image2.jpg",#"image3.jpg"])
{
UIImageView *imageView = [[UIImageView alloc]initWithFrame:imageViewFrame];
UIImage *image = [UIImage imageNamed:imageName];
imageView.image = image;
[self.scrollView addSubview:imageView];
imageViewFrame.origin.x+=imageViewFrame.size.width;
}
CGSize contentSize = self.scrollView.frame.size;
//Content size is calculate from the imageViewFrame and an offset is added to it
contentSize.width = imageViewFrame.origin.x+xOffset;
[self.scrollView setContentSize:contentSize];
}
Source Code
You can scroll to a particular place in the scrollview using the following code
[YOURSCROLLVIEW setContentOffset:CGPointMake(x, y) animated:YES];

IOS: UIScrollView with an infinite paging view

I have this code for a scrollview to showe 3 images:
const CGFloat kScrollObjHeight = 150.0;
const CGFloat kScrollObjWidth = 320.0;
const NSUInteger kNumImages = 3;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
scrollView2.pagingEnabled = YES;
scrollView3.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
//[scrollView2 addSubview:imageView];
//[scrollView3 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
But now I want to do a scrollview that when is in last image show me after the first image of scroll view and the same thing when I have the first image if I go back, it must show the last image; so I want create a paging loop.
The basic idea is to set yourself as a UIScrollViewDelegate and apply some modulo arithmetic to the scroll position in order to wrap it around.
There are two basic variations on the idea. Suppose your images are A, B, C, so you currently have them within the scrollview ordered as ABC.
In the more logically pleasing solution — especially if you had lots and lots of images — you watch the scroll position and as soon as it gets to a position where the view is being pushed rightward and C has left the screen, you reorder the images as CAB and shift the current scroll position one spot to the right so that the move is invisible to the user. To put that another way, the scroll position is restrained to an area of two screens, centred on the middle of B (so, you get all of B and half a screen either side). Whenever you wrap it from somewhere on the left to somewhere on the right you shift all your image views one place to the right. And vice versa.
In the slightly easier to implement variation, instead of creating a scroll view with images arranged ABC, arrange then as CABCA. Then apply the same wrap around logic but to a central area of four screens and don't do any view reshuffling.
Make sure you use just setContentOffset: (or the dot notation, as in scrollView.contentOffset =) as a setter. setContentOffset:animated: will negate velocity.

Resources