Content of UIScrollView has offset below Navigation Bar - ios

I have a UIScrollView which contains a UIView, that in turn has an UIImageView and several UIButtons in it.
The problem I have is that the image is displayed about 20 px underneath my navigation bar.
People who seem to have similar problems had solutions like setting
self.automaticallyAdjustsScrollViewInsets = NO;
or just hide the status bar
- (BOOL)prefersStatusBarHidden {
return YES;
}
However, both solutions don't work for me. The first one sets the contents too high and adds the 20px space at the bottom instead. The second one hides the status bar , but the offset still remains.
Since I have a lot of the code from this tutorial by Ray Wenderlich and I have no idea where exactly in my code the problem lies, this is the link to code on github.
Can anyone help me?

I was able to figure out what is going on. Thanks for posting the link to your app.
The issue is this following code:
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
It turns out the contentsFrame.size.height is in fact less than bounds.Size.height when the map is first displayed. So your code is centering the image vertically. That's why you see that offset at the top. 17.279 pixels to be exact.
I've been playing around with your app (which seem very interesting btw) and I believe that you can get rid of the two calls to centerScrollViewContents altogether and it will work just as you expected.
Let me know if you have more questions.
Hope this helps!

The right solution is the one from #LuisCien
I'm adding here that I have found it useful when using UIScrollView with a MPMediaPickerController, so:
- (void)fixViewFrameBoundSize {
CGRect contentsFrame = self.view.frame;
CGSize boundsSize = self.view.bounds.size;
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
[self.view setFrame:contentsFrame];
}
and
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
[self dismissViewControllerAnimated:YES completion:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self fixViewFrameBoundSize];
});
}];
}
and the same for the selected items callback:
[self dismissViewControllerAnimated:YES
completion:^{
//LP : get item url and play
dispatch_async(dispatch_get_main_queue(), ^{
[self fixViewFrameBoundSize];
});
MPMediaItem *item = [collection representativeItem];
This solution works well when you have a XIB with a UIView, and you transform it in a UISCrollView as follows:
- (void)scrollViewMakeScrollable {
CGSize scrollableSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height+44.0);
[((UIScrollView*)self.view) setContentSize:scrollableSize];
[((UIScrollView*)self.view) setAlwaysBounceHorizontal:NO];
[((UIScrollView*)self.view) setAlwaysBounceVertical:NO];
self.automaticallyAdjustsScrollViewInsets = NO;
}
So normally when you are doing like
- (void) viewDidLoad {
[super viewDidLoad];
[self scrollViewMakeScrollable];

Related

UIScrollView zoom is not working properly

Whenever I click on an image, I want the image to display as a larger image with the ability to zoom. So far when I click on the image, it displays as I want it to inside a scrollview. However, I have to get lucky to be able to zoom in properly. Most of the time when I attempt to zoom, the image just moves down and to the right and does not zoom at all. Here is my code:
-(void) pictureButtonAction
{
self.scrollImageView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
self.scrollImageView.contentSize = self.fullImageView.image.size;
self.scrollImageView.delegate = self;
self.scrollImageView.clipsToBounds = YES;
self.scrollImageView.scrollEnabled = YES;
[self.scrollImageView setMaximumZoomScale:4.0f];
[self.scrollImageView setMinimumZoomScale:1.0f];
[self.view addSubview:self.scrollImageView];
[self.scrollImageView addSubview:fullImageView];
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.fullImageView;
}
ImageViews frame got changed while zooming , so that it moves down. So, You have to centralize the image view each time you zoom .
your scrollviews contentsize should be greater than or equal to your image size , if your fullImageView.image.size is less than your scrollviews bounds ,then set your scrollviews contentSize atleast double the scrollviews bounds .
call the below function in scrollViewDidZoom delegate method
-(void) centerScrollViewContents
{
CGSize boundsSize = self.scrollView.bounds.size;
CGRect contentsFrame = self.imageView.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
self.imageView.frame = contentsFrame;
}
Try this , hope it will help you ; happy coding ! :)
#Maria's answer works but when zooming you'll experience unwanted bounces, instead of using it under scrollViewDidZoom, use scrollViewDidEndZooming: delegate to prevent that..
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
{
[self centerScrollViewContents];
}
and with a little enhancement from her code:
[UIView animateWithDuration:0 animations:^{
self.previewImageView.frame = contentsFrame;
}];
a bit late for an answer but i hope this will be useful to some..

Objective C - Cannot zoom UIImageView that is embedded into UIScrollView

I'm a new kid on the block here. Nice to meet you all.
I'm trying to implement Ray Wenderlich's zooming of an UIScrollView that was described here:
http://www.raywenderlich.com/10518/how-to-use-uiscrollview-to-scroll-and-zoom-content
But it seemed like it didn't work for me. What I would like to do is:
Create the UIImageView from a nib.
Add UIImageView to the UIScrollView.
Zoom it in from the center of the image with the scale of 2 at the start of the view if the app is executed from an iPad.
Here's my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//Hide the status bar
[[UIApplication sharedApplication] setStatusBarHidden:YES];
//------------------------------
//Initialize the image view of the home screen
_mapView = (TM_MapView *)[[[NSBundle mainBundle]loadNibNamed:#"MapView" owner:self options:nil]objectAtIndex:0];
// set the content size to be the size our our whole frame
mapScrollView.contentSize = _mapView.imageView.image.size;
[mapScrollView setScrollEnabled:YES];
//set the selector for the buttons in the map view
[self setButtonsSelector];
// now add our scroll view to the main view
[mapScrollView addSubview:_mapView];
//------------------------------
NSLog(#"_mapView.imageView.frame: %#", NSStringFromCGRect( _mapView.imageView.frame));
NSLog(#"_mapView.imageView.image.size: %#", NSStringFromCGSize( _mapView.imageView.image.size));
NSLog(#"mapScrollView.contentSize: %#", NSStringFromCGSize( mapScrollView.contentSize));
}
-(void)viewWillAppear:(BOOL)animated
{
mapScrollView.minimumZoomScale = 1.0f;
mapScrollView.maximumZoomScale = 2.5f;
mapScrollView.zoomScale = 1.0f;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
[self zoomOnStart];
}
}
-(void)zoomOnStart
{
NSLog(#"Zooming on start");
CGPoint zoomPoint = CGPointMake(512.0f, 384.0f);
CGFloat newZoomScale = 2.0f;
CGSize scrollViewSize = self.mapScrollView.bounds.size;
CGFloat w = scrollViewSize.width / newZoomScale;
CGFloat h = scrollViewSize.height / newZoomScale;
CGFloat x = zoomPoint.x - (w/2.0f);
CGFloat y = zoomPoint.y - (h/2.0f);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
//CGRect rectToZoomTo = CGRectMake(300, 300, 200, 100);
NSLog(#"rectToZoomTo: %#", NSStringFromCGRect(rectToZoomTo));
[self.mapScrollView zoomToRect:rectToZoomTo animated:YES];
}
#pragma mark - Delegates
-(UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView
{
NSLog(#"Scroll View viewForZoomingInScrollView");
return _mapView;
}
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
{
NSLog(#"Scroll View End Zooming!");
}
-(void)scrollViewDidZoom:(UIScrollView *)scrollView
{
NSLog(#"Scroll View Zoom changed to: %f", scrollView.zoomScale);
}
As you can see, I've logged some of the frames and delegates to see the input for the zooming and to see whether or not we are zooming. Here's the console logs:
2014-10-09 17:24:18.507 TrueMuzeiOS[13268:60b] _mapView.imageView.frame: {{0, 0}, {1024, 768}}
2014-10-09 17:24:18.511 TrueMuzeiOS[13268:60b] _mapView.imageView.image.size: {1024, 768}
2014-10-09 17:24:18.513 TrueMuzeiOS[13268:60b] mapScrollView.contentSize: {1024, 768}
2014-10-09 17:24:18.519 TrueMuzeiOS[13268:60b] Zooming on start
2014-10-09 17:24:18.521 TrueMuzeiOS[13268:60b] rectToZoomTo: {{320, 128}, {384, 512}}
As you can see, the logs inside viewForZoomingInScrollView:, scrollViewDidEndZooming:withView:atScale:, and scrollViewDidZoom: didn't get called, meaning we are not zooming at all (CMIIW). I've added the UIScrollViewDelegate so it should've worked.
So, can you guys help me here? I've followed the steps correctly, IMHO. So I'm lost now. Thanks a lot in advance.
do you set the delegate property of the UIScrollView?
I donĀ“t see this on the code you published although you could have done it on Interface Builder.
If this the case, simply this would make your methods get called:
mapScrollView.delegate = self;
Check the UIScrollView documentation on the delegate property section to more information.
https://developer.apple.com/library/ios/documentation/uikit/reference/uiscrollview_class/index.html#//apple_ref/occ/instp/UIScrollView/delegate

iOS rotation issues

Afternoon all,
Has anyone worked with collection views in iOS with an image fullscreen and horizontal paging?
I am currently experiencing difficulties when I rotate to landscape. I have read many posts on this subject on here and can't seem to find anything that helps the issue.
When I rotate the item i was looking at changes and the images are displaced on the screen. Is there anything short of turning orientations off that will fix this?
Thanks
ps if you need to see any of the code let me know and i'll edit my question
Code used:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (_startingIndexPath) {
NSInteger currentIndex = floor((scrollView.contentOffset.x - scrollView.bounds.size.width / 2) / scrollView.bounds.size.width) + 1;
if (currentIndex < [self.marbleImages count]) {
self.title = self.marbleImages[currentIndex][#"name"];
}
}
}
- (BOOL) shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
layout.itemSize = self.view.bounds.size;
[self.collectionView scrollToItemAtIndexPath:self.startingIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}

content jumps on zooming out with UIScrollView

I want help with my UIScrollView sample.
I created a simple program that scrolls and zooms the content (UIImageView). It works fine, except that the content frequently disappears to the right-bottom when I try zooming out. But since I set minimumZoomScale to 1.0f, it is actually not zooming out, only the content is jumping out of the view. And what is even more weird is that I cannot scroll up after this. Apparently content size is messed up as well.
The setup I have in my sample code is as in the figure below.
When I checked the status after (trying) zooming out, I found two wrong things.
_scrollView.contentSize is 480x360, which should not be smaller than 1000x1000
_scrollView.bounds jumped to the top somehow (i.e., _scrollView.bounds.origin.y is always 0)
To cope with the two items above, I added following code in my UIScrollViewDelegate and now it works fine.
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
if(scrollView == _scrollView && view == _contentView)
{
// Setting ivars for scrollViewDidZoom
_contentOffsetBeforeZoom = _scrollView.contentOffset;
_scrollViewBoundsBeforeZoom = _scrollView.bounds;
}
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
if(scrollView == _scrollView)
{
// If you zoom out, there are cases where ScrollView content size becomes smaller than original,
// even though minimum zoom scale = 1. In that case, it will mess with the contentOffset as well.
if(_scrollView.contentSize.width < CONTENT_WIDTH || _scrollView.contentSize.height < CONTENT_HEIGHT)
{
_scrollView.contentSize = CGSizeMake(CONTENT_WIDTH, CONTENT_HEIGHT);
_scrollView.contentOffset = _contentOffsetBeforeZoom;
}
// If you zoom out, there are cases where ScrollView bounds goes outsize of contentSize rectangle.
if(_scrollView.bounds.origin.x + _scrollView.bounds.size.width > _scrollView.contentSize.width ||
_scrollView.bounds.origin.y + _scrollView.bounds.size.height > _scrollView.contentSize.height)
{
_scrollView.bounds = _scrollViewBoundsBeforeZoom;
}
}
}
However, does it need to come down to this? This is a very simple sequence, and it is hard to believe that Apple requires us to put this kind of effort. So, my bet is I am missing something here...
Following is my original code. Please help me find what I am doing wrong (or missing something)!
#define CONTENT_WIDTH 1000
#define CONTENT_HEIGHT 1000
>>>> Snip >>>>
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
_scrollView.contentSize = CGSizeMake(CONTENT_WIDTH, CONTENT_HEIGHT);
_scrollView.backgroundColor = [UIColor blueColor];
_scrollView.maximumZoomScale = 8.0f;
_scrollView.minimumZoomScale = 1.0f;
_scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
_scrollView.scrollEnabled = YES;
_scrollView.delegate = self;
[self.view addSubview:_scrollView];
_contentView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"sample.jpg"]]; // sample.jpg is 480x360
CGPoint center = (CGPoint){_scrollView.contentSize.width / 2, _scrollView.contentSize.height / 2};
_contentView.center = center;
[_scrollView addSubview:_contentView];
_scrollView.contentOffset = (CGPoint) {center.x - _scrollView.bounds.size.width / 2, center.y - _scrollView.bounds.size.height / 2};
}
- (UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
{
if(scrollView == _scrollView)
{
return _contentView;
}
return nil;
}
I created a quick sample project and had the same issue you described using the code you pasted. I don't exactly know what the "proper" way to zoom is in iOS but I found this tutorial which says that you need to recenter your contentView after the scrollView has been zoomed. I would personally expect it to be automatically re-centered given that it is the view you're returning in the viewForZoomingInScrollView delegate method but apparently not.
- (void)centerScrollViewContents {
CGSize boundsSize = _scrollView.bounds.size;
CGRect contentsFrame = _contentView.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
} else {
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
} else {
contentsFrame.origin.y = 0.0f;
}
_contentView.frame = contentsFrame;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// The scroll view has zoomed, so we need to re-center the contents
[self centerScrollViewContents];
}
The code above is not written by me but is simply copied from the tutorial. I think its pretty straightforward. Also, centring the contentView seems to be a lot more elegant then constantly changing the bounds and content size of the scrollview so give it a try.
If anyone is having an issue of bouncing when you zooming out resulting background to show, try removing bounces (Bounces Zoom) in Interface Builder.
I was able to fix this problem using the delegate answer that adjusted the rates after zoom... but then I remembered I was using auto-layout, and just adding constraints for centering horizontally and vertically (in addition to the constraints tying the image to each edge of the scroll view) solved the issue for me without using the delegate methods.
Olshansk answer in swift 5
func scrollViewDidZoom(_ scrollView: UIScrollView) {
centerScrollViewContents()
}
func centerScrollViewContents() {
let boundsSize = scrollView.bounds.size;
var contentsFrame = container.frame;
if (contentsFrame.size.width < boundsSize.width) {
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0;
} else {
contentsFrame.origin.x = 0.0;
}
if (contentsFrame.size.height < boundsSize.height) {
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0;
} else {
contentsFrame.origin.y = 0.0;
}
container.frame = contentsFrame;
}

UIImageView in UIScrollView: panning fail

I am making a simple photo viewer that allows zooming and panning.
so in IB I create a UIScrollView containing a UIImageView:
Then I can configure it to house the photo as soon as the photo is available:
- (void) imageCaptureCompleted
{
{
UIImage* I = self.frontCamView.stillImage;
self.imageView.bounds = CGRectMake(0, 0, I.size.width, I.size.height );
self.imageView.image = I;
// - - -
self.scrollView.maximumZoomScale = 4.0;
self.scrollView.minimumZoomScale = 0.75;
self.scrollView.clipsToBounds = YES;
self.scrollView.delegate = self;
self.scrollView.contentSize = self.imageView.bounds.size;
}
[self hideCaptureView];
UIImageWriteToSavedPhotosAlbum( self.frontCamView.stillImage,
self,
#selector( image: didFinishSavingWithError: contextInfo: ),
nil );
}
- (UIView *) viewForZoomingInScrollView: (UIScrollView *) scrollView
{
return self.imageView;
}
This is almost working. It is indeed letting me pan and zoom.
However, it pans too far! It should bounce back when it hits the right edge of the photo. but instead it behaves as if the photo is in a larger black rectangle.
I have set up the autoresizing masks of the scroll view in exactly the same way as per the above picture.
How to get it to work?
PS I have now figured this out; I will put up the answer for posterity.
This code sorts it out:
// self.imageView.bounds = CGRectMake(0, 0, I.size.width, I.size.height );
self.imageView.image = I;
[self.imageView sizeToFit];
However, I can't understand why this change is necessary. If anyone can tell me, I will accept that answer ( in which case please paste the above code then I can remove this answer ).

Resources