UIScrollView and UIImageView - move horizontally - ios

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.

Related

Calculating Visible CGRect to crop a UIImageView [duplicate]

This question already has answers here:
How to crop a UIImageView to a new UIImage in 'aspect fill' mode?
(2 answers)
Closed 4 years ago.
I have a UIView. There is a UIImageView inside that UIView. UIImageView doesn't comply to autolayout constraints. Parent UIView's bounds are clipped.
Now content mode of UIImageView is Aspect Fill, but the size of UIImageView is always calculated and set to size of UIImage that is being rendered. So UIImageView's size will always be equal to size of UIImage.
Now UIImageView can be positioned. It has a pan gesture applied to it. UIImageView is being moved within the parent UIView based on requirement of user.
My task is to crop the UIImage of UIImageView to the visible viewport of parent UIVIew only. Core Cropping the image is not issue but finding the visible rect is.
My solution which is not working was to convert frame of parent UIView and child UIImageView to window screen. Then find the intersection of new converted frames. But this is not working. There should be some simple mathematics behind this which I am not able to come up successfully.
This is my code so far.
CGRect imgFrame = [_pageImageView convertRect:_pageImageView.frame toView:nil];
CGRect viewportFrame = [_viewportView convertRect: _viewportView.frame toView:nil];
CGRect visibleRect = CGRectIntersection(imgFrame, viewportFrame);
CGImageRef imageRef = CGImageCreateWithImageInRect([_pageImageView.image CGImage], visibleRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
My objective is to find the visible rect that is visible through clipped parent UIVIew, then crop the UIImageView based on that visible rect. Important note: UIImageView can be positioned and moved within parent UIView.
EDIT: I can't use UIScrollView for cropping as used in many other discussions for my internal reasons.
You can place the image view inside the UIScrollView instead of UIView which make the pan gesture work easier.
I have the scrollview have the UIImageView
- (CGRect)imageCropRect
{
CGSize imageSize = self.image.size;
CGSize contentSize = self.contentSize;
CGRect cropBoxFrame = self.frame;
CGPoint contentOffset = self.contentOffset;
UIEdgeInsets edgeInsets = self.contentInset;
CGRect frame = CGRectZero;
frame.origin.x = floor((contentOffset.x + edgeInsets.left) * (imageSize.width / contentSize.width));
frame.origin.x = MAX(0, frame.origin.x);
frame.origin.y = floor((contentOffset.y + edgeInsets.top) * (imageSize.height / contentSize.height));
frame.origin.y = MAX(0, frame.origin.y);
frame.size.width = ceil(cropBoxFrame.size.width * (imageSize.width / contentSize.width));
frame.size.width = MIN(imageSize.width, frame.size.width);
frame.size.height = ceil(cropBoxFrame.size.height * (imageSize.height / contentSize.height));
frame.size.height = MIN(imageSize.height, frame.size.height);
return frame;
}

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

Reduce a UIView's Height From the Top Down?

Resizing a UIView's height can be done by modifying it's frame.size.height property OR by modifying it's NSLayoutHeight constraint. However, by default, reducing a UIView's height will cut off the UIView from the bottom up, I need to reduce a UIView's height from the top down. Is this possible?
Adjust the origin.y of the view as you change the height.
CGFloat const delta = 100;
[aView setFrame:CGRectMake(CGRectGetMinX([aView frame]), CGRectGetMinY([aView frame]) + delta, CGRectGetWidth([aView bounds]), CGRectGetHeight([aView bounds]) - delta)];
You will need to adjust the origin of the frame as well.
Eg:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 20.0, 40.0)];
to change the height to 30.0 from the 'top down' do:
view.frame = CGRectMake(0.0, 10.0, 20.0, 30.0);
Create container UIView with clipsToBounds == YES, and move your view inside the container view.
Just like clipping mask in drawing software.

UIImageView and autolayout

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

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

Resources