Scroll view with dynamically created thumbnails on iPhone and iPad - iphone

I need one long scrollable view with 2 thumbnails (wallpapers) in every row.
Every thumbnail has also a button to share and download photo, and when you click the thumbnail it shows full size wallpaper. So I was thinking about making a custom view (200x200) which will contain thumbnail and two buttons, and add them dynamically to scroll view depending how many wallpapers are on server.
Something like this:
NSUInteger i;
int xCoord=0;
int yCoord=0;
int thumbnailWidth=200;
int thumbnailHeight=200;
int buffer = 10;
for (i = 1; i <= [items count]; i++)
{
UIView *aView = [[ThumbnailView alloc] initWithThumnailAtIndex: i ];
aView.frame = CGRectMake(xCoord, yCoord, thumbnailWidth, thumbnailHeight );
[scrollView addSubview:aView];
xCoord += thumbnailWidth + buffer;
yCoord += thumbnailHeight + buffer;
}
[scrollView setContentSize:CGSizeMake(700, yCoord)];
Do you think that is a good way to do this?
Also, how would I handle lazy loading of thumbnails if there are a lot of thumbnails in scrollview?

As everybody else here has said, use a UITableView. I will add that you should use a custom UITableViewCell subclass. Create the class, then use Storyboards to make a table view scene with prototype cells. Set the class of the prototype cell to your cell subclass. Add as many imageview, labels, buttons, whatever nonsense you want to the prototype cell on the storyboard, then hook those up to your custom class using IBOutlets. Now when it's time to display something in the cell, just pass an object or dictionary containing all the info that's needed to the custom cell subclass, and have it populate the various view via the outlets. Here's a tutorial: http://www.techotopia.com/index.php/Using_Xcode_Storyboards_to_Build_Dynamic_TableViews_with_Prototype_Table_View_Cells

I would suggest you use the UITableView with custom UITableViewCell implementations. The tableview will automatically handle the recycling of the cells, so you would not need to worry as much about performance.
You could pre-load all your assets during the view initialization and then simply use them in the tableview's datasource.

I would use a UITableView and each cell would contain both images. Take a look at this answer.
About loading the images, try using EGOImageLoader, is very simple and effective. Here is the Github project.

Related

Shifting UITableView down (UITableViewController)

I am just wondering whether or not it is possible to shift a UITableView down the page by, say, maybe 50 pixels. I know this would usually work if I had used a UIViewController then added a table view on top, but would I be able to do this and still keep it as UITableViewController?
I had the same problem and the answer above didn't work. This did:
[self.tableView setContentInset:UIEdgeInsetsMake(50,0,0,0)];
My solution is to override tableViewcontroller's method viewWillLayoutSubviews
- (void) viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.tableView.frame = CGRectMake(0,0,CGRectGetWidth(self.view.frame),300);
}
Works great and always for me with changing orientations and in all situations
A UITableView is actually a UIScrollView. This means that you can scroll the UITableView to the point you want. This is a previous link which shows you how to do this, including sample code and discussion.
Edit: In order to shift the WHOLE tableview down, just use:
float yOffset = 50.0f; // Change this how much you want!
tableview.view.frame = CGRectMake(tableview.view.frame.origin.x, tableview.view.frame.origin.y + yOffset, tableview.view.frame.size.width, tableview.view.frame.size.height);
Hope that Helps!
Since a Table View is backed by a UIScrollView you can move in around using the content Offset.
self.tableView.contentOffset = CGPointMake( x, y);
You might want to wrap in a UIView animation
If you are trying to add a UI element at the top of the table, why not just set it to the tableHeaderView instead?
UILabel *someLabel;
// configure label
self.tableView.tableHeaderView = someLabel;
If you need a view behind (or on top of) the tableview, then you'll have to subclass UIViewController instead and add a UITableView afterwards.
Another solution could be to set the table's header view (reference) but in this case, keep in mind that this view will scroll together with the table.
More information about the limitations of UITableViewController in this article: "Clean table view code".
Swift 2.2:
To shift the tableView inside a UITableViewController down:
let edgeInsets = UIEdgeInsetsMake(20, 0, 0, 0)
self.tableView.contentInset = edgeInsets
UITableViewController is actually a UIViewController, only plus is it gives you some methods to override and useful for table actions. so you can do whatever you want
check this, once you get the idea of what UITableViewController actully is you will do whatever you want
http://cocoawithlove.com/2009/03/recreating-uitableviewcontroller-to.html

