UIScroll center image - ios

I've edited this question a few times, but can still not get my images to center inside a uiview. I want them to be able to rotate like the photos app and display the correct size when a user brings them up. Here is what I'm working with:
In my PhotoViewController.h
#import <UIKit/UIKit.h>
#protocol PhotoViewControllerDelegate <NSObject>
- (void)toggleChromeDisplay;
#end
#interface PhotoViewController : UIViewController <UIScrollViewDelegate, UIGestureRecognizerDelegate>
#property (nonatomic, strong) UIImage *photo;
#property (nonatomic) NSUInteger num;
//Delegate
#property (nonatomic, strong) id<PhotoViewControllerDelegate> photoViewControllerDelegate;
#property (nonatomic, strong) UIImageView *photoImgView;
#property (nonatomic, strong) UIScrollView *scrollView;
#end
In my PhotoViewController.m:
#import "PhotoViewController.h"
#interface PhotoViewController ()
#end
#implementation PhotoViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
//todo
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect screenBounds = self.view.bounds;
//scroll view
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, screenBounds.size.width, screenBounds.size.height)];
_scrollView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
_scrollView.pagingEnabled = NO;
_scrollView.scrollEnabled = YES;
[_scrollView setBackgroundColor:[UIColor blueColor]];
//Zoom Properties
_scrollView.maximumZoomScale = 6.0;
_scrollView.minimumZoomScale = 1.0;
_scrollView.bouncesZoom = YES;
_scrollView.delegate = self;
_scrollView.zoomScale = 1.0;
_scrollView.contentSize = _photoImgView.bounds.size;
[_scrollView setShowsHorizontalScrollIndicator:NO];
[_scrollView setShowsVerticalScrollIndicator:NO];
[self photoBounds];
[self.view addSubview: _scrollView];
//Add the UIImageView
_photoImgView = [[UIImageView alloc] initWithImage:_photo];
_photoImgView.image = _photo;
_photoImgView.clipsToBounds = YES;
_photoImgView.contentMode = UIViewContentModeScaleAspectFit;
_photoImgView.autoresizingMask = (UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin);
[_photoImgView setUserInteractionEnabled:YES];
[_scrollView addSubview: _photoImgView];
//Set up Gesture Recognizer
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
UITapGestureRecognizer *dTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dTapGestureCaptured:)];
dTap.numberOfTapsRequired = 2;
[singleTap requireGestureRecognizerToFail:dTap];
//Gesture Methods
[self.scrollView addGestureRecognizer:singleTap];
[self.scrollView addGestureRecognizer : dTap];
}
- (void)photoBounds
{
UIInterfaceOrientation statusbar = [[UIApplication sharedApplication] statusBarOrientation];
CGSize photoBounds = _photo.size;
CGSize scrollBounds = self.view.bounds.size;
CGRect frameToCenter = [_photoImgView frame];
float newHeight = (scrollBounds.width / photoBounds.width) * photoBounds.height;
float newWidth = (scrollBounds.height / photoBounds.height) * photoBounds.width;
float yDist = fabsf(scrollBounds.height - newHeight) / 2;
float xDist = fabsf(scrollBounds.width - newWidth) / 2;
//Width Larger
if (photoBounds.width >=photoBounds.height) {
NSLog(#"portrait width");
_photoImgView.frame = CGRectMake(0, 0, scrollBounds.width, newHeight);
frameToCenter.origin.y = yDist;
}
//Height Larger
else if (photoBounds.height > photoBounds.width) {
NSLog(#"portrait height");
_photoImgView.frame = CGRectMake(0, 0, newWidth, scrollBounds.height);
frameToCenter.origin.x = xDist;
}
//Square
else {
NSLog(#"portrait square");
if ((statusbar == 1) || (statusbar == 2)) {
_photoImgView.frame = CGRectMake(0, 0, scrollBounds.width, newHeight);
frameToCenter.origin.y = yDist;
} else {
_photoImgView.frame = CGRectMake(0, 0, newWidth, scrollBounds.height);
frameToCenter.origin.x = xDist;
}
}
}
//Rotation Magic
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
//later
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self photoBounds];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
//
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
//Zoom Ability
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.photoImgView;
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale
{
NSLog(#"scale %f", scale);
NSLog(#"done zooming");
}
//Touches Control
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
//CGPoint touchPoint=[gesture locationInView:_scrollView];
NSLog(#"touched");
NSLog(#"single touch");
[self performSelector:#selector(callingHome) withObject:nil afterDelay:0];
}
- (void)dTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
NSLog(#"double touched");
}
- (void)panGestureCaptured:(UIPanGestureRecognizer *)gesture
{
NSLog(#"pan gesture");
}
- (void)callingHome {}
#end
The overall issue is that I can not get my picture to display correctly and be able to zoom on just it, no space around it and It needs to be the correct dimensions on load. I've been struggling with it for a few days.
Any help?

I have resolved a similar problem using a really simple subclass of UIScrollView of my own. You can take a look at it here - https://gist.github.com/ShadeApps/5a29e1cea3e1dc3df8c8. Works like charm for me.
That's how you init it:
scrollViewMain.delegate = self;
scrollViewMain.minimumZoomScale = 1.0;
scrollViewMain.maximumZoomScale = 3.0;
scrollViewMain.contentSize = imageViewMain.frame.size;
scrollViewMain.backgroundColor = [UIColor blackColor];
scrollViewMain.tileContainerView = imageViewMain;

There is awesome blog post about this problem from Peter Steinberger: http://petersteinberger.com/blog/2013/how-to-center-uiscrollview/

Related

UICollectionView Will Not Update Its Layout On Screen Rotation

I have a custom UIView with a UICollectionView.
On screen rotation I am trying to get the UICollectionView to stretch across the screen, and then redraw its cells.
After I had the data downloaded I tried both [grid setNeedsLayout] and [grid setNeedsDisplay] but that didn't work.
This is what I want to happen:
Portrait
Landscape
(This is also how it appears when the app is started in landscape, but if you change to portrait it doens't update.)
But this is what I get if I start in Portrait mode and switch to Landscape.
I am creating these views programmatically. I am not using any Storyboards.
I have tried:
-(void)viewDidLayoutSubviews {
grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];
}
I have also tried toying with:
- (void) viewWillLayoutSubviews {
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
//LANDSCAPE
if(grid){
NSLog(#"Grid Needs Landscape Layout");
grid.frame =CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2);
[grid refreshData];
}
}else {
//PORTRIAT
if(grid){
NSLog(#"Grid Needs Portrait Layout");
grid.frame =CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2);
[grid refreshData];
}
}
}
But I can't get it to stretch.
Any help?
MyThumbnailGridView
#interface ViewController () <UINavigationControllerDelegate> {
MyThumbnailGridView *grid;
NSMutableArray * arrImages;
}
- (void)viewDidLoad {
[super viewDidLoad];
arrImages = [NSMutableArray new];
grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];
//grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectZero];
NSLog(#"showThumbnailGrid Grid View Size: %#", NSStringFromCGRect(grid.frame));
[self.view addSubview:grid];
[self getListOfImages];
}
-(void) getListOfImages {
//Do background task to get images and fill arrImages
[self onDownloadImageDataComplete];
}
- (void) onDownloadImageDataComplete{
grid.imageDataSource = arrImages;
// [grid setNeedsLayout];
// [grid setNeedsDisplay];
}
//...
#end
*MyThumbnailGridView.h
#interface MyThumbnailGridView : UIView
-(id)initWithFrame:(CGRect)frame;
-(void) refreshData;
#property (nonatomic,strong) NSArray *imageDataSource;
#end
*MyThumbnailGridView.m
#interface MyThumbnailGridView () <UICollectionViewDelegate, UICollectionViewDataSource>{
UICollectionView *collectionView;
}
#end
#implementation MyThumbnailGridView
- (instancetype) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self){
[self customInit];
}
return self;
}
- (void) customInit {
collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:[[MyFlowLayout alloc] init]];
collectionView.delegate = self;
collectionView.dataSource = self;
collectionView.allowsMultipleSelection = NO;
collectionView.showsVerticalScrollIndicator = YES;
[collectionView setBackgroundColor:[UIColor darkGrayColor]];
[collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:#"MyId"];
[self addSubview:collectionView];
}
- (void) refreshData {
NSLog(#"Refresh Grid Data");
[collectionView reloadData];
}
////other code
#end
MyFlowLayout
#interface MyFlowLayout : UICollectionViewFlowLayout
#end
#implementation MyFlowLayout
- (instancetype)init{
self = [super init];
if (self)
{
self.minimumLineSpacing = 1.0;
self.minimumInteritemSpacing = 1.0;
self.scrollDirection = UICollectionViewScrollDirectionVertical;
}
return self;
}
- (CGSize)itemSize {
NSInteger numberOfColumns = 3;
CGFloat itemWidth = (CGRectGetWidth(self.collectionView.frame) - (numberOfColumns - 1)) / numberOfColumns;
return CGSizeMake(itemWidth, itemWidth);
}
#end
MyCollectionViewCell
#interface MyCollectionViewCell : UICollectionViewCell
#property (strong, nonatomic) UIImageView *imageView;
#end
#implementation MyCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.imageView = [UIImageView new];
[self.imageView setContentMode:UIViewContentModeScaleAspectFill];
[self.imageView setClipsToBounds:YES];
[self.imageView setBackgroundColor:[UIColor darkGrayColor]];
[self.contentView addSubview:self.imageView];
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
self.imageView.image = nil;
[self.imageView setHidden:NO];
}
- (void)layoutSubviews {
[super layoutSubviews];
[self.imageView setFrame:self.contentView.bounds];
}
#end
This can be solved with
either you can change the frame of MyThumbnailGridView view in delegate function of orientation or create the view with constraints like this
(void)viewDidLoad {
[super viewDidLoad];
arrImages = [NSMutableArray new];
grid = [[MyThumbnailGridView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height/2, self.view.frame.size.width, self.view.frame.size.height/2)];
[self.view addSubview:grid];
[self getListOfImages];
}
-(void)viewDidLayoutSubviews
{
if(Once){
Once = NO;
// adding constraints
MyThumbnailGridView.translatesAutoresizingMaskIntoConstraints = NO;
[self.MyThumbnailGridView.widthAnchor constraintEqualToConstant:self.view.frame.size.width].active = YES;
[self.MyThumbnailGridView.heightAnchor constraintEqualToConstant:self.view.frame.size.height/2].active = YES;
[self.MyThumbnailGridView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[self.MyThumbnailGridView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:self.view.frame.size.height/2].active = YES;
}
}
Also implement this
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[self.view layoutIfNeeded];
[MyThumbnailGridView.collectionView invalidate];
// Do view manipulation here.
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
The problem is that the collection view itself is not changing size when the app rotates. You have given the collection view a fixed frame and then just walked away. So it never changes. So never lays itself out again.
You should give your MyThumbnailGridView and its collection view subview autolayout contraints to their superviews, so that they change size correctly when the app rotates.

Symmetric zooming of image within scrollview in iOS

I am new to iPhone to iOS development. and I want a demo for zoom in and zoom out (symmetric zooming of image) a image within a scrollview in iOS.This is my code : in this code i have taken an image view within a scrollview(ZoomScrollView) and scrollview within a another Scrollview(scrollView_Gallery).Thanks in advance..
//ZoomGalleryViewController.m//
scrollView_Gallery.backgroundColor = [UIColor yellowColor];
scrollView_Gallery.delegate = self;
scrollView_Gallery.pagingEnabled = YES;
scrollView_Gallery.userInteractionEnabled = YES;
scrollView_Gallery.showsHorizontalScrollIndicator = NO;
scrollView_Gallery.showsVerticalScrollIndicator = NO;
[self.view addSubview:scrollView_Gallery];
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
[scrollView_Gallery setContentSize:CGSizeMake(self.view.frame.size.width*[arrayUrl count],self.view.frame.size.height)];
}
else if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
{
[scrollView_Gallery setContentSize:CGSizeMake([[UIScreen mainScreen] bounds].size.width*[arrayUrl count],[[UIScreen mainScreen] bounds].size.height)];
}
for (int i = 0; i < [arrayUrl count]; i++)
{
zoomScrollView = [[ZoomScrollView alloc]init];
zoomScrollView.backgroundColor = [UIColor redColor];
[zoomScrollView setContentSize:CGSizeMake(zoomScrollView.contentSize.width,zoomScrollView.frame.size.height)];
CGRect frame = scrollView_Gallery.frame;
frame.origin.x = (frame.size.width)* i;
frame.origin.y = 0;
zoomScrollView.frame = frame;
zoomScrollView.imageView.contentMode = UIViewContentModeScaleAspectFit;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[[arrayUrl objectAtIndex:i]objectForKey:#"photopath"]]];
__weak UIImageView *weakImageView = zoomScrollView.imageView;
zoomScrollView.imageView.tag = i;
zoomScrollView.ZOOM_VIEW_TAG = zoomScrollView.imageView.tag;
[zoomScrollView.imageView setImageWithURLRequest:request
placeholderImage:nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image)
{
NSLog(#"image=%f,imageheight=%f",image.size.width,image.size.height);
UIImageView *strongImageView = weakImageView; // make local strong reference to protect against race conditions
strongImageView.frame = CGRectMake(0,0,image.size.width*image.scale, image.size.height*image.scale);
strongImageView.center = scrollView_Gallery.center;
NSLog(#"image11 = %f, imageheight11 = %f",image.size.width*image.scale, image.size.height*image.scale);
NSLog(#"imageScale = %f",image.scale);
if (!strongImageView) return;
[UIView transitionWithView:strongImageView
duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
strongImageView.image = image;
}
completion:NULL];
//[scrollView_Gallery setContentOffset:CGPointMake(strongImageView.frame.size.width * (indexNumber+1), 0)];
}failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error){
NSLog(#"Request failed with error: %#", error);
}];
[scrollView_Gallery addSubview:zoomScrollView];
[zoomScrollView setContentSize:CGSizeMake(zoomScrollView.contentSize.width,zoomScrollView.frame.size.height)];
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
[scrollView_Gallery setContentOffset:CGPointMake(self.view.frame.size.width * (indexNumber), 0)];
}
else if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
{
[scrollView_Gallery setContentOffset:CGPointMake([[UIScreen mainScreen] bounds].size.width * (indexNumber), 0)];
}
// ZoomScrollView.h//
#import <UIKit/UIKit.h>
#interface MRZoomScrollView : UIScrollView <UIScrollViewDelegate>
{
UIImageView *imageView;
}
#property (nonatomic, retain) UIImageView *imageView;
#end
// MRZoomScrollView.m//
#import "MRZoomScrollView.h"
#define MRScreenWidth CGRectGetWidth([UIScreen mainScreen].applicationFrame)
#define MRScreenHeight CGRectGetHeight([UIScreen mainScreen].applicationFrame)
#interface MRZoomScrollView (Utility)
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center;
#end
#implementation MRZoomScrollView
#synthesize imageView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.delegate = self;
self.frame = CGRectMake(0, 0, MRScreenWidth, MRScreenHeight);
[self initImageView];
}
return self;
}
- (void)initImageView
{
imageView = [[UIImageView alloc]init];
// The imageView can be zoomed largest size
imageView.frame = CGRectMake(0, 0, MRScreenWidth * 2.5, MRScreenHeight * 2.5);
imageView.userInteractionEnabled = YES;
[self addSubview:imageView];
[imageView release];
// Add gesture,double tap zoom imageView.
UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
[doubleTapGesture setNumberOfTapsRequired:2];
[imageView addGestureRecognizer:doubleTapGesture];
[doubleTapGesture release];
float minimumScale = self.frame.size.width / imageView.frame.size.width;
[self setMinimumZoomScale:minimumScale];
[self setZoomScale:minimumScale];
}
#pragma mark - Zoom methods
- (void)handleDoubleTap:(UIGestureRecognizer *)gesture
{
float newScale = self.zoomScale * 1.5;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gesture locationInView:gesture.view]];
[self zoomToRect:zoomRect animated:YES];
}
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center
{
CGRect zoomRect;
zoomRect.size.height = self.frame.size.height / scale;
zoomRect.size.width = self.frame.size.width / scale;
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
return zoomRect;
}
#pragma mark - UIScrollViewDelegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return imageView;
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
[scrollView setZoomScale:scale animated:NO];
}
You can do it by using UIScrollView and enable enabledZoom ON.
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
in viewDidLoad method paste this code
- (void)viewDidLoad {
[super viewDidLoad];
self.scrollView.minimumZoomScale=0.5;
self.scrollView.maximumZoomScale=6.0;
self.scrollView.contentSize=CGSizeMake(1280, 960);
self.scrollView.delegate=self;
}
Look at this tutorial, it was helpful for me:
Assuming you have a property scrollView, try the following code in your view controller s viewDidLoad or viewWillAppear methods:
self.scrollView.minimumZoomScale=1.0;
self.scrollView.maximumZoomScale=2.0;
self.scrollView.contentSize=self.scrollView.frame.size;
self.scrollView.bounces=YES;
self.scrollView.delegate=self;
Let your view controller conform to the UIScrollViewDelegate protocol. And implement the delegate method :
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;// return the imageView inside the scrollview which has to be scaled.
}

