I'm starting to develop a simple application for iOS, and this application is a simple gallery of some photo (taken from a website).
The first problem I encountered is how to create the view for the gallery.
The view should be something like this (or the Photo App):
however doing a view this way is problematic, first because it uses fixed dimension, and I think is a bit difficult to implement (for me).
The other way is to use a custom cell within a tableview, like this:
but it is still using fixed dimension.
What's the best way to create a gallery, without using any third part lib (like Three20)?
Thanks for any reply :)
PS. I think that using fixed dimension is bad because of the new iphone 4 (with a different resolution), am I right?
You should check out AQGridView which does exactly what you are trying to achieve. Even if you want to write your own custom code, have a look at the AQGridView source as more than likely you will need to use a UIScrollView as a base.
In case that you want to use third party classes, the next tutorials can be mixed, they worked for me.
Here's a good grid view:
custom image picker like uiimagepicker
And if you want to load them asynchronously, use this:
image lazy loading
Both tutorials are very well described and have source code.
The difference in resolution shouldn't be an issue since iOS, if I recall correctly, scales up UI components and images to the right resolution if it detects that it has a retina display. An aside; remember to start making hi/lo-res versions of your graphics if you intend to support both screen sizes without degradation of quality.
As long as you design things in terms of points instead of pixels (which is the way it's done in XCode 4), iOS will be able to handle scaling for you transparently. On a small screen one point will be one pixel, whereas it will be two pixels on a retina display. This allows it to render things with a crisper look on retina displays. Source
I know this question is old, but I didn't see anyone addressing the issue of fixed widths, so I thought I'd contribute for once.
If you don't want to use a third party library, you should do this in UITableView rows. Because of the way UITableView caches cells, it's relatively lightweight in memory. Certainly more so than a possibly very large UIView inside a UIScrollView. I've done it both ways, and I was much happier with the UITableView.
That said, next time I need to do this? I plan to use AQGridView.
Um, since ios6 came out, the right way to do this is with Collection Views:
Apple Docs on CollectionViews
Also, see the two WWDC 2012 sessions on them:
Introduction to Collection Views
Advanced Collection Views
Sadly, Apple did not include a simple gallery or coverflow layout, but it's pretty easy to make one.
I wrote a tutorial on building a media gallery using a UICollectionView. It populates from the user's photo library. I think it will work perfectly for what you are trying to do.
iPhone Programming Tutorial: Creating An Image Gallery Like Over – Part 1
Hope that helps. Cheers!
I did something very similar to this in a project of my own. I just show some parts of the code here, but if you want to view the full code you can view it on GitHub GitHub Repo
First I made a custom Collection View cell with an ImageView
in CustomCollectionCell.h
#import <UIKit/UIKit.h>
#interface CustomCollectionCell : UICollectionViewCell
#property (nonatomic , retain) UIImageView *imageView;
#end
in CustomCollectionCell.m
#import "CustomCollectionCell.h"
#implementation CustomCollectionCell
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupImageView];
}
return self;
}
#pragma mark - Create Subviews
- (void)setupImageView {
self.imageView = [[UIImageView alloc] initWithFrame:self.bounds];
self.imageView.autoresizingMask = UIViewAutoresizingNone;//UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:self.imageView];
}
#end
Then in the view where you want to have the thumbnails you set up the CollectionView
in ThumbNailViewController.m (snippet)
UICollectionView *collectionViewThumbnails;
in ThumbNailViewController.m (snippet)
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
collectionViewThumbnails=[[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - 50) collectionViewLayout:layout];
if (collectionViewThumbnails && layout)
{
[collectionViewThumbnails setDataSource:self];
[collectionViewThumbnails setDelegate:self];
[collectionViewThumbnails registerClass:[CustomCollectionCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[collectionViewThumbnails setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:collectionViewThumbnails];
}
Then you have the required methods for the collection views. Here you can set up what you
//Number of items in the collectionview
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [galleryData count];
}
//Set up what each cell in the collectionview will look like
//Here is where you add the thumbnails and the on define what happens when the cell is clicked
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//initialize custom cell for the collectionview
CustomCollectionCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
[cell.imageView setClipsToBounds:YES];
cell.imageView.contentMode = UIViewContentModeScaleAspectFill;
//format url to load image from
NSString *url = [NSString stringWithFormat:#"http://andrecphoto.weebly.com/uploads/6/5/5/1/6551078/%#",galleryData[indexPath.item]];
//load thumbnail
[cell.imageView setImageWithURL:[NSURL URLWithString:url]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
//Sets up taprecognizer for each cell. (onlcick)
UITapGestureRecognizer *tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[cell addGestureRecognizer:tap];
//sets cell's background color to black
cell.backgroundColor=[UIColor blackColor];
return cell;
}
//Sets size of cells in the collectionview
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 100);
}
//Sets what happens when a cell in the collectionview is selected (onlclicklistener)
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
//gets the cell thats was clicked
CustomCollectionCell *cell_test = (CustomCollectionCell *)recognizer.view;
//gets indexpath of the cell
NSIndexPath *indexPath = [collectionViewThumbnails indexPathForCell:cell_test];
if (isConnectedGal)
{
//sets the image that will be displayed in the photo browser
[photoGallery setInitialPageIndex:indexPath.row];
//pushed photobrowser
[self.navigationController pushViewController:photoGallery animated:YES];
}
}
Hopefully that answers your question.
Here is a very good library called FGallery for iOS
-Supports auto-rotation
-thumbnail View
-zoom
-delete
Related
i hope you will find a solution for my problem, cause i don't have any ideas anymore.
I have a tableview, which has several cells. some cells have another view as subview on their contentView.
This additional view has 2 subviews: 1 UIImageView and 1 UILabel.
Now when i tap an UIButton the UIImageView should be hidden/removed and the UILabel changes it's textColor to white(black before).
The UILabel changes it's textColor but the UIImageView is still visible, even after removing the UIImageView from it's superview.
The Code looks like this.
_adsc_dot_view is the UIImageView
_adsc_text_label is the UILabel
- (void)mc_set_selected:(BOOL)selected {
if (selected) {
_adsc_dot_view.hidden = YES;
_adsc_text_label.textColor = [UIColor whiteColor];
}
else {
_adsc_dot_view.hidden = NO;
_adsc_text_label.textColor = [UIColor blackColor];
}
}
Some check you might find useful for this issue:
1) make sure you create once your UIImageView which referenced as _adsc_dot_view
2) do a debug, mark mc_set_selected with a breakpoint and in the log check the view hierarchy, whether you have the needed number of UIImageView and not more
po [[UIWindow keyWindow] recursiveDescription]
or check this advanced SO answer: I need to inspect the view hierarchy on an iPhone program
3) if you use Interface Builder make sure you have proper type (and not UIImage) and proper reference
You are using UITableView and you add UIImageView and UILabel as a subview in UITableViewCell. So, I think you should reload UITabeView using [self.tableView reloadData]; or [YourTableName reloadData]; after your hide and show UIImageView method. Otherwise you should hide and show UIImageView using UIImageView tag or using UITableViewCell index path.
is the target device on iOS 7? If yes then do try to layoutsubviews of the cell. I had a similar issue where the cell wasn't refreshing on ios 7.
Just reload table view cell after Remove/Hide ImageView.
I want to implement a wheel like infinte scrolling Rating tool like the below image.
No i had taken an scrollview and set the orange image in scrollview
- (void)viewWillAppear:(BOOL)animated
{
UIImageView * headerImage = [[UIImageView alloc] init];
headerImage.image = [UIImage imageNamed:#"img_2.png"];
SCrl_Wheel.backgroundColor = [UIColor colorWithPatternImage:headerImage.image];
[SCrl_Wheel setContentSize:CGSizeMake(500,0)];
[SCrl_Wheel setShowsHorizontalScrollIndicator:NO];
Lbl_Rate.text=#"0";
[super viewWillAppear:animated];
}
Apple has an example project featuring infinite scrolling it's called StreetScroller, which demonstrates how a UIScrollView subclass can scroll infinitely in the horizontal direction.
There is also an UIScrollView subclass on Github called BAGPagingScrollView, which is paging & infinite, but it has a few bugs you have to fix on your own, because it's not under active development (especially the goToPage: method leads to problems).
I hope this helps you.
Also check this link for easy implementation they also have a sample code attached :)
http://mobiledevelopertips.com/user-interface/creating-circular-and-infinite-uiscrollviews.html
I'm currently working on an iPhone app that's doing some strange things with a UIScrollView inside a UITableView. This is my first foray into iPhone dev, so I'm sure it's something silly I'm missing.
In each UITableViewCell I am putting in a basic UITableViewCell. In that UITableViewCell is a Label and a UIScrollView.
The label and scrollview is setup and working properly, but when it first displays it is offset about 30 pixels down on the y axis than it should be, or is positioned by the XIB/NIB. I am not moving it around manually. The label shows up in the right spot. at 0,0. The UIScrollView should be showing up at 0,22 but is showing up closer to 0,40.
When I swipe to scroll the containing UITableView, then all the UIScrollViews will show up in the right spot assuming that when the UITableView scrolled that UITableViewCell went offscreen.
Here is the code for the UITableView.cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"GalleryRowCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
[cell.layer setMasksToBounds:TRUE];
[cell.layer setCornerRadius:10.0];
Contagion *c = (Contagion *)[self.dataSet objectAtIndex:indexPath.row];
GalleryRowViewController *subView = [[GalleryRowViewController alloc] initWithContagion:c];
[cell.contentView addSubview:subView.view];
subView.contagionName.text = c.name;
subView.contagion = c;
return cell;
}
Here is the code for my GalleryRowViewController.viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
self.imageScroll.delegate = self;
[self.imageScroll setBackgroundColor:[UIColor blackColor]];
[self.imageScroll setCanCancelContentTouches:NO];
self.imageScroll.indicatorStyle = UIScrollViewIndicatorStyleWhite;
self.imageScroll.clipsToBounds = NO;
self.imageScroll.scrollEnabled = YES;
self.imageScroll.pagingEnabled = NO;
NSInteger x = 0;
CGFloat xPos = 0;
for (x=0;x<=10;x++) {
UIImage *image = [UIImage imageNamed:#"57-icon.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[imageView setBackgroundColor:[UIColor yellowColor]];
CGRect rect = imageView.frame;
rect.size.height = 70;
rect.size.width = image.size.width;
rect.origin.x = xPos;
rect.origin.y = 5;
imageView.frame = rect;
[self.imageScroll addSubview:imageView];
xPos += imageView.frame.size.width+5;
}
[self.imageScroll setContentSize:CGSizeMake(xPos, [self.imageScroll bounds].size.height)];
}
--- EDIT FOR IMAGES ---
After App Loads: http://img809.imageshack.us/img809/4576/screenshot20110927at427.png
After Scrolling the rows offscreen and back: http://img690.imageshack.us/img690/9461/screenshot20110927at428.png
Well, as my previous response was at too low a level, let me take another shot at it.
First, I just noticed the core problem that you're using a viewcontroller for each cell. To quote Apple, " "A single view controller typically manages the views associated with a single screen’s worth of content." That would also get rid of your XIB (just manually configuring your scrollview), which I bet will get rid of your problem.
To proceed, your main choice is whether to create a ContagionTableViewCell class or not as suggested by Scott.
If so, following the Elements example, create a subclass of UITableViewCell ContagionTableViewCell with properties of a scrollView, a labelview and a contagion. Like they use a custom setter for the element, use one for the contagion, so that whenever it is assigned, it also updates the cells label (and associated pictures).
Move your imageScroll code from GalleryRowViewController.viewDidLoad into the ContagionTableViewCell init code. Put the image code into a new routine, which will be called from the contagion setter.
If NOT, then move the GalleryRowView Controller code into your UITableView. I suggest you take a look at cellForRowAtIndexPath in Apple's tableViewSuite, the fourth example on subviews. In particular, it shows this pattern of separating the creation of a cell (when you need a brand new one) vs configuring the cell (when reusing it). As you have 10 imageViews inside your scrollView, you'll have to decide whether to delete all those (and/or the scrollview), or just reach inside and update their images when a cell is reused.
Can you post a screenshot. Its a bit hard to visualize what you are describing. I'm not sure how you are computing y origin to be 22.
As a side note I believe its cleaner to do this by creatint your own TableViewCell subclass and use that instead of the default UITableViewCell. There is an example called Elements which shows how to do this properly: http://developer.apple.com/library/ios/#samplecode/TheElements/Introduction/Intro.html
Well, I don't know it's the cause of your problem, but you've definitely got an issue. Note that every time you are asked for a cell, you're adding the galleryRow subview. When a cell goes off-screen, it's put on the reusableCell queue. Then you're asked for another cell; you get it from the queue, it still has the old galleryRow subview, and now you add another one; so that's not good. You should either reuse or delete the old one.
Finally, why are you using UITableViewCellStyleSubtitle, and then not using any of the default fields in that UITableView?
How can I set the background color of a cell in UITableView?
Thanks.
I know this is an old post, but I am sure some people are still looking for help. You can use this to set the background color of an individiual cell, which works at first:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
[cell setBackgroundColor:[UIColor lightGrayColor]];
However, once you start scrolling, the iphone will reuse cells, which jumbles different background colors (if you are trying to alternate them). You need to invoke the tableView:willDisplayCell:forRowAtIndexPath. This way, the background color gets set before the reuse identfier is loaded. You can do it like this:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = ([indexPath row]%2)?[UIColor lightGrayColor]:[UIColor whiteColor];
}
The last line is just a condensed if/else statement. Good luck!
Update
Apparently the existing UITableViewCell framework makes it very difficult to change the background color of a cell and have it work well through all its state changes (editing mode, etc.).
A solution has been posted at this SO question, and it's being billed on several forums as "the only solution approved by Apple engineers." It involves subclassing UITableViewCell and adding a custom view for the subclassed cell's backgroundView property.
Original post - this solution doesn't work fully, but may still be useful in some situations
If you already have the UITableViewCell object, just alter its contentView's backgroundColor property.
If you need to create UITableViewCells with a custom background color, the process is a bit longer. First, you'll want to create a data source for your UITableView - this can be any object that implements the UITableViewDataSource protocol.
In that object, you need to implement the tableView:cellForRowAtIndexPath: method, which returns a UITableViewCell when given an NSIndexPath for the location of the cell within the table. When you create that cell, you'll want to change the backgroundColor property of its contentView.
Don't forget to set the dataSource property of the UITableView to your data source object.
For more info, you can read these API docs:
UITableViewDataSource - tableView:cellForRowAtIndexPath
UITableViewCell - contentView
UIView - backgroundColor
UITableView - dataSource
Note that registration as an Apple developer is required for all three of these links.
The backgroundView is all the way on the bottom. It's the one that shows the rounded corners and the edges. What you want is the contentView which is on top of the backgroundView. It covers the usually white area of the cell.
The version I wrote will work in iPhone 3.0 or higher and fallback to a white background otherwise.
In your viewDidLoad method of the UITableViewController we add the following:
self.view.backgroundColor=[UIColor clearColor];
// Also consider adding this line below:
//self.tableView.separatorColor=[UIColor clearColor];
When you are creating your cells (in my code this is my tableView:cellForRowAtIndexPath:) add the following code:
cell.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:#"code_bg.png"]];
float version = [[[UIDevice currentDevice] systemVersion] floatValue];
if (version >= 3.0)
{
[[cell textLabel] setBackgroundColor:[UIColor clearColor]];
}
This works perfectly for me:
NSEnumerator *enumerator = [cell.subviews objectEnumerator];
id anObject;
while (anObject = [enumerator nextObject]) {
if( [anObject isKindOfClass: [ UIView class] ] )
((UIView*)anObject).backgroundColor = [UIColor lightGrayColor];
}
You may set the backgroundColor of the backgroundView. If the backgroundView does not exists, you can create one for it.
if (!tableView.backgroundView) {
tableView.backgroundView = [[UIView alloc] initWithFrame:tableView.bounds];
}
tableView.backgroundView.backgroundColor = [UIColor theMostFancyColorInTheUniverse];
If you want to set the background of a cell to an image then use this code:
// Assign our own background image for the cell
UIImage *background = [UIImage imageNamed:#"image.png"];
UIImageView *cellBackgroundView = [[UIImageView alloc] initWithImage:background];
cellBackgroundView.image = background;
cell.backgroundView = cellBackgroundView;
I have a table view with an alphabetical index and am using the side alphabet to get through the list quickly. For those not familiar, that uses this:
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
My problem is that my application has just been skinned black. And so now it's hard to see the alphabet letters on the side.
I can't figure out how to change the color of the alphabet. I'd like it to be 'white' if at all possible.
if your minimum iOS version is newer than 6.0, you can use sectionIndexColor property of UITableView.
The color to use for the table view’s index text.
#property(nonatomic, retain) UIColor *sectionIndexColor
Discussion:
Table views can display an index along the side of the view, making it
easier for users to navigate the contents of the table quickly. This
property specifies the color to use for text displayed in this region.
Update date 2014.1.13
I find an open source third party library:GDIIndexBar to help custom the index appearance.
From what I can tell unfortunately it is not possible to customize the color of the text displayed in the index, the closest I've been able to come is being able to modify the background color and the font of the index.
There is some code in the iPhone Developers cookbook by Erica Sadun which shows how to access the UITableViewIndex view (an undocumented class). You can find the reference to it on page 175 of the book if you have it. Which gives access to the background color and the font. You can see an unofficial document related to this class here.
WARNING This is undocumented use of an undocumented class so you need to be cautious about using it.
Here is a code snippet from the cookbook with minor modifications:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
for(UIView *view in [tv subviews])
{
if([[[view class] description] isEqualToString:#"UITableViewIndex"])
{
[view setBackgroundColor:[UIColor whiteColor]];
[view setFont:[UIFont systemFontOfSize:14]];
}
}
//rest of cellForRow handling...
}
This illustrates how you can access and the UITableViewIndex view and modify it in some aspects. It looks like the view doesn't have any subviews so it is likely doing some custom drawing with the array of index titles.
It's not perfect but hopefully it helps a little.
Paul
This can be easily changed in the interface builder for the UITableView - No need to use undocumented classes?
See screenshot below, as you can see the font colour and the background colour can be changed too. Job's a good'n!
For iOS7 or Higher:
self.tableView.sectionIndexColor = [UIColor whiteColor];
self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
I was having the same problem and just found out a way of doing this, though this is using undocumented classes and methods so think one extra time before trying to upload it to the App Store.
I should say that i've only tried this with iOS5 so I don't know if it will work for previous versions.
I borrowed and modified the Erica Saunders cookbook example so that it now changes the text color to red:
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
for(UIView *view in [tv subviews])
{
if([[[view class] description] isEqualToString:#"UITableViewIndex"])
{
[view performSelector:#selector(setIndexColor:) withObject:[UIColor redColor]];
}
}
//rest of cellForRow handling...
}
We have successfully used the following code:
for(UIView *view in [tableView subviews]) {
if([view respondsToSelector:#selector(setIndexColor:)]) {
[view performSelector:#selector(setIndexColor:) withObject:[UIColor whiteColor]];
}
}
which works fine - it's very similar to Mooglas answer - but refrains from using the word "UITableViewIndex".
You can set the tint color for the tableView.
[[UITableView appearance] setTintColor:[UIColor purpleColor]];
Swift 5:
tableView.sectionIndexColor = .red
tableView.sectionIndexBackgroundColor = .clear
There is a way to change the color of the index Alphabet.
In your header file, declare your UITableView as a property:
#property (weak, nonatomic) IBOutlet UITableView *mainTable;
Then in your implementation file's viewDidAppear, use the following line:
//Change the color of the UITableView index color
_mainTable.sectionIndexColor = [UIColor blackColor];
Here's the best solution I've found to adjust the background colour of the index bar on the side. It works in iOS7 and probably iOS6.
Add this to your viewDidLoad
if ([_tableView respondsToSelector:#selector(setSectionIndexColor:)]) {
_tableView.sectionIndexBackgroundColor = [UIColor clearColor];
_tableView.sectionIndexTrackingBackgroundColor = [UIColor whiteColor];
}
The first one is the default colour, the second is the background colour when you are scrolling.
Make a mutable array to contain the alternate title label
In
-(NSArray * )sectionIndexTitlesForTableView:(UITableView * )tableView
return an array of #" " where the number of spaces between the quotes determines the width of the hi-lighted scroller.
Have "sectionIndexTitlesForTableView" call an update label function.
In that function remove all the labels in the array you created earlier from their superviews Then create and add however many labels are needed. Then add them to the table's superview.
These are the lines required to place the labels in the right place.
rect.origin.x = table.frame.origin.x+table.frame.size.width-rect.size.width-2;
rect.origin.y = 5+table.frame.origin.y+counter *(280-rect.size.height-([customIndexLabels count]-1))/([customIndexLabels count]-1);
if ([customIndexLabels lastObject]==thisLabel)
{
rect.origin.y-=10;
}
Hope that helps. It's not perfect I just don't care enough to fix it myself
The main problem is that the spacing of the last label is not uniform.
Swift edition for undocumented font change:
extension NSObject {
class func objectClassName() -> String {
let classLongName = reflect(self.self).summary;
let tokens = classLongName.componentsSeparatedByString(".")
if let typeName = tokens.last {
return typeName
}
return NSStringFromClass(self.dynamicType)
}
}
func changeSectionIndexFont(tableView: UITableView) -> Void {
let realSubviews = tableView.subviews as! [UIView]
for subview in realSubviews {
if subview.dynamicType.objectClassName() == "UITableViewIndex" {
subview.setValue(UIFont(name: "OpenSans", size: 10), forKey: "font")
}
}
}