I am attempting to make a basic scroll view with a connected page control, and I have run into some problems with my code. My viewDidLoad method looks like this:
- (void)viewDidLoad{
[super viewDidLoad];
NSLog (#"View did load");
// Do any additional setup after loading the view, typically from a nib.
scrollView.delegate = self;
scrollView.pagingEnabled=YES;
NSArray *frames = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
for (int i = 0; i < frames.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [frames objectAtIndex:i];
[self.scrollView addSubview:subview];
NSLog (#"Looped, i = %i color = %#", i, [frames objectAtIndex:i]);
}
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * frames.count, scrollView.frame.size.height);
NSLog(#"The width is: %f", self.scrollView.frame.size.width);
}
The problem seems to be that the coloured frames I attempt to add to the view never appear (not even the first one). If I didn't have ARC enabled, I would have released the CGRect frame at the end of each loop, but it really should do that itself with ARC, right?
When I run the app, both in the simulator and on my actual phone, I get a black screen with the UIPageControl dots at the bottom. When I swipe my finger across the ScrollView nothing happens, but if I pull it very far to one side, the pageControl moves to the next "dot".
The last NSLog sentence always outputs 0.0000, indicating that none of the views have been added to the scroll view.
All help is very appreciated :)
The problem is doing it in viewDidLoad. Move your code to viewDidAppear: and it should work fine. Frames are not yet set in viewDidLoad.
Related
I followed the tutorial about how to create a scrollView Page Control: http://www.iosdevnotes.com/2011/03/uiscrollview-paging/
This tutorial is really good and I implement well the code. Here my question:
I want to put a space between the my PageViews, but when it change the page it show the space between the views in the next page. The scroll must stop after the space when I change the page.
I changed the tutorial code here:
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
#define space 20
for (int i = 0; i < colors.count; i++) {
CGRect frame;
frame.origin.x = (self.scrollView.frame.size.width + space) * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [colors objectAtIndex:i];
[self.scrollView addSubview:subview];
[subview release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * colors.count+ space*(colors.count-1), self.scrollView.frame.size.height);
}
It sounds like you want a “gutter” between the pages, so that each page fills the scroll view and the gutter is only visible while the user is dragging the view. The built-in Photos app does this, for example.
Make your scroll view wider by space points. For example, if you want the scroll view to appear to be as wide as the screen (320 points), with a 20 point margin between items, then make the scroll view 340 points wide, with the extra 20 points hanging off the right edge of the screen.
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor blueColor], nil];
#define kGutterWidth 20
UIScrollView *scrollView = self.scrollView;
CGRect scrollViewFrame = scrollView.frame;
scrollViewFrame.size.width += kGutterWidth;
scrollView.frame = scrollViewFrame;
CGSize scrollViewSize = scrollView.bounds.size;
for (int i = 0; i < colors.count; i++) {
CGRect frame = CGRectMake(scrollViewSize.width * i, 0,
scrollViewSize.width - kGutterWidth, scrollViewSize.height);
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [colors objectAtIndex:i];
[scrollView addSubview:subview];
[subview release];
}
scrollView.contentSize = CGSizeMake(
colors.count * scrollViewSize.width,
scrollViewSize.height);
}
I've been down this road before, and I would advise laying out the scroll view as the tutorial code recommends, with no space between the subviews.
Instead, give each subview another subview whose frame is inset from it's parent...
CGRect scrollViewFrame = self.scrollView.frame;
for (int i=0; i<colors.count; i++) {
CGRect frame = CGRectMake(scrollViewFrame.size.width * i, 0, scrollViewFrame.size.width, scrollViewFrame.size.height);
// this will be our framing view, full size with no gaps
UIView *subview = [[UIView alloc] initWithFrame:frame];
subview.backgroundColor = [UIColor whiteColor];
// here's the trick - use CGRectInset on the framing view's bounds
UIView *colorView = [[UIView alloc] initWithFrame:CGRectInset(subview.bounds, 10, 10)];
colorView.backgroundColor = [colors objectAtIndex:i];
[subview addSubview:colorView];
[self.scrollView addSubview:subview];
// aren't you using ARC? your tutorial is probably older than ARC
// would strongly suggest converting to ARC
[subview release];
[colorView release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * colors.count, self.scrollView.frame.size.height);
The benefit of this approach is that the math for the top level subview layout remains a simple multiple of the width. The only place you'll refer to that inset constant is on the CGRectInset where it belongs.
I would like to display an image (width: 320 pixels, height: 1250 pixels) in an image view.
When I compile the application I get no scrolling at all. The view stays fixed.
What I did:
Added an UIScrollView via Interface Builder to my view.
Added an UIImageView via Interface Builder to my view.
Verified that UIImageView is below UIScrollView in Interface Builder.
Set the size of the UIScrollView with ViewDidLoad.
How do I do this?
Code:
- (void)viewDidLoad
{
[super viewDidLoad];
scrollView.contentSize = CGSizeMake(320, 1250);
}
Screenshots:
ImageView:
ScrollView:
I just have done the same task..
Try this one.....
scrollView.delegate = self;
scrollView.scrollEnabled = YES;
int scrollWidth = 120;
scrollView.contentSize = CGSizeMake(scrollWidth,80);
int xOffset = 0;
imageView.image = [UIImage imageNamed:[imagesName objectAtIndex:0]];
for(int index=0; index < [imagesName count]; index++)
{
UIImageView *img = [[UIImageView alloc] init];
img.bounds = CGRectMake(10, 10, 50, 50);
img.frame = CGRectMake(5+xOffset, 0, 50, 50);
NSLog(#"image: %#",[imagesName objectAtIndex:index]);
img.image = [UIImage imageNamed:[imagesName objectAtIndex:index]];
[images insertObject:img atIndex:index];
scrollView.contentSize = CGSizeMake(scrollWidth+xOffset,110);
[scrollView addSubview:[images objectAtIndex:index]];
xOffset += 70;
}
Also set this one....
imagesName = [[NSArray alloc]initWithObjects:#"image1.jpg",#"image2.jpg",#"image3.jpg",#"image4.jpg",#"image5.jpg",#"image6.png",#"image7.png",#"image9.png",nil];
images = [[NSMutableArray alloc]init];
So for me the problem was that setting the content size didn't work in viewDidLoad(). I tried everything and I didn't understand why it wouldn't want to work, and then I tried the same stuff in viewDidAppear() and it magically worked...
From you last screenshot and from your comments it looks like your scrollView is way to big.
The scrollview must be visible on screen completely. For example a full screen UIScrollView on iPhone would have a size of 320 x 460.
If the scrollview is the same size as its content you can't scroll.
The greenish rectangle shows the size of your scrollview, the pinkish the size of your content (your image):
Xcode 11+, Swift 5
You can find the complete solution here.
I came across this same issue on iOS6 and the solution was to programmatically adjust the ContentSize.
So I will just quote from Raja (above) to show this:
CGSize scrollViewContentSize = CGSizeMake(320, 400);
[self.scrollView setContentSize:scrollViewContentSize];
NOTE: I was not having this issue on iOS5.. seems like iOS6 decided to do alot of prank just like the rotation/orientation saga
Since Xcode 5 it does not work like before. Also scrolling to the end of a scrollable text field makes problems. There are also differences between doing it on iPhone or iPad. On iPhone it worked without delayed timer.
This worked for me:
- (void)viewDidLoad
{
[super viewDidLoad];
NSTimer *timerforScrollView;
timerforScrollView =[NSTimer scheduledTimerWithTimeInterval:0.1
target:self selector:#selector(forScrollView)userInfo:nil repeats:NO];
}
- (void) forScrollView {
[scrollviewPad setScrollEnabled:YES];
[scrollviewPad setContentSize:CGSizeMake(768, 1015)]; // must be greater then the size in Storyboard
}
I found I had a similar problem but none of the above code worked. The issue was due to autolayout. I found that if I turned off autolayout by going to the storyboard clicking on Utilities -> File Inspector and unchecked Use Autolayout the scrolling did work (I also set scroll.contentSize = ...).
Sometimes autoLayout checkbox is ticked in the xib. That also creates this issue in xcode 5. Which makes the UIScrollView scrolling off.
Don't forget to add the category protocol to the interface, like this
#interface MyViewController : <UIScrollViewDelegate>
If you don't, you will not be able to set the scroll view delegate to self
(i.e. [MyScrollView setDelegate:self];)
If you do this, it should work.
My code is:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[contentScrollView setDelegate:self];
[contentScrollView setScrollEnabled:YES];
contentScrollView.contentSize = CGSizeMake(310, 500);
contentScrollView.frame = CGRectMake(5, 188, 310, 193);
}
Did you assign the scroll's view delegate? Always remember these:
[self.scrollView setDelegate:self];
[self.scrollView setScrollEnabled:YES];
The image view has to be a subview (so inside AND below) of the scrollview. From your description it seems they are paralell
You forgot one line. Add this to your view load function:
[scrollView setScrollEnabled:YES];
You could try disabling AutoLayout. In XCode 5 I tested all the above answers and I could only scroll it by disabling autolayout and activating all autosizing masks under the Size Inspector. The following code was used too:
self.scrollView.contentSize = CGSizeMake(320, 900);
self.scrollView.delegate = self;
self.scrollView.scrollEnabled = YES;
self.scrollView.frame = self.view.frame;
CGRect scrollViewFrame = CGRectMake(0, 0, 320, 400);
self.scrollView = [[UIScrollView alloc] initWithFrame:scrollViewFrame];
[self.view addSubview:self.scrollView];
CGSize scrollViewContentSize = CGSizeMake(320, 400);
[self.scrollView setContentSize:scrollViewContentSize];
scrollView.delegate = self;
[self.scrollView setBackgroundColor:[UIColor blackColor]];
[scrollView setCanCancelContentTouches:NO];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.clipsToBounds = YES;
scrollView.scrollEnabled = YES;
scrollView.pagingEnabled = YES;
NSUInteger nimages = 0;
CGFloat cx = 0;
for (; ; nimages++) {
NSString *imageName = [NSString stringWithFormat:#"image%d.jpg", (nimages + 1)];
UIImage *image = [UIImage imageNamed:imageName];
if (image == nil) {
break;
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = image.size.height;
rect.size.width = image.size.width;
rect.origin.x = ((scrollView.frame.size.width - image.size.width) / 2) + cx;
rect.origin.y = ((scrollView.frame.size.height - image.size.height) / 2);
imageView.frame = rect;
[scrollView addSubview:imageView];
[imageView release];
cx += scrollView.frame.size.width;
}
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
Assuming that scrollView is a subview of view and fills it entirely you can use the following in viewDidLoad:
[scrollView setContentSize: CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)];
I had a UIScrollView that was not scrolling and this allowed it to scroll.
Just add code
scrollView.contentSize = CGSizeMake(WIDTH,HEIGHT);
to method -(void)viewDidLayoutSubviews.
For more information checkout Stanford CS193p Lecture No 8 to understand View Controller Life cycle.
I had the same issue and was looking for the answer in this thread. I tried all the stuff, but nothing works. Then I found this:
.
You just need to deselect "Use Auto Layout" in File Inspector of your ViewController. Ta-Da, it works immediately for me. Enjoy.
I'm a newbe on iOS development, I'm trying to make a scroll header like Engadget's app for iPhone, i created a custom UIView to act as a subview for UIScrollView, the algorithm for placing the subviews seems to be ok as I can Scroll the subviews, programatically i change the background color of the views, but the problem is that I can't see anything of the content, just gray backgrounds what am I doing wrong?
Thanks in advance.
This is my code:
Promoted is a UIView with two labels and a UIImageView.
- (void)layoutScrollSubViews
{
promoted *view = nil;
NSArray *subviews = [sView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[promoted class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
frame.size.height = kScrollObjHeight;
frame.size.width = kScrollObjWidth;
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[sView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [sView1 bounds].size.height)];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad{
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
promoted *p = [[promoted alloc] initWithFrame:CGRectMake(0, 0, 320, 187)];
p.title.text = #"Test 1";
p.num.text = #"1/1";
p.num.backgroundColor = [UIColor whiteColor];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
p.backgroundColor = [UIColor colorWithRed:(.9/i) green:(.9/i) blue:(.9/i) alpha:1];
p.tag = i; // tag our images for later use when we place them in serial fashion
[sView1 addSubview:p];
[p release];
}
[self layoutScrollSubViews];
[super viewDidLoad];
}
You can do two things:
1. Add your image view and labels directly to scrollView
2. also alloc your label and ImageView before adding them to your UIView(and don't forgot to release them when requirement is finish, in respective scope)
As per my experience, UIScrollView is a weird buggy control released by apple. Don't know why it behaves abnormal when added through nib file. I always try to create UIScrollView programmatically and add subviews to it by allocating them programmatically as well.
May be it would sound strange, but it works for me most of the time!
I'm building a comic viewer app, that consists of two view controllers, the root viewcontroller basically displays a view where a user decides what comic they want to read by pressing a button. The second viewController actually displays the comic as a uiscrollview with a toolbar and a title at the top.
So the problem I am having is that the comic image panels themselves are not changing from whatever the first comic you go to if you select another comic after viewing the first one. The way I set it up, and I admit it's not exactly mvc, so please don't hate, anyway the way I set it up is each comic uiscrollview consists of x number of jpg images where each comic set's image names have a common prefix and then a number like 'funny1.jpg', 'funny2.jpg', 'funny3.jpg' and 'soda1.jpg', 'soda2.jpg', 'soda3.jpg', etc...
so when a user selects a comic to view in the root controller it makes a call to the delegate and sets ivars on instances of the comicviewcontroller that belongs to the delegate (mainDelegate.comicViewController.property) I set the number of panels in that comic, the comic name for the title label, and the image prefix.
The number of images changes(or at least the number that you can scroll through), and the title changes but for some reason the images are the same ones as whatever comic you clicked on initially.
I'm basing this whole app off of the 'scrolling' code sample from apple.
I thought if I added a viewWillAppear:(BOOL) animated call to the comicViewController everytime the user clicked the button that would fix it but it didn't, after all that is where the scrollview is laid out.
Anyway here is some code from each of the two controllers:
RootController:
-(IBAction) launchComic2{
AppDelegate *mainDelegate = [(AppDelegate *) [UIApplication sharedApplication] delegate];
mainDelegate.myViewController.comicPageCount = 3;
mainDelegate.myViewController.comicTitle.text = #"\"Death by ETOH\"";
mainDelegate.myViewController.comicImagePrefix = #"etoh";
[mainDelegate.myViewController viewWillAppear:YES];
[mainDelegate.window addSubview: mainDelegate.myViewController.view];
comicViewController:
-(void) viewWillAppear:(BOOL)animated {
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 whiteColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= self.comicPageCount; i++)
{
NSString *imageName = [NSString stringWithFormat:#"%#%d.jpg", self.comicImagePrefix, i];
NSLog(#"%#%d.jpg", self.comicImagePrefix, 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((self.comicPageCount * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
Any help would be appreciated on this.
Nick
So what I ended up doing is just making multiple instances of the comic controller inside the delegate instead of just re-using the one. Will update this if I run into problems.
Nick
I'm ATTEMPTING to learn UIScrollview using Apple's Docs and their sample code http://developer.apple.com/iphone/library/samplecode/Scrolling/index.html but something SO simple is escaping me.
How do you tell what image is currently on the screen, so that if I selected one of the images in the horizontal scrolling view, how would I get the filename of the image, or even a pointer in the array, to then do something further with the image?
I thought with Page Control enable I might be able to find a page # and map it to the image. I thought about counting deceleration to count pages, but a flick no full enough will increment it and give a false number.
The last thing I could think of is to get contentOffSet and divide by image size which will give a 1, 2, 3 and I could point to the array (too tired to try tonight... thought I might ask before I waste a lot more time ;-) ).
Any other ideas? I thought there would be a method somewhere that they use in the photo album app.
PS: Here's the code:
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
// set the content size so it can be scrollable
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// 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:#"Card %d.png", 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
This was easy after a good sleep!
CGPoint p = scrollView1.contentOffset;
NSLog(#"x = %f, y = %f", p.x, p.y);
Now just divide by 320 (if horizontal and full screen image) and add 1 (because it starts at 0).
Hope this helps someone else!
Paul