Second ScrollView doesn't zoom or scroll

I have two Scroll View's in a xib, and they both contain a very large image that should start with it completely scaled down to fit. The first ScrollView works perfectly, objects are all moving around correctly when you zoom or scroll, but the second ScrollView starts completely zoomed in, unable to zoom out.
The ScrollView is now showing 25% of the image(completely zoomed in at 0,0) and also cannot be dragged to see the rest. If I pinch to zoom, the image moves diagonally up and left without zooming at all, I can now drag the image back to 0,0 and back down the the max point it scrolled diagonally.
.h file
UIScrollView *_scrollView;
UIScrollView *_miamiScrollView;
UIView *_mapImageView;
UIView *_mapMiamiView;
UIView *_mapContentView;
NSArray *_autoLayoutViews;
NSArray *_staticViews;
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;//(linked to working scrollview)
#property (strong, nonatomic) IBOutlet UIScrollView *miamiScrollView;//(Linked to 'broken' scrollview)
.m file
- (void)viewDidLoad
{
[self _customizeViews];
}
- (void) _customizeViews
{
UIImageView *mapImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"MainGameDisplay.jpg"]];
mapImageView.userInteractionEnabled = YES;
UIImageView *mapMiamiView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"miami.jpg"]];
mapMiamiView.userInteractionEnabled = YES;
_mapContentView = [[UIView alloc] initWithFrame:CGRectMake(0, 50, 568, 270)];
_mapContentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_mapContentView.clipsToBounds = YES;
_mapContentView.userInteractionEnabled = YES;
[_mapContentView addSubview:_scrollView];
[_mapContentView addSubview:_miamiScrollView];
[self.view addSubview:_mapContentView];
[self.view sendSubviewToBack:_mapContentView];
UIScrollView *scrollView = _scrollView;
CGRect scrollFrame = scrollView.frame;
scrollFrame.origin = CGPointZero;
scrollView.frame = scrollFrame;
scrollView.delegate = self;
scrollView.minimumZoomScale = 1;
scrollView.maximumZoomScale = 1.0;
[scrollView addSubview:mapImageView];
scrollView.contentSize = mapImageView.frame.size;
_scrollView = scrollView;
_mapImageView = mapImageView;
UIScrollView *miamiScrollView = _miamiScrollView;
CGRect miamiScrollFrame = CGRectMake(0 , 270, 568, 270);
scrollFrame.origin = CGPointZero;
miamiScrollView.frame = miamiScrollFrame;
miamiScrollView.delegate = self;
miamiScrollView.minimumZoomScale = 0.125;
miamiScrollView.maximumZoomScale = 1;
[miamiScrollView addSubview:mapMiamiView];
miamiScrollView.contentSize = mapMiamiView.frame.size;
_miamiScrollView = miamiScrollView;
_mapMiamiView = mapMiamiView;
[self _setupAutolayoutViews];
[self _setupStaticViews];
[self _zoomToFit: _scrollView];
[self _zoomToFit: _miamiScrollView];
[self _updatePositionForViews:_autoLayoutViews];
}
- (void) _zoomToFit: (UIScrollView*)view
{
CGFloat contentWidth = view.contentSize.width;
CGFloat contentHeigth = view.contentSize.height;
CGFloat viewWidth = view.frame.size.width;
CGFloat viewHeight = view.frame.size.height;
CGFloat width = viewWidth / contentWidth;
CGFloat heigth = viewHeight / contentHeigth;
CGFloat scale = MAX(width, heigth);
if ( scale < view.minimumZoomScale ) {
view.minimumZoomScale = scale;
} else if ( scale > view.maximumZoomScale ) {
view.maximumZoomScale = scale;
}
view.zoomScale = scale;
}
#pragma mark - Positions
- (void) _updatePositionForViews:(NSArray *)views
{
CGFloat scale = _scrollView.zoomScale;
CGPoint contentOffset = _scrollView.contentOffset;
contentOffset.x -= _scrollView.frame.origin.x;
contentOffset.y -= _scrollView.frame.origin.y;
for ( UIView *view in views ) {
CGPoint basePosition = [self _basePositionForView:view];
[self _updatePositionForView:view scale:scale basePosition:basePosition offset:contentOffset];
}
}
- (CGPoint) _basePositionForView:(UIView *)view
{
NSString *key = [NSString stringWithFormat:#"%d", view.tag];
NSString *stringValue = [_coordinates objectForKey:key];
NSArray *values = [stringValue componentsSeparatedByString:#":"];
if ( [values count] < 2 ) return CGPointZero;
CGPoint result = CGPointMake([[values objectAtIndex:0] floatValue], [[values objectAtIndex:1] floatValue]);
return result;
}
- (void) _updatePositionForView:(UIView *)view scale:(CGFloat)scale basePosition:(CGPoint)basePosition offset:(CGPoint)offset;
{
CGPoint position;
position.x = (basePosition.x * scale) - offset.x;
position.y = (basePosition.y * scale) - offset.y;
CGRect frame = view.frame;
frame.origin = position;
view.frame = frame;
}
//////////////////////////////////////////////////////////////////////////////////////
#pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
{
[self _lockInteraction];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{
[self _unlockInteraction];
}
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
[self _lockInteraction];
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;
{
[self _unlockInteraction];
}
- (void) _lockInteraction
{
[self _setControls:_staticViews interacted:NO];
[self _setControls:_autoLayoutViews interacted:NO];
}
- (void) _unlockInteraction
{
[self _setControls:_staticViews interacted:YES];
[self _setControls:_autoLayoutViews interacted:YES];
}
- (void) _setControls:(NSArray *)controls interacted:(BOOL)interacted
{
for ( UIControl *control in controls ) {
if ( [control isKindOfClass:[UIControl class]]) {
control.userInteractionEnabled = interacted;
}
}
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
[self _updatePositionForViews:_autoLayoutViews];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self _updatePositionForViews:_autoLayoutViews];
}
- (UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView;
{
return _mapImageView;
}
//DEFAULT BUTTONS.
- (void) _setupAutolayoutViews
{
UIButton *btn1 = [UIButton buttonWithType: UIButtonTypeDetailDisclosure];
[btn1 addTarget:self action:#selector(quickTest:) forControlEvents:UIControlEventTouchUpInside];
btn1.tag = kAddContactButton;
btn1.center = CGPointZero;
[_mapContentView addSubview:btn1];
_autoLayoutViews = [[NSArray alloc] initWithObjects:btn1, nil];
}
//CUSTOM BUTTONS.
- (void) _setupStaticViews
{
UIButton *openMiamiButton = [UIButton buttonWithType:UIButtonTypeCustom];
[openMiamiButton setBackgroundImage:[UIImage imageNamed:#"logo.png"] forState:UIControlStateNormal];
[openMiamiButton addTarget:self action:#selector(quickTest:) forControlEvents:UIControlEventTouchUpInside];
openMiamiButton.frame = CGRectMake(0.0 ,0.0, 50.0, 50.0);
openMiamiButton.tag = OpenMiamiButton;
openMiamiButton.enabled = YES;
openMiamiButton.alpha = 0.5;
[_mapImageView addSubview:openMiamiButton];
_staticViews = #[openMiamiButton,];
for ( UIView *view in _staticViews ) {
CGPoint point = [self _basePositionForView:view];
CGRect frame = view.frame;
frame.origin = point;
view.frame = frame;
}
}
//And for the transition between views:
-(void) quickTest: (UIButton *)button
{
/*
if (!openMiami)
openMiami = [[MiamiGameDisplay alloc] initWithNibName:nil bundle:nil];
openMiami.mainPage = self;
[self.navigationController pushViewController:openMiami animated:YES];
*/
if (!testBool){
[UIView animateWithDuration:0.5f
animations:^{
_scrollView.frame = CGRectMake(0 , -270, 568, 270);
}
completion:Nil];
[UIView animateWithDuration:0.5f
animations:^{
_miamiScrollView.frame = CGRectMake(0 , 0, 568, 270);
}
completion:Nil];
testBool=YES;
}
else {
[UIView animateWithDuration:0.5f
animations:^{
_miamiScrollView.frame = CGRectMake(0 , 270, 568, 270);
}
completion:Nil];
[UIView animateWithDuration:0.5f
animations:^{
_scrollView.frame = CGRectMake(0 , 0, 568, 270);
}
completion:Nil];
testBool=NO;
}
}
I've run into a similar issue with scrollViews. Basically, as far as I can tell, only the last scrollView added to the window will respond as a scrollView.
You can produce the same effect with any other type of object being added to the window before the scrollView.
Example :
[[self window] addSubview:logo];
[[self window] addSubview:scrollView];
Will work, but:
[[self window] addSubview:scrollView];
[[self window] addSubview:logo];
will not. (Currently running against iOS 6.1.2 and xCode 4.6.1)

Page Control not changing when scroll view scrolls

I am trying to add a page control to my scroll view, and have followed numerous web tutorials, the majority which use the same code as this tutorial. However, once I place the code into my project, even with me making changes to the code to try to make it work, it just doesn't. I have managed to make the code work for when the page control is pressed, however it just won't work for the page scrolling. My issue is similar to this, although the answers are of no help. Here is my code:
MainViewController.h
#interface MainViewController : UIViewController
{
UIScrollView *svCollegeMain;
UIScrollView *svCollegePage;
UIPageControl *pcCollege;
UIView *viewP1;
}
#property (nonatomic, retain) IBOutlet UIScrollView* svCollegeMain;
#property (nonatomic, retain) IBOutlet UIScrollView* svCollegePage;
#property (nonatomic, retain) IBOutlet UIPageControl * pcCollege;
- (IBAction)changePage;
#end
and MainViewController.m
#implementation MainViewController
#synthesize svCollegeMain, svCollegePage, pcCollege;
- (void)viewDidLoad
{
[super viewDidLoad];
self.svCollegeMain.contentSize = CGSizeMake(960, 332);
self.svCollegePage.contentSize = CGSizeMake(320, 500);
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)scrollViewDidScroll:(UIScrollView *)sender
{
CGFloat pageWidth = 320;
int page = floor((svCollegeMain.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pcCollege.currentPage = page;
}
- (IBAction)changePage
{
CGRect frame;
frame.origin.x = self.svCollegeMain.frame.size.width * self.pcCollege.currentPage;
frame.origin.y = 0;
frame.size = self.svCollegeMain.frame.size;
[self.svCollegeMain scrollRectToVisible:frame animated:YES];
}
#pragma mark - View lifecycle
- (void)viewDidUnload
{
[super viewDidUnload];
self.svCollegeMain = nil;
self.svCollegePage = nil;
self.pcCollege = nil;
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Just incase this makes any difference, my view is set out with a view, then a main scroll view and page control within this view, another view and scroll view (next to each other) within the main scroll view, and finally a final view in the second scroll view (all in IB, did not want too much code), and everything is linked up in IB.
I notice that your MainViewController doesn't declare itself as implementing UIScrollViewDelegate, so I also assume that you've forgotten to set it up as the delegate for the scroll view in IB (otherwise it wouldn't compile).
Since it has no delegate defined, the scroll view won't be calling your scrollViewDidScroll function.
Tim
Try this
HeaderFile:
#interface DemoPageControlViewController : UIViewController <UIScrollViewDelegate>
{
IBOutlet UIScrollView *scrollView;
IBOutlet UIPageControl *pageControl;
BOOL pageControlUsed;
NSMutableArray *imageArray;
int pageNumber;
}
#property (nonatomic, retain) UIScrollView *scrollView;
#property (nonatomic, retain) UIPageControl *pageControl;
#property (nonatomic, retain) NSMutableArray *imageArray;
- (IBAction) changePage:(id)sender;
Implementation File:
#import "DemoPageControlViewController.h"
#implementation DemoPageControlViewController
#synthesize pageControl, scrollView, imageArray;
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect frame;
frame.origin.x = 0;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
imageArray = [[NSMutableArray alloc]init];
[imageArray addObject:#"small_one.png"];
[imageArray addObject:#"small_two.png"];
[imageArray addObject:#"small_three.png"];
[imageArray addObject:#"small_four.png"];
// add the last image to first
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed: [imageArray objectAtIndex:([imageArray count] -1)]]];
imageView.frame = CGRectMake(0, 0, scrollView.frame.size.width, scrollView.frame.size.height);
[self.scrollView addSubview:imageView];
[imageView release];
for(int i = 0; i < imageArray.count; i++)
{
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:[imageArray objectAtIndex:i]]];
imageView.frame = CGRectMake((scrollView.frame.size.width * i ) + 320 , 0, scrollView.frame.size.width, scrollView.frame.size.height);
[self.scrollView addSubview:imageView];
[imageView release];
}
// add the first image to last
imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:[imageArray objectAtIndex:0]]];
imageView.frame = CGRectMake(scrollView.frame.size.width * ([imageArray count]+1), 0, scrollView.frame.size.width, scrollView.frame.size.height);
[self.scrollView addSubview:imageView];
[imageView release];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * ([imageArray count]+ 2), self.scrollView.frame.size.height);
[scrollView setContentOffset:CGPointMake(0, 0)];
[self.view addSubview:scrollView];
[self.scrollView scrollRectToVisible:CGRectMake(scrollView.frame.size.width,0,scrollView.frame.size.width,scrollView.frame.size.height) animated:NO];
}
- (IBAction)changePage :(id)sender
{
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage ;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
[self.scrollView scrollRectToVisible:frame animated:YES];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
//pageControlUsed = NO;
NSLog(#"%f", self.scrollView.contentOffset.x);
CGFloat pageWidth = self.scrollView.frame.size.width;
//pageNumber = floor((self.scrollView.contentOffset.x - pageWidth / ([imageArray count]+2)) / pageWidth) + 1 ;
pageNumber = self.scrollView.contentOffset.x / pageWidth;
if(pageNumber == 0)
{
[self.scrollView scrollRectToVisible:CGRectMake((self.scrollView.frame.size.width * [imageArray count]), 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height) animated:NO];
pageNumber = [imageArray count];
//self.pageControl.currentPage = pageNumber;
}
else if(pageNumber == ([imageArray count]+1))
{
[self.scrollView scrollRectToVisible:CGRectMake(self.scrollView.frame.size.width, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height) animated:NO];
pageNumber = 1;
//self.pageControl.currentPage = pageNumber;
}
self.pageControl.currentPage = pageNumber - 1;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
}
This Code works fine. Try this

Leaks in my UIScrollView helper class

I want to publish tutorial about how to easily create an UIScrollView on http://www.xprogress.com/ and I just want to check with you guys if the code is alright before I publish anything. Any help will be appreciated and I'll put your name / website on the bottom of the article :)
Thanks a lot :)
Ondrej
header file:
///
/// IGUIScrollViewImage.h
///
/// IGUILibrary
///
/// Created by Ondrej Rafaj on 7.4.10.
///
/// Copyright 2010 Home. All rights reserved.
///
/// #todo enable margin and center the image to the middle of the view
/**
<b>Examples:</b>
<i>This is just a short example how to use this class</i>
<pre>
- (NSArray *)getImages {
NSMutableArray *arr = [[[NSMutableArray alloc] init] autorelease];
[arr addObject:[UIImage imageNamed:#"image-1.jpg"]];
[arr addObject:[UIImage imageNamed:#"image-2.png"]];
[arr addObject:[UIImage imageNamed:#"image-3.png"]];
[arr addObject:[UIImage imageNamed:#"image-4.jpg"]];
return (NSArray *)arr;
}
- (void)viewDidLoad {
IGUIScrollViewImage *svimage = [[IGUIScrollViewImage alloc] init];
[svimage setSizeFromScrollView:self.scrView]; // takes size of the scroll view you've already placed on stage via Interface Builder
// or
//[svimage setWidth:320 andHeight:240]; // half screen
[svimage enablePositionMemory]; // enables position (pagination) memory for this scroll view
// or
//[svimage enablePositionMemoryWithIdentifier:#"myIdentifier"]; if you have more instances of this scroll view in your application
[svimage enablePageControlOnBottom];
// or
//[svimage enablePageControlOnTop];
[self.myUIView addSubview:[svimage get]]; // and place it on the stage :)
[super viewDidLoad];
}
</pre>
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface IGUIScrollViewImage : NSObject <UIScrollViewDelegate> {
UIScrollView *scrollView;
UIPageControl *pageControl;
CGRect rectScrollView;
CGRect rectPageControl;
int scrollWidth;
int scrollHeight;
NSArray *contentArray;
UIColor *bcgColor;
BOOL pageControlEnabledTop;
BOOL pageControlEnabledBottom;
BOOL rememberPosition;
NSString *positionIdentifier;
}
#property (nonatomic, retain) UIScrollView *scrollView;
- (int)getScrollViewWidth;
- (void)setWidth:(int)width andHeight:(int)height;
- (void)setSizeFromScrollView:(UIScrollView *)scView;
- (void)setBackGroudColor:(UIColor *)color;
- (void)setContentArray:(NSArray *)images;
- (void)enablePageControlOnTop;
- (void)enablePageControlOnBottom;
- (void)enablePositionMemory;
- (void)enablePositionMemoryWithIdentifier:(NSString *)identifier;
- (UIScrollView *)getWithPosition:(int)page;
- (UIScrollView *)getWithPositionMemoryIdentifier:(NSString *)identifier;
- (UIScrollView *)get;
#end
And the implementation file:
//
// IGUIScrollViewImage.m
// IGUILibrary
//
// Created by Ondrej Rafaj on 7.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import "IGUIScrollViewImage.h"
#define kIGUIScrollViewImagePageIdentifier #"kIGUIScrollViewImagePageIdentifier"
#define kIGUIScrollViewImageDefaultPageIdentifier #"Default"
#implementation IGUIScrollViewImage
#synthesize scrollView;
- (int)getScrollViewWidth {
return ([contentArray count] * scrollWidth);
}
- (void)setWidth:(int)width andHeight:(int)height {
scrollWidth = width;
scrollHeight = height;
if (!width || !height) rectScrollView = [[UIScreen mainScreen] applicationFrame];
else rectScrollView = CGRectMake(0, 0, width, height);
}
- (void)setSizeFromScrollView:(UIScrollView *)scView {
scrollWidth = scView.frame.size.width;
scrollHeight = scView.frame.size.height;
rectScrollView = CGRectMake(0, 0, scrollWidth, scrollHeight);
}
- (void)setContentArray:(NSArray *)images {
contentArray = images;
}
- (void)setBackGroudColor:(UIColor *)color {
bcgColor = color;
}
- (void)enablePageControlOnTop {
pageControlEnabledTop = YES;
}
- (void)enablePageControlOnBottom {
pageControlEnabledBottom = YES;
}
- (void)enablePositionMemoryWithIdentifier:(NSString *)identifier {
rememberPosition = YES;
if (!identifier) identifier = kIGUIScrollViewImageDefaultPageIdentifier;
positionIdentifier = identifier;
}
- (void)enablePositionMemory {
[self enablePositionMemoryWithIdentifier:nil];
}
- (UIScrollView *)getWithPosition:(int)page {
if (!contentArray) {
contentArray = [[[NSArray alloc] init] autorelease];
}
if (page > [contentArray count]) page = 0;
if (!scrollWidth || !scrollHeight) {
rectScrollView = [[UIScreen mainScreen] applicationFrame];
scrollWidth = rectScrollView.size.width;
scrollHeight = rectScrollView.size.height;
}
rectScrollView = CGRectMake(0, 0, scrollWidth, scrollHeight);
self.scrollView = [[UIScrollView alloc] initWithFrame:rectScrollView];
self.scrollView.contentSize = CGSizeMake([self getScrollViewWidth], scrollHeight);
if (!bcgColor) bcgColor = [UIColor blackColor];
self.scrollView.backgroundColor = bcgColor;
self.scrollView.alwaysBounceHorizontal = YES;
self.scrollView.contentOffset = CGPointMake(page * scrollWidth, 0);
self.scrollView.pagingEnabled = YES;
UIImageView *imageView;
UIView *main = [[[UIView alloc] initWithFrame:rectScrollView] autorelease];
int i = 0;
for (UIImage *img in contentArray) {
imageView = [[UIImageView alloc] initWithImage:img];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
imageView.backgroundColor = [UIColor blackColor];
float ratio = img.size.width/rectScrollView.size.width;
CGRect imageFrame = CGRectMake(i, 0, rectScrollView.size.width, (img.size.height / ratio));
imageView.frame = imageFrame;
[self.scrollView addSubview:imageView];
i += scrollWidth;
}
[imageView release];
[main addSubview:scrollView];
if (pageControlEnabledTop) {
rectPageControl = CGRectMake(0, 5, scrollWidth, 15);
}
else if (pageControlEnabledBottom) {
rectPageControl = CGRectMake(0, (scrollHeight - 25), scrollWidth, 15);
}
if (pageControlEnabledTop || pageControlEnabledBottom) {
pageControl = [[[UIPageControl alloc] initWithFrame:rectPageControl] autorelease];
pageControl.numberOfPages = [contentArray count];
pageControl.currentPage = page;
[main addSubview:pageControl];
}
if (pageControlEnabledTop || pageControlEnabledBottom || rememberPosition) self.scrollView.delegate = self;
//if (margin) [margin release];
return (UIScrollView *)main;
}
- (UIScrollView *)get {
return [self getWithPosition:0];
}
- (UIScrollView *)getWithPositionMemoryIdentifier:(NSString *)identifier {
[self enablePositionMemoryWithIdentifier:identifier];
return [self getWithPosition:[[[NSUserDefaults alloc] objectForKey:[NSString stringWithFormat:#"%#%#", kIGUIScrollViewImagePageIdentifier, positionIdentifier]] intValue]];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sv {
int page = sv.contentOffset.x / sv.frame.size.width;
pageControl.currentPage = page;
if (rememberPosition) {
[[NSUserDefaults alloc] setObject:[NSString stringWithFormat:#"%d", page] forKey:[NSString stringWithFormat:#"%#%#", kIGUIScrollViewImagePageIdentifier, positionIdentifier]];
}
}
- (void)dealloc {
[scrollView release];
[super dealloc];
}
#end
Just a quick glance. You alloc UIImageView multiple times in
-(UIScrollView*)getWithPosition:(int)page and release it only once:
for (UIImage *img in contentArray) {
imageView = [[UIImageView alloc] initWithImage:img];
// ...
}
[imageView release];

Resources