I am trying to display about 53 images in Xcode for iphone, but about the 37th image crashes my entire app! If any one sees any errors in my code, I would really appreciate your help. Thank you!!
I think I am not releasing my images somewhere...just not sure what to do!
#import "MyProjectViewController.h"
#implementation MyProjectViewController
#synthesize scrollView1;
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
const CGFloat kScrollObjHeight = 320.0;
const CGFloat kScrollObjWidth = 480.0;
const NSUInteger kNumImages = 53;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
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);
}
}
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES;
scrollView1.scrollEnabled = YES;
scrollView1.pagingEnabled = YES;
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"c1_%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i;
[scrollView1 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages];
}
- (void)dealloc
{
[scrollView1 release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Thank you!!!!!
How big are images? I suspect the problem is not with code itself, but with memory limitations of iPhone/iPod - if you're loading big images they simply eat all memory and program is closed.
Well the most likely reason is that you run out of memory. Put an NSLog message in didReceiveMemoryWarning to check if you are getting a warning for low memory.
In any case I would suggest that you lazy load images and not all of the images at once. It will greatly reduce to load time of your app and will also probably solve your memory problems. Use the UIScrollViewDelegate to know when to load images that weren't loaded yet according to the position of the UIScrollView offset value.
Related
I have a question in scroll view.
Right now I wrote a sample about image gallery with scroll view. I have plenty of images added into a scroll view. Each time, it display 3 images, the question is how can measure the scrolling properly. For example: the minimum each scroll is moving 1 image. Right now, I think each time I scroll, the minimum images moving are 3. That make me can't stop at the right image I want to see.
Below is the code.
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scroll 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
[scroll setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scroll bounds].size.height)];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// 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
[scroll setBackgroundColor:[UIColor blackColor]];
[scroll setCanCancelContentTouches:NO];
scroll.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scroll.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scroll.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.
scroll.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
[scroll addSubview:imageView];
[imageView release];
}
[self layoutScrollImages];
}
Use this code......
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if(scroll.contentOffset.y> 320)
{
int y = scrollView.contentOffset.y;
y = y/3;
[scrollView setContentOffset:CGPointMake(0, y)];
}
}
Hope, this will help you...Chill
Subclass the content view and overwrite this function:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([self pointInside:point withEvent:event]) {
if ([[self subviews] count] > 0) {
//force return of first child, if exists
return [[self subviews] objectAtIndex:0];
} else {
return self;
}
}
return nil; }
See detail at https://github.com/taufikobet/ScrollViewCustomPaging.
I am trying to add set of imageviews on a UIScrollView. My problem is that the imageviews are overlapping with each other even though I increase the x value. What's also weird is that this problem is only for devices with ios 4.2.1, but works on simulator 4.2 and other device ios.
Here is my code:
- (void)addScrollView {
[self setImages];
scrollView = [[UIScrollView alloc] initWithFrame:self.frame];
scrollView.delegate = self;
[scrollView setBackgroundColor:[UIColor blackColor]];
[scrollView setCanCancelContentTouches:NO];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
[self addSubview:scrollView];
NSUInteger nimages;
CGFloat cx = 0;
for (nimages = 1; nimages < [imagesArray count] ; nimages++) {
UIImage *image = [UIImage imageNamed:[imagesArray objectAtIndex:nimages]];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.origin.x = cx;
rect.origin.y = 0;
rect.size.width = 320;
rect.size.height = 480;
imageView.frame = rect;
[scrollView addSubview:imageView];
[imageView release];
cx += rect.size.width;
}
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
}
Called from here:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self addScrollView];
UIImage *handImg;
UIImageView *longhand = [[UIImageView alloc] init];
minuteHand = [[UIView alloc] initWithFrame:CGRectMake(0, 55, 320, 480)];
handImg = [UIImage imageNamed:#"clock_long_hand.png"];
longhand.image = handImg;
/************** TRY COMMENT OUT HERE **************/
longhand.frame = CGRectMake(155 - (handImg.size.width / 2), 240 - handImg.size.height, handImg.size.width, handImg.size.height);
[minuteHand addSubview:longhand];
[self addSubview:minuteHand];
/************** END COMMENT OUT HERE **************/
[longhand release];
}
return self;
}
UPDATE:
This code is in a UIView subclass which is why I use [self...] instead of [self.view...].
I tried experimenting and found that when I comment out the indicated parts, the scrollview works fine. But when it is included, this is when the imageviews are overlapped.
I know that the scrollview's content size is correct because its indicator continues to scroll, with just a plain black background.
I am really confused why this works on some ios and not on others. Hope you can help.
This might have something to do with autoresizing mask. The width actual images, I mean .png files is bigger than 320, right?
I am using this code for zoom in and out image in a scroll view. But I don't know what is wrong because zoom in is not working?
const CGFloat kScrollObjHeight = 460.0;
const CGFloat kScrollObjWidth = 320.0;
const NSUInteger kNumImages = 32;
- (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;
//imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image0.jpg"]];
[scrollView1 addSubview:imageView];
[scrollView1 setContentSize:CGSizeMake(imageView.frame.size.width, imageView.frame.size.height)];
scrollView1.minimumZoomScale = 1;
scrollView1.maximumZoomScale = 3;
scrollView1.delegate = self;
[scrollView1 setScrollEnabled: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;
// 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:#"page-%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];
[ImageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView {
return imageView;
}
how add below code for zooming with above code?
#define ZOOM_VIEW_TAG 100
#define ZOOM_STEP 1.5
#interface RootViewController (UtilityMethods)
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center;
#end
#implementation RootViewController
#synthesize imageScrollView, imageView;
- (void)loadView {
[super loadView];
// set the tag for the image view
[imageView setTag:ZOOM_VIEW_TAG];
// add gesture recognizers to the image view
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
UITapGestureRecognizer *twoFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTwoFingerTap:)];
[doubleTap setNumberOfTapsRequired:2];
[twoFingerTap setNumberOfTouchesRequired:2];
[imageView addGestureRecognizer:singleTap];
[imageView addGestureRecognizer:doubleTap];
[imageView addGestureRecognizer:twoFingerTap];
[singleTap release];
[doubleTap release];
[twoFingerTap release];
// calculate minimum scale to perfectly fit image width, and begin at that scale
float minimumScale = [imageScrollView frame].size.width / [imageView frame].size.width;
[imageScrollView setMinimumZoomScale:minimumScale];
[imageScrollView setZoomScale:minimumScale];
}
- (void)viewDidUnload {
self.imageScrollView = nil;
self.imageView = nil;
}
- (void)dealloc {
[imageScrollView release];
[imageView release];
[super dealloc];
}
#pragma mark UIScrollViewDelegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [imageScrollView viewWithTag:ZOOM_VIEW_TAG];
}
/************************************** NOTE **************************************/
/* The following delegate method works around a known bug in zoomToRect:animated: */
/* In the next release after 3.0 this workaround will no longer be necessary */
/**********************************************************************************/
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
[scrollView setZoomScale:scale+0.01 animated:NO];
[scrollView setZoomScale:scale animated:NO];
}
#pragma mark TapDetectingImageViewDelegate methods
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
// single tap does nothing for now
}
- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer {
// double tap zooms in
float newScale = [imageScrollView zoomScale] * ZOOM_STEP;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
[imageScrollView zoomToRect:zoomRect animated:YES];
}
- (void)handleTwoFingerTap:(UIGestureRecognizer *)gestureRecognizer {
// two-finger tap zooms out
float newScale = [imageScrollView zoomScale] / ZOOM_STEP;
CGRect zoomRect = [self zoomRectForScale:newScale withCenter:[gestureRecognizer locationInView:gestureRecognizer.view]];
[imageScrollView zoomToRect:zoomRect animated:YES];
}
#pragma mark Utility methods
- (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center {
CGRect zoomRect;
// the zoom rect is in the content view's coordinates.
// At a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
// As the zoom scale decreases, so more content is visible, the size of the rect grows.
zoomRect.size.height = [imageScrollView frame].size.height / scale;
zoomRect.size.width = [imageScrollView frame].size.width / scale;
// choose an origin so as to get the right center.
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
return zoomRect;
}
in above code how zoom images in scroll view?
You can use Pinch gesture recognizer for zoom in/out. Check following link:
How can I use pinch zoom(UIPinchGestureRecognizer) to change width of a UITextView?
I'm building an app based upon the "Scrolling" sample code that Apple provided. All is working very well. The nature of the images that I want to display, would make it desirable, if the order of the images is reversed, and that the first visible image is the right-most, rather than the left most. Basically, the user should scroll back, from right to left, rather than from left to right.
But now: I don't understand the syntax Apple is using, and I hope someone can explain to me what is going on. Here are the relevant parts of the sample app:
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor whiteColor];
// 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];
[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
- (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)];
}
So this is what I ended up doing:
I first inverted the order of the subviews, and then I made the scrollview jump to the last 'frame', by adding the following lines:
CGPoint lastFrame = CGPointMake(((kNumImages -1) * kScrollObjWidth), 0.0f);
[scrollview setContentOffset:lastFrame];
I hope that this somehow is useful to somebody...
It looks like you need to modify layoutScrollImages. Initialize curXLoc to the max number needed, and decrement it in the loop.
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = kNumImages * kScrollObjWidth;
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)];
}
How would I add a dissolve transition to my code?
I tried looking at Apple's code but to no avail. Any ideas?
#import "ApotheosisViewController.h"
#implementation ApotheosisViewController
#synthesize scrollView1;
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
const CGFloat kScrollObjHeight = 320.0;
const CGFloat kScrollObjWidth = 480.0;
const NSUInteger kNumImages = 40;
- (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 = UIScrollViewIndicatorStyleBlack;
scrollView1.clipsToBounds = NO; // 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;
// 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];
[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
- (void)dealloc
{
[scrollView1 release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// invoke super's implementation to do the Right Thing, but also release the input controller since we can do that
// In practice this is unlikely to be used in this application, and it would be of little benefit,
// but the principle is the important thing.
//
[super didReceiveMemoryWarning];
}
#end
I can't immediately tell what the code you posted has to do with a dissolve transition.
If you are trying to go from one view to another, then you could put this in your code:
In
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
for one viewController:
self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
and when switching from one view to the other:
[self presentModalViewController:otherViewController animated:YES];