UITableView Cell Layout

I am trying to change the look of the tableviewcells by adding columns. I know the normal tableview doesn't allow this. Can someone point me in the right direction to achieve something similar to the attached image? The basic functionality is to have a grid of cells. 3x3 and any of the 9 cells can be clicked and it opens another page. its similar to the image picker but instead of images it would be cells with subtitles etc.
http://www.bronron.com/apps/IpadMenu.jpg
Any ideas?
Thanks in advance.
I would recommend that you try using a UIScrollView instead of a UITableView for this.
Each item in your menu can be a UIImageView, or a UIButton which you add as subviews to your UIScrollView.
The following code can be insterted in viewDidLoad inside your view controller and assumes that you have setup your UISCrollView in interface builder, otherwise you would need to allocate your scroll view inside viewDidLoad.
The code will add a variable number of menu items to a UIScrollView with two columns. To deal with user input you can make all the menu items UIButtons which call associated IBAction methods, or in this case the menuItems are you views, so you can identify which menu item the user is touching by looking at the users touch location within the scroll view, and then carrying out the appropriate action based on this.
UIImageView *menuItem = nil;
//The x and y view location coordinates for your menu items
int x = 0, y = 0;
//The number of items you want in your menu
int numOfItemsToAdd = 10;
//The height and width of your menu items
int menuItemHeight = 50, menuItemWidth = 50;
//The content seize needs to refelect the number of menu items that will be added
//The hieght of the ocnten size is calclutated by multiplying the menu item height by the number of
//menu items devided by the number of menu items that fit across in the width of the view.
[scrollView setContentSize:CGSizeMake(320, menuItemHeight*numOfItemsToAdd];
for(int i=0; i<numOfItemsToAdd; i++){
if(i%2 == 0){//% the number of columns you want in your menu
x = 0;
if(i!=0)
y += menuItemHeight;
}else{
x = menuItemWidth;
}
menuItem = [[UIImageView alloc] initWithFrame: CGRectMake(x, y, menuItemWidth, menuItemHeight)];
//set the center of the menu item in the scroll superviews coordinate system
menuItem.center = CGPointMake(x, y);
//Add the name of the image you want for the menu item
//These strings could be stored in an array and retrieved in order
menuItem.image = [UIImage imageNamed:#"MyImage"];
//Finaly add the menu item to the scorll view
[scrollView addSubview:menuItem];
}
You can go for multi column grid table view layout , where you can define each and every row and column.
you can check this tutorial for Drawing a Grid in a iPhone UITableView – Tabular Cell Data
http://www.iphonedevx.com/?p=153
This is a completely custom view layout and IMHO, not really suitable for a table view. As with anything custom there are many ways to achieve what you want. Here's how I would approach this implementation myself. There may very well be some good open source implementations out there.
GridViewController : UIViewController
This is the top most view controller and has a UIScrollView containing 1 or more pages of GridView objects. This view controller would communicate with a dataSource that provides 0..N objects to display on the individual grid views.
GridView : UIView
Each grid view would be a custom UIViewSubclass that knows how to layout 0 to N objects as dictated by the data provided by the GridViewController dataSource. Each icon in the grid would be an appropriate UIView subclass, maybe UIButton or UIImageView or maybe custom depending on what it needs to look and act like.
More behavior would be added as needed to drag icons around, create new pages, persist state in the data model, etc etc.

UITableViewCell custom reorder control

Is there any way to change the image of the reorder control that is displayed when the UITableView is in edit mode? I have a UIImage that I’d like to display instead of the usual grey bars.
Do I have to subclass UITableViewCell to accomplish this?
I guess you're a long way past this by now, but this has come up in a new question.
See my answer here:
Change default icon for moving cells in UITableView
I recently ran across the need to change the image for the reorder control, because I subclassed UITableViewCell to provide my own custom table cell. As part of this effort, I changed the background of the cell to something other than the default color.
Everything works correctly, but when I put the UITableView into editing mode, the reorder control would appear, with a white background - instead of the background color I was using for the cell. This didn't look good, and I wanted the background to match.
During the course of various versions of iOS, the hierarchy of views in a UITableViewCell has changed. I've taken an approach that will traverse the entire set of views until it finds the UITableViewCellReorderControl private class. I believe this will work for iOS 5 and all subsequent iOS versions at the time of this answer. Please note that while the UITableViewCellReorderControl class itself is private, I am not using any private API's to find it.
First, here's the code to scan for the reorder control; I'm assuming that the text "Reorder" will be in the class name - which Apple could change in the future:
-(UIView *) findReorderView:(UIView *) view
{
UIView *reorderView = nil;
for (UIView *subview in view.subviews)
{
if ([[[subview class] description] rangeOfString:#"Reorder"].location != NSNotFound)
{
reorderView = subview;
break;
}
else
{
reorderView = [self findReorderView:subview];
if (reorderView != nil)
{
break;
}
}
}
return reorderView;
}
In your custom UITableViewCell subclass, you will override -(void) setEditing:animated: and find the reorder control here. If you try to find this control when the table is not in editing mode, the reorder control will not be in the view hierarchy for the cell:
-(void) setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
if (editing)
{
// find the reorder view here
// place the previous method either directly in your
// subclassed UITableViewCell, or in a category
// defined on UIView
UIView *reorderView = [self findReorderView:self];
if (reorderView)
{
// here, I am changing the background color to match my custom cell
// you may not want or need to do this
reorderView.backgroundColor = self.contentView.backgroundColor;
// now scan the reorder control's subviews for the reorder image
for (UIView *sv in reorderView.subviews)
{
if ([sv isKindOfClass:[UIImageView class]])
{
// and replace the image with one that you want
((UIImageView *)sv).image = [UIImage imageNamed:#"yourImage.png"];
// it may be necessary to properly size the image's frame
// for your new image - in my experience, this was necessary
// the upper left position of the UIImageView's frame
// does not seem to matter - the parent reorder control
// will center it properly for you
sv.frame = CGRectMake(0, 0, 48.0, 48.0);
}
}
}
}
}
Your mileage may vary; I hope this works for you.
Here is my Swift solution based on Rick Morgan's answer:
func adjustSize() {
// we're trying to leverage the existing reordering controls, however that means the table must be kept in editing mode,
// which shrinks the content area to less than full width to make room for editing controls
let cellBounds = bounds
let contentFrame = contentView.convert(contentView.bounds, to: self)
let leftPadding = contentFrame.minX - cellBounds.minX
let rightPadding = cellBounds.maxX - contentFrame.maxX
// adjust actual content so that it still covers the full length of the cell
contentLeadingEdge.constant = -leftPadding
// this should pull our custom reorder button in line with the system button
contentTrailingEdge.constant = -rightPadding
// make sure we can still see and interact with the content that overhangs
contentView.clipsToBounds = false
// recursive search of the view tree for a reorder control
func findReorderControl(_ view: UIView) -> UIView? {
// this is depending on a private API, retest on every new iPad OS version
if String(describing: type(of: view)).contains("Reorder") {
return view
}
for subview in view.subviews {
if let v = findReorderControl(subview) {
return v
}
}
return nil
}
// hunt down the system reorder button and make it invisible but still operable
findReorderControl(self)?.alpha = 0.05 // don't go too close to alpha 0, or it will be considered hidden
}
This worked pretty well. contentLeadingEdge and contentTrailingEdge are layout constraints I set up in Interface Builder between the contentView and the actual content. My code calls this adjustSize method from the tableView(_:, willDisplay:, forRowAt:) delegate method.
Ultimately, however, I went with Clifton's suggestion of just covering the reorder control. I added a UIImageView directly to the cell (not contentView) in awakeFromNib, positioned it, and when adjustSize is called I simply bring the image view to the front, and it covers the reorder control without having to depend on any private APIs.
I put a little work into this recently, but came up short. I tried setting my own editingAccesoryView but couldn't get the reorder control to change. Odd.
My guess is that it has something to do with the following comment in the UITableviewCell docs re: showsReorderControl:
If the value is YES , the reordering
control temporarily replaces any
accessory view.
In other words, the editingAccessoryView is being replaced by the reordering control view, which might be why we cannot override the reordering control. Hoping someone can find a workaround.
You set the cell's editingAccessoryView property to an image view containing the image you want.
As an aside, I would caution you to be careful when doing this. When you substitute a custom graphic for a system standard such as the reorder graphic, you run a serious risk of confusing the user. The standard UI grammar has told them to expect the standard graphic when reordering and they may not understand the significance of your custom graphic.
Maybe we're all overthinking this. :)
Just put a custom UIImageView over the top of the default move accessory so it covers it up. Done.

Setting up multiple UIImageView instances

I would like to create a 4 x 6 grid of UIImageViews that each contain a slightly different image. I would also like to be able to randomly select one of the instances and change it's image.
My question is what's the best way to set up the UIImageViews in a grid formation, perform a few actions between each setup, and randomly pick 1 of the 24 instances once setup is complete. Optimally, I wouldn't have to set up each one by one.
Thanks in advance.
There are different approaches you can take, depending on whether or not you want to use Interface Builder to layout your grid.
One option is to layout your 24 UIImageViews as subviews of a common parent view within IB. On the View Attributes tab you can set a "Tag" number from 1 to 24 to differentiate your UIImageViews. Then in your code you can use [parentView viewWithTag:tagNumber] to access each UIImageView.
If you prefer to do things more programmatically, you could create each of your UIImageViews in a loop in the loadView method of your UIViewController subclass. You could maintain an array (or an array of arrays corresponding to rows and columns) as a property of your controller, and store a reference to each of these image views as you create them. For each UIImageView you create, set its imageView.frame property to define its position, then call [view addSubview:imageView] to add it to the parent view.
I would do it programmatically for your sake.
NSArray *myViews = //I assume you can create an array of views
for (int i=0; i<rows; ++i) {
for (int j=0; j<columns; ++j) {
UIImageView *thisImageView = [myViews objectAtIndex:(i*columns+j)];
CGSize size = thisImageView.image.size;
[thisImageView setFrame:CGRectMake(j*size.width, i*size.height, size.width, size.height)];
[self.view addSubview:thisImageView];
}
}
//Later to pick one randomly
UIImageView *myRandomView = [myViews objectAtIndex:(arc4random()%[myViews count])];
[myRandomView setImage:myNewImage];

How do I push grouped tables down in the view on the Iphone?

Below shows the default position when you add a grouped table to a view? How do I push the entire grouped table down in the view?
(source: pessoal.org)
You can assign a transparent view with a fixed height to the tableHeaderView property of the tableView. This will push the table contents down by the height of the transparent view.
You can do this from your UITableViewController's viewDidLoad:
// force the table down 70 pixels
CGRect headerFrame = self.tableView.bounds;
headerFrame.size.height = 70;
UIView *header = [[UIView alloc] initWithFrame: headerFrame];
header.backgroundColor = [UIColor clearColor];
self.tableView.tableViewHeader = header;
[header release];
Look at the delagate to the UITableView.
You will find a property 'heightForHeaderInSection'.
For section 0 just make the header larger (default is 0) it will push the table down the view.
If you are moving the table down, you undoubtedly wish to use the space you gain to add UI elements.
At that point, consider building the page in IB. You can resize the table view to be where you like and put the UI elements above the table. You can use a UIViewController to manage the page and add the UITableViewDelegate/Datasource protocol methods so that you can wire the UITableView back to your view controller as a delegate... then you can also wire the other UI elements to the same view controller.
The simplest way to do it is probably just to modify the frame for the tableview. You'll need to get a reference to the tableview in your controller either through an IBOutlet or by finding the view in the view hierarchy OR you can change the frame in Interface Builder.
In code something like:
tableView.frame = CGRectMake(0.0, 200.0, 320.0, 280.0);
Would position the tableview down the screen and limit its height - the dimensions you use will be dependent on whether you had a tab bar on the view and things like that.
In interface build just select the tableview, then choose the Size inspector (the inspector tab with the ruler icon) and set the height and y offset to shift it down the view.