UIScrollview containing many images - iphone

I'm using UIScrollview in Xcode 4.6. I want to insert around 30 images into the scrollview. Within the storyboard I can't add this many as it doesn't actually let you scroll down on the storyboard to add more images, hence all the images overlap each other.
The answer is probably quite simple so sorry if this is a dumb question. How do I add this many images to the scrollview, is there a way to code it like in Android xml? Or is there anyway to not have the images overlap?

Also consider using a UITableView. It may be a more efficient way of handling that many images. You can load them as they're displayed, rather than all at once.

You won't want to do this in Interface Builder - that will make it a creation and maintenance nightmare.
Instead, do it in code. You'll want to Google UIScrollView tutorial to get started. It's really quite easy - much easier than dragging out a bunch of image views by hand.

So this is problem that I have solved before. There are a few ways that you could solve this I think the new preferred way at least in iOS 6.x you could opt to use UICollectionView.
UICollectionView View Apple Docs
This is a great tutorial site that has loads of helpful information
UICollectionView Tutorial
Also one solution I came up with was loading and placing the images manually. And then based on the size needed width wise I set my UIScrollView setcontentSize property.
//Clean Up and remove old buttons
for(int i=0; i < _localButtonArray.count; i++){
[(CategoryButton*)[_localButtonArray objectAtIndex:i] removeFromSuperview];
}
[_localButtonArray removeAllObjects];
CGFloat baseX = 10,
X = 0,
Y = 0;
int xPadding = 20,
yPadding = 12,
index = 0,
maxRow = 4,
maxCol = 4,
colCount = 0;
CGRect buttonFrame;
buttonFrame.size.height = 137;
buttonFrame.size.width = 137;
buttonFrame.origin.y = X;
buttonFrame.origin.x = Y;
for(int i = 0;i < _localInfoArray.count ; i++){
id object = [_localInfoArray objectAtIndex:i];
if(index >= maxRow){
index = 0;
X = baseX;
Y += buttonFrame.size.height + yPadding;
if(colCount >= (maxRow * maxCol)){
colCount=0;
baseX += 637;
Y = 0;
}
}
X = baseX + (index * (buttonFrame.size.width + xPadding));
index++;
colCount++;
buttonFrame.origin.x = X;
buttonFrame.origin.y = Y + yPadding;
/*
* Custom button class
*/
CategoryButton * categoryButton = [[CategoryButton alloc]initWithFrame:buttonFrame Object:object];
//Add action
[categoryButton addTarget:self action:#selector(categoryButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[categoryButton.titleLabel setNumberOfLines:3];
[categoryButton.titleLabel setLineBreakMode:NSLineBreakByWordWrapping];
[categoryButton.titleLabel setFont:[UIFont fontWithName:#"Helvetica-Bold" size:19]];
[categoryButton.titleLabel setTextAlignment:NSTextAlignmentCenter];
[categoryButton setMultipleTouchEnabled:NO];
[_localButtonArray addObject:categoryButton];
[self.view addSubview:categoryButton];
}
There is a lot of other code that isn't here, but laying out the page is handled here.
Even this isn't an optimal solution, but hopefully it will help you.
Best of luck ^_^

Related

Why is UIView drawRect causing first pass of UIScrollview to be choppy/jerky/slow?

EDIT: It looks like the problem code is in a procedural background that I am drawing in a UIView which I am then adding as a subview to UIScrollView. The procedural code is below. It draws box shapes, which look sort of like a skyline. Any Ideas why this is slowing down the first pass of my UIScrollView? It can be as much as a thousand pixels wide or more at times. See image...
- (void)drawRect:(CGRect)rect
{
UIBezierPath *vertLine = [[UIBezierPath alloc] init];
[vertLine moveToPoint:CGPointMake(0,self.frame.size.height)];
int detail = 10;
int ranNum = 0;
int count = self.bounds.size.width/detail;
CGFloat heightIncrement = 0.0;
CGFloat minHeight = self.frame.size.height;
CGFloat xPos = 0;
CGFloat yPos = self.frame.size.height-20;
for (int i =0; i<count; i++)
{
ranNum += (arc4random() % 9)-5;
yPos -= (arc4random() % 30);
[vertLine addLineToPoint:CGPointMake(xPos,yPos)];
xPos += (arc4random() % 20)+10;
[vertLine addLineToPoint:CGPointMake(xPos,yPos)];
yPos += (arc4random() % 30);
[vertLine addLineToPoint:CGPointMake(xPos,yPos)];
xPos += (arc4random() % 30);
[vertLine addLineToPoint:CGPointMake(xPos,yPos)];
if (yPos>self.frame.size.height-10) {
yPos = self.frame.size.height-10;
}
if (yPos<self.frame.size.height-50) {
yPos = self.frame.size.height-50;
}
}
[vertLine addLineToPoint:CGPointMake(count*20,(self.frame.size.height))];
[[UIColor colorWithRed:0.0/255.0 green:38.0/255.0 blue:51.0/255 alpha:1] setFill];
[vertLine fill];
}
I have a jerky scroll view, but ONLY on the first pass. After all the views have been viewed in the scroll view, it is very smooth.
First Pass: During the first pass it appears that when each UIImageView is coming into view (from right to left) There is a jerk right when it is entering the visible area. So if you reference the attached image, you'll see UIImageView 5 entering from right to left. When this happens there is a small pause as if the scroll view is telling the image view to load/prepare to be on stage. I have tried to profile this but I don't see any problems in my code and im not sure how I can profile the methods etc. that I have not overridden. So a sub question would be... What methods are called on a subview of UIScrollView when it is entering the visible area?
As I mention I tried to do the async and other concurrent approaches, but it seems that no matter how the images are loaded, the first pass is always jerky, then its as if the UIScrollView caches the subviews. Is it possible to do this caching/loading up front...
[scrollView cacheSubViews]; I would rather have a slower startup than it to be clunky on the first scroll.
Thanks for any ideas on this or information about how the UIScrollView works with its subviews. I have seen many questions and some solutions about jerky UIScrollViews with UIImageViews as subviews. I have tried many of them, but still have a slow scrollview.
austin
imageWithContentsOfFile is a synchronous process takes a lot of tile.Use some asynchronous way to load the images and the smoothness can be achieved

multiple uiimageviews from for loop

I am writing a game in which a Uiimageview needs to be 'spawned,' if you will. every time the character hits the end box. Everything else is working except that. Could someone check my code and see what I'm doing wrong? Thanks!
for (int i = 1; i <= level; i++) {
int xPos = rand() % 316;
int yPos = rand() % 450;
UIImageView *mine = [[UIImageView alloc] initWithFrame:CGRectMake(xPos, yPos, 10, 10)];
}
You are not adding the views that you create in a loop as subviews to your main view. That's why they do not become visible.
As a side note, I think you would be better off using CALayer objects instead of UIImageView: they are lighter-weight, and require about the same amount of work.

How to adjust width of TTStyledTextLabel?

I am implementing an IM app on iOS. I found that three20 library has a TTStyledTextLabel which provides cool features like showing images and url links. However I want to embed the TTStyledTextLabel in a message bubble (just like the sms app shipped with iphone does), where I need the label to adjust its size according to the text length. I found that TTStyledTextLabel can adjust its height according to its width, but I don't know how to make it shrink horizontally when the text is very short and can't fill up a whole line. Any suggestions?
I think I have a slightly better solution: I get the rootFrame of the ttstyledtext and iterate over its sibling frames to find the max width.
It works like this:
TTStyledTextLabel* label = [[TTStyledTextLabel alloc] init];
label.text = [TTStyledText textFromXHTML:myTextToBeDisplayed];
[label sizeToFit];
CGFloat maxWidth = 0;
TTStyledFrame *f = label.text.rootFrame;
while (f) {
int w = f.x + f.width;
if (w > maxWidth) {
maxWidth = w;
}
f = f.nextFrame;
}
return CGSizeMake(maxWidth, label.height);
I tried doing it by incrementally passing the width parameter in size to sizeToFit and looking at the resulting height to give cues in terms of whether the size is ok. But this is not a elegant solution
for (int index = 100; index < 320; index= index+30)
{
label.width = x;
if (label.height < 20)
break;
}

How to get the Template Chooser/Document Browser view on iOS?

What is the view used to create the Template Chooser view in the iWork apps on iPad?
How can I create a view like that on iPad, and what would be a best way to implement it on iPhone considering screen size constraints.
There isn't any built-in view that will provide that functionality. Which means there will be quite some work to duplicate that functionality.
What you can try is:
1) Create a new UIViewController with a nib.
2) Add the top bar and an UIScrollView with opaque = NO and alpha = 0.
3) If you have a fixed number of "templates" they can be added directly in the nib. You should be able to use UIImageView
4) Otherwise you can add the "templates" dynamically in e.g. viewDidLoad. The only part which can be a little bit tricky is calculating the frame. The following pseudo code should get you started.
int MARGIN = 20;
float templateWidth = self.scrollView.bounds.size.width / 3;
float templateHeight = 300;
for (int i = 0; i < [templates count]; i++) {
int row = i / 3;
int col = i % 3;
float x = MARGIN + col * templateWidth;
float y = MARGIN + row * templateHeight;
CGRect templateFrame = CGRectMake(x, y, width - 2 * MARGIN, height - 2 * MARGIN);
// initialize `UIImageView` or similar
templateView.frame = templateFrame;
[self.scrollView addSubView:templateView];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.width, /* max bottom of templates */);
}
After you have got the layout perfected the rest should be quite straightforward since you only need to respond to taps on your template images. Take a look at UITapGestureRecognizer for one way of doing that.
Regarding the iPhone. I would probably do it in the way you select a document in the iWorks apps. Only one template is displayed on screen at the time and you swipe left/right to choose. But it all depends on the context. Perhaps a table view is better suited for the iPhone.
Good luck!
With iOS 6, use UICollectionView!

managing images in UIScrollView

i'm not understanding where in my code i write in the image names and in what order to appear. Here is my code
// 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];
I have images that are titled "image0.jpeg, image1.jpg." how to i insert this into my code and order them in a certain way?
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
use %d for signed int
and %u for unsigned
Your code snippet is already doing what you want - at least partially.
If you have an image numbered 0, then you need to start your loop with i = 0 instea of i = 1, and adjust the constraint appropriately:
for (NSUInteger i = 0; i < kNumImages; i++) {
NSString *imageName = [NSString stringWithFormat:#"image%u.jpg", i];
// create the image and insert into imageview
// add imageview to the containing view
}
The order is quite straight forward, as the images will be added 0, 1, 2.. and so forth
With the code from your first post, you create multiple (kNumImages, to be more specific) ImageViews, and load in them JPG files from your project directory, called "imageN.jpg", where N is integer between 1 and kNumImages.
To display these newly created views in your UIScrollView, you have to add them to it as subviews.
Something like
for (int i = 0; i < pageCount; i++) {
UIView *view = [pageViews objectAtIndex:i];
if (!view.superview)
[scrollView addSubview:view];
view.frame = CGRectMake(pageSize.width * i, 0, pageSize.width, pageSize.height);
}
The most straightforward way to do this is in UIScrollView's UIViewController. You may want to add them in some sort of collection (it's likely that the collection retains them, so don't forget to release the views, when you add them).
As you get more comfortable with your application, you may want to lazy-load the views or use simple UIViewControllers for the different images.
In iPhone OS 3.0 and above, there are significant improvements in UIScrollView, and you can find excellent code samples in the ScrollViewSuite tutorial project on ADC's iPhone section.