My code parts in two:
The first is the "cellForRowAtIndexPath" method for my table view. In this table view i'm supposed to show 3 buttons in each cell and each button is a different image. Images are in an NSMutableArray call "photosArray". It looks like this.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (photosArray.count > 0) {
for (int i = 0; i < 3; i++) {
if (photosArray.count > photoCounter) {
//position the UiButtons in the scrollView
CGRect frame = CGRectMake((i*100) + 30, 5, 60, 60);
//Create the UIbuttons
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTag:i];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
button.frame = frame;
button.layer.borderWidth = 2;
button.layer.cornerRadius = 5;
button.clipsToBounds = YES;
//Add images to the button
NSLog(#"PhotosArray count is: %d",photosArray.count);
if ([[photosArray objectAtIndex:0] isKindOfClass:[UIImage class]]) {
NSLog(#"UIImage class true");
}
if ([[photosArray objectAtIndex:0] isMemberOfClass:[UIImage class]]) {
NSLog(#"UIImage class true");
}
UIImage *btnImg = [self.photosArray objectAtIndex:photoCounter];
//UIImage *btnImg2 = [UIImage imageNamed:#"GameOver"];
photoCounter++;
[button setBackgroundImage:btnImg forState:UIControlStateNormal];
[cell.contentView addSubview:button];
}
}
}else{
UILabel *noImages = [[UILabel alloc] initWithFrame:CGRectMake(0, 25, 320, 20)];
noImages.text = #"No images";
noImages.textAlignment = NSTextAlignmentCenter;
[cell.contentView addSubview:noImages];
}
return cell;
}
The second part is where I load my pictures into "photosArray". I am using WSAssetPicker to load multiple photos from my asset library.
Here is the code:
- (void)assetPickerController:(WSAssetPickerController *)sender didFinishPickingMediaWithAssets:(NSArray *)assets
{
// Dismiss the WSAssetPickerController.
[self dismissViewControllerAnimated:YES completion:^{
arep = [[ALAssetRepresentation alloc] init];
for (ALAsset *asset in assets) {
UIImage *imageA = [[UIImage alloc] initWithCGImage:asset.defaultRepresentation.fullScreenImage];
[self.photosArray addObject:imageA];
}
NSLog(#"%d",photosArray.count);
photoCounter = 0;
[self.tableView reloadData];
}];
}
And now for the issue, the buttons that are created have no image in it. I only get a transparent button with a border and rounded corners.
Why is that?
It was recently brought to my attention that I omitted an important piece from the README (which is now updated).
It is necessary to hold a strong reference of WSAssetPickerController if you are accessing ALAsset objects in the dismissViewControllerAnimated:completion: completion block.
If you do not hold a strong reference to the picker controller before calling dismissViewControllerAnimated:completion: the picker controller will be released before the completion block is executed resulting in the ALAssetsLibrary (used internally in the WSAssetPicker code) from being released before you try to access the ALAssets in the assets array passed in the assetPickerController:didFinishPickingMediaWithAssets: delegate method.
If ALAssetsLibrary gets released, the ALAssets owned by the ALAssetsLibrary will expire and calls to asset.defaultRepresentation.fullScreenImage will return null.
The following will preserve the ALAssetsLibrary while dismissing the picker controller's view:
- (void)assetPickerController:(WSAssetPickerController *)sender didFinishPickingMediaWithAssets:(NSArray *)assets
{
// Hang on to the picker to avoid ALAssetsLibrary from being released.
self.picker = sender;
__block id weakSelf = self;
// Note: Instead of `id` you could specify the class of `self` order to access properties with dot notation.
// Dismiss the WSAssetPickerController.
[self dismissViewControllerAnimated:YES completion:^{
// Do something with the assets here.
// Release the picker.
[weakSelf setPicker:nil];
}];
}
An alternative would be to process the array of ALAssets before calling dismissViewControllerAnimated:completion:, but that could cause the picker controller's dismissal to delay resulting in a poor user experience.
Related
Currently, I am developing an app in which I have fetch Facebook album photo & display it as
gallery view asynchronously using Table view & put images on button of table view cell using below code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"particulars..:%d",[particular count]);
int count=self.particular.count%3;
if(count==0)
{
return self.particular.count/3;
}
else
{
return (self.particular.count/3) +1;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell1";
CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"CustomTableViewCell" owner:self options:nil];
cell = customcell;
}
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSString *buttonurl=[self.particular objectAtIndex:((indexPath.row)*3)+0];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl]];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:data];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor=[UIColor clearColor];
[cell.first setBackgroundImage:image forState:UIControlStateNormal] ;
[cell.first addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.first setContentMode:UIViewContentModeCenter] ;
cell.first.layer.cornerRadius = 10.0;
cell.first.layer.borderColor = [[UIColor grayColor]CGColor];
cell.first.layer.borderWidth = 1.0f;
cell.first.backgroundColor=[UIColor clearColor];
cell.first.tag = ((indexPath.row)*3)+1 ;
[spinner stopAnimating];
});
[data release];
});
if(((indexPath.row)*3)+3<[particular count])
{
UIActivityIndicatorView *spinner2 = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
UIActivityIndicatorView *spinner3 = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
//spinner2.backgroundColor=[UIColor blackColor];
CGRect frame= cell.second.frame;
spinner2.frame=frame;
//spinner2.frame=CGRectMake(112, y, 106, 106);
spinner2.hidesWhenStopped = YES;
[cell.second addSubview:spinner2];
[spinner2 startAnimating];
CGRect frame2= cell.third.frame;
spinner3.frame=frame2;
spinner3.hidesWhenStopped = YES;
[cell.third addSubview:spinner3];
[spinner3 startAnimating];
dispatch_async(dispatch_get_global_queue(0,0), ^
{
NSString *buttonurl=[self.particular objectAtIndex:((indexPath.row)*3)+1];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl]];
NSString *buttonurl1=[self.particular objectAtIndex:((indexPath.row)*3)+2];
NSData * data1 = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl1]];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^
{
UIImage *image = [UIImage imageWithData:data];
UIImage *image1 = [UIImage imageWithData:data1];
[cell.second setBackgroundImage:image forState:UIControlStateNormal] ;
[cell.second addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.second setContentMode:UIViewContentModeCenter] ;
cell.second.layer.cornerRadius = 10.0;
cell.second.layer.borderColor = [[UIColor grayColor]CGColor];
cell.second.layer.borderWidth = 1.0f;
cell.second.backgroundColor=[UIColor clearColor];
cell.second.tag = ((indexPath.row)*3)+2 ;
NSLog(#"cell.second.tag:%d",cell.second.tag);
[cell.third setBackgroundImage:image1 forState:UIControlStateNormal] ;
[cell.third addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.third setContentMode:UIViewContentModeCenter] ;
cell.third.layer.cornerRadius = 10.0;
cell.third.layer.borderColor = [[UIColor grayColor]CGColor];
cell.third.layer.borderWidth = 1.0f;
cell.third.backgroundColor=[UIColor clearColor];
cell.third.tag = ((indexPath.row)*3)+3 ;
NSLog(#"cell.third.tag:%d",cell.third.tag);
[spinner2 stopAnimating];
[spinner3 stopAnimating];
});
[data release];
});
}
else if(((indexPath.row)*3)+2<[particular count])
{
UIActivityIndicatorView *spinner2 = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGRect frame1 = CGRectMake(120, y, 106, 107);
spinner2.frame=frame1;
spinner2.hidesWhenStopped = YES;
[cell.second addSubview:spinner2];
[spinner2 startAnimating];
dispatch_async(dispatch_get_global_queue(0,0), ^
{
NSString *buttonurl=[self.particular objectAtIndex:((indexPath.row)*3)+1];
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: buttonurl]];
if ( data == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^
{
UIImage *image = [UIImage imageWithData:data];
[cell.second setBackgroundImage:image forState:UIControlStateNormal] ;
[cell.second addTarget:self action:#selector(original:) forControlEvents:UIControlEventTouchUpInside];
[cell.second setContentMode:UIViewContentModeCenter] ;
cell.second.layer.cornerRadius = 10.0;
cell.second.layer.borderColor = [[UIColor grayColor]CGColor];
cell.second.layer.borderWidth = 1.0f;
cell.second.backgroundColor=[UIColor clearColor];
cell.second.tag = ((indexPath.row)*3)+2 ;
NSLog(#"cell.second.tag:%d",cell.second.tag);
[spinner2 stopAnimating];
});
[data release];
});
}
else
{
cell.second.hidden = YES;
cell.third.hidden = YES;
}
y=y+106;
return cell;
}
This code is working fine for me but the problem is that when images load into button contain by table view cell then if we scroll down then it slowly show images but after that when we scroll up to see previously load images then images disappear & it again load from starting & take times.So please tell where i am doing mistake in code or how can I solve this?
I'd suggest you to use this AsyncImageView. I've used it and it work wonders. To call this API:
ASyncImage *img_EventImag = alloc with frame;
NSURL *url = yourPhotoPath;
[img_EventImage loadImageFromURL:photoPath];
[self.view addSubView:img_EventImage]; // In your case you'll add in your TableViewCell.
It's same as using UIImageView. Easy and it does most of the things for you. AsyncImageView includes both a simple category on UIImageView for loading and displaying images asynchronously on iOS so that they do not lock up the UI, and a UIImageView subclass for more advanced features. AsyncImageView works with URLs so it can be used with either local or remote files.
Loaded/downloaded images are cached in memory and are automatically cleaned up in the event of a memory warning. The AsyncImageView operates independently of the UIImage cache, but by default any images located in the root of the application bundle will be stored in the UIImage cache instead, avoiding any duplication of cached images.
The library can also be used to load and cache images independently of a UIImageView as it provides direct access to the underlying loading and caching classes.
There are some custom libraries which do the job very well for you
AsynchImageView
SDWebImage
AFNetworking Image Extension (if you are using AF )
It is working the way it should do. When you scroll a table view is like if the cells that disappeared have been released and when you scroll back the cell are dequeued.
So, you should use a solution for caching the images so that they don't need to be loaded again, such as EGOImageView (here), AsyncImageView, SDWebImage etc.
Here is a solution with out using dispatch_async.If you are getting the URL from services than use this method NSObject where service is called
-(void)loadProfilePicWithURL:(NSString *)strUrl tagV:(NSInteger)tagV{
isProfilePicLoaded = NO;
//set media tag as indexPath.row
//call this method from cellForRowAtIndexpPath
//Pass the image URL --> strProfilePicURL
//Load the image in bg and set to imgProfilePic
//After loaded, send a notification with tag to table view to update the cell
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:strUrl]];
imgProfilePic=[UIImage imageWithData:data];
isProfilePicLoaded = YES;
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadTableViewCell" object:[NSNumber numberWithInteger:tagV]];
}
Call this method from cellForRowAtIndexPath
[self performSelectorInBackground:#selector(loadPic:) withObject:[NSNumber numberWithInteger:indexPath.row]];
implement
-(void)loadPic: (id )indexPath{
NSInteger conV=[indexPath integerValue];
NSObject *object=[Array objectAtIndex:conV];
[object loadProfilePicWithURL:object.url tagV:conV];
}
Add Observer for the notification in NSObject
-(void)reloadTableViewCell:(NSNotification *)note{
NSInteger mediaTag = [[note object] integerValue];
[self reloadCellImage:mediaTag];
}
Re-load the particular cell in the table.
-(void)reloadCellImage:(NSInteger)row{
NSObject *object = [self.receivedArray objectAtIndex:row];
NSIndexPath* rowToReload = [NSIndexPath indexPathForRow:row inSection:0];
customCell *cell = (customCell *)[self.tableView cellForRowAtIndexPath:rowToReload];
[cell.imgVw setImage:object.image];}
My app's UI requires grids of 9 images that are paginated.
To do this I'm creating several UITables inside a UIScrollView (with a UIPageControl):
My table is coming from a xib file that I register. Each table cell has 3 buttons in it.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
int numPages = ([self.images count] + 8) / 9;
NSLog(#"Page count: %i", numPages);
// Set pages
self.pageControl.numberOfPages = numPages;
for (int i = 0; i < numPages; 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 = [UIColor blackColor];
[self.scrollView addSubview:subview];
// Let's try and draw a table
UITableView *table = [[UITableView alloc] initWithFrame:frame style:UITableViewStylePlain];
table.delegate = self;
table.dataSource = self;
table.tag = 100 + i;
table.separatorColor = [UIColor clearColor];
[table setBackgroundColor:[UIColor blackColor]];
[table registerNib:[UINib nibWithNibName:#"Cell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"TestCell"];
[self.scrollView addSubview:table];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * numPages, self.scrollView.frame.size.height);
}
My problem is that the view loads slowly (5+ seconds). The images being loaded into the buttons are local and not large.
My cellForRowAtIndexPath looks like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TestCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// What table/page are we looking at?
// Check the tag
int page = tableView.tag - 100;
NSLog(#"We are on page/table: %i", page);
// Configure the cell
// Our cells have 3 button images
// So we'll loop and set each image
for (int i = 0; i < 3; i++) {
// From our images array, the item we want
// Will be the row * 3 + i
int imageIndex = (page * 9) + (indexPath.row * 3) + i;
NSLog(#"Image index is: %i", imageIndex);
// Button tags are 10-12 (or 10 + i)
UIButton *button = (UIButton *)[cell viewWithTag:(10 + i)];
[button addTarget:self action:#selector(poseSelected:) forControlEvents:UIControlEventTouchUpInside];
// We have to make sure we don't go out of the bounds of
// our images array (might not have /3 exactly)
if (imageIndex > [self.images count] - 1) {
// We have an extra button, let's hide it
button.hidden = YES;
} else {
// Get the image and file nameefrom our array
NSDictionary *imageDict = (NSDictionary *)[self.images objectAtIndex:imageIndex];
NSString *fileName = [imageDict objectForKey:#"file"];
// Make the thumb name
NSString *thumbName = [fileName stringByReplacingOccurrencesOfString:#".jpg"
withString:#"-THUMB.jpg"];
// NSLog(#"Thumb name is: %#", thumbName);
// Set the button image
UIImage *btnImage = [UIImage imageNamed:thumbName];
[button setImage:btnImage forState:UIControlStateNormal];
}
}
return cell;
}
When I look at the log output, All of the cells are getting setup right away. Why is this?
Shouldn't table views off the screen not be rendered? Or am I using dequeueReusableCellWithIdentifier the wrong way?
You are correct, you are misinterpreting how cellForRowAtIndexPath and a scroll view works. Your cells are getting loaded immediately because your tableviews are all subviews in the scrollview. So the tableviews as subviews will get loaded immediately when the scrollview is added to the view hierarchy. The cellForRowAtIndexPath does recycling for cells that are disappearing when you scroll a tableview (by design this makes sense). My recommendation would be to use a recycling scrollview, or even better a custom gridview implementation (appears to be what you need). I have have some examples in my library, but it might be worth search for the best grid view or image viewer than meets your needs. My library can be found here:
https://github.com/daltoniam/GPLib-iOS
You are going to want to take a look at:
https://github.com/daltoniam/GPLib-iOS/tree/master/GPLib/Views/ImageViews
https://github.com/daltoniam/GPLib-iOS/tree/master/GPLib/Views/GridView
As I stated above, it might be worth looking for a grid view/image view more along the lines your UI needs then what my lib provides, but should be a good starting point. Any questions let me know.
i want to create an application in one row of tableView there will be 4 images of button which will be loaded from server in background because if i directly load them than the table view will hang some. for this i have used this code for creating button in cell and performing to download images in background.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *hlCellID = #"hlCellID";
UITableViewCell *hlcell = [tableView dequeueReusableCellWithIdentifier:hlCellID];
if(hlcell == nil) {
hlcell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault reuseIdentifier:hlCellID] autorelease];
hlcell.accessoryType = UITableViewCellAccessoryNone;
hlcell.selectionStyle = UITableViewCellSelectionStyleNone;
}
int section = indexPath.section;
NSMutableArray *sectionItems = [sections objectAtIndex:section];
int n = [sectionItems count];
int i = 0, j = 0, tag = 1;
int x = 10;
int y = 30;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (i = 1; i<= n ; i++) //[arr count]
{
for(j=1; j<=4;j++)
{
if (i>=n) break;
Item *item = [sectionItems objectAtIndex:i];
CGRect rect = CGRectMake(x = x, y = y, 68, 65);
UIButton *button=[[UIButton alloc] initWithFrame:rect];
[button setFrame:rect];
UIImage *buttonImageNormal=[UIImage imageNamed:item.image];
[button setBackgroundImage:buttonImageNormal forState:UIControlStateNormal];
[button setContentMode:UIViewContentModeCenter];
// set the image to be loaded (using the same one here but could/would be different)
NSURL *imgURL = [NSURL URLWithString:#"http://londonwebdev.com/wp-content/uploads/2010/07/featured_home.png"];
// Create an array with the URL and imageView tag to
// reference the correct imageView in background thread.
NSMutableArray *arr = [[NSArray alloc] initWithObjects:imgURL, [NSString stringWithFormat:#"%d", tag], nil ];
// Start a background thread by calling method to load the image
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
// button.tag = [tagValue intValue];
button.tag = tag;
//NSLog(#"....tag....%d", button.tag);
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[hlcell.contentView addSubview:button];
[button release];
tag++;
x = x + 77;
}
x = 10;
y = y + 74;
}
[pool release];
return hlcell;
}
the above code work perfectly but when i download the images and trying to assign at the some particular button than i can't find the button tags althoug i can find the button tags while touchupinside action.
- (void) loadImageInBackground:(NSArray *)urlAndTagReference {
NSLog(#"Received URL for tagID: %#", urlAndTagReference);
// Create a pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Retrieve the remote image. Retrieve the imgURL from the passed in array
NSData *imgData = [NSData dataWithContentsOfURL:[urlAndTagReference objectAtIndex:0]];
UIImage *img = [[UIImage alloc] initWithData:imgData];
// Create an array with the URL and imageView tag to
// reference the correct imageView in background thread.
NSMutableArray *arr = [[NSArray alloc] initWithObjects:img, [urlAndTagReference objectAtIndex:1], nil ];
// Image retrieved, call main thread method to update image, passing it the downloaded UIImage
[self performSelectorOnMainThread:#selector(assignImageToImageView:) withObject:arr waitUntilDone:YES];
[pool release];
}
- (void) assignImageToImageView:(NSArray *)imgAndTagReference
{
// Create a pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i;
UIButton *checkView;
// [imagesForCategories addObject:[imgAndTagReference objectAtIndex:1]];
// UITableViewCell *cell = [celebCategoryTableView cellForRowAtIndexPath:[imgAndTagReference objectAtIndex:1]];
// UIImageView *profilePic = (UIImageView *)[cell.contentView viewWithTag:20];
// profilePic.image = [imgAndTagReference objectAtIndex:0];
// checkView.tag = [[imgAndTagReference objectAtIndex:1] intValue];
// loop
for (UIButton *checkView in [self.tblImage subviews] )
{ i++;
NSLog(#"Checking tag: %d against passed in tag %d",checkView.tag, [[imgAndTagReference objectAtIndex:1] intValue]);
if ([checkView tag] == [[imgAndTagReference objectAtIndex:1] intValue]) {
if (i==35) break;
// Found imageView from tag, update with img
// [checkView setImage:[imgAndTagReference objectAtIndex:0]];
[checkView setImage:[imgAndTagReference objectAtIndex:0] forState:UIControlStateNormal];
//set contentMode to scale aspect to fit
checkView.contentMode = UIViewContentModeScaleAspectFit;
//change width of frame
CGRect frame = checkView.frame;
frame.size.width = 80;
checkView.frame = frame;
}
}
// release the pool
[pool release];
// Remove the activity indicator created in ViewDidLoad()
[self.activityIndicator removeFromSuperview];
}
the all code works perfect but i can't find the table cell subview here for (UIButton *checkView in [self.tblImage subviews] so how to find the subviews of table cell subviews.?
i want to create something like this pls see image.! after that new city will come and just section change the data will show new images in row and cell section.
you may use SDWebImage
Web Image
This library provides a category for UIImageVIew with support for remote images coming from the web.
It provides:
An UIImageView category adding web image and cache management to the Cocoa Touch framework
An asynchronous image downloader
An asynchronous memory + disk image caching with automatic cache expiration handling
A guarantee that the same URL won't be downloaded several times
A guarantee that bogus URLs won't be retried again and again
Performances!
just use it
[youImageView setImageWithURL:[NSURL URLWithString:url] placeholderImage:nil options:SDWebImageRetryFailed];
I got this solution on this site: Click an UIImage and open an UIImageView in Objective-c
Add UITapGestureRecognizer to your UIImageView:
UITapGestureRecognizer *tapRecognizer;
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(yourSelector)];
[thumbnail addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
thumbnail.userInteractionEnabled = YES; // very important for UIImageView
This is working very fine for single ImageView, but I am adding more than one (about to 20) to my scrollView then How can I differentiate which ImageView will tapped or selected by user. I tried to set my own #selector(imageClicked), but it only returns tag for last imageView.
I am adding addGestureRecognizer in a loop, as I load 20 static images dynamically in an imageView.
This might help
for(int i=0;i<20;i++)
{
UIImageView *img=[[UIImageView alloc]initWithImage:[UIImage imageNamed:#"yourimage.png"]];
[img setTag:i];
img.frame= //set frame accordingly;
img.userInteractionEnabled = YES;
UITapGestureRecognizer *tap =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[img addGestureRecognizer:tap];
[tap release];
[scrollView addSubView:img];
}
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
UIImageView *imageView = (UIImageView *)recognizer.view;
switch([imageView tag])
{
case 1:
//do your work
break;
.
.
.
.
case n:
}
}
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
for (UIImageView *thumbnail in imageArray) {
[thumbnail addGestureRecognizer:tapRecognizer];
}
[tapRecognizer release];
You can get the view from the property "view" of UIGestureRecognizer.
In your selector, for example:
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
UIImageView *imageView = (UIImageView *)recognizer.view;
// Now do something with your view
}
You cannot add a single tap recognizer to multiple views. Create a new one for every view you want to add a tap recognizer to. Since you are using a tableview just do that in the tableView:cellForRowAtIndexPath: method:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// usual implementation
static NSString *cellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeue ...];
if (!cell) {
cell = [[UITableViewCell alloc] init....];
// add new gesture recognizer here.
}
// setup cell: set the image (just an example)
cell.imageView.image = [images objectAtIndex:indexPath.row];
return cell;
}
Instead of using tags like mentioned in the other answers, and just getting the imageview try to work with the underlying model. When handling the tap, find the indexPath to know what model object to access:
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
UIImageView *imageView = (UIImageView *)recognizer.view;
// assumes the image view is direct subview of the cell
// change to match your cell structure
UITableViewCell *cell = (UITableViewCell *) [imageView superview];
// get the index path for the cell clicked
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// TODO: Use index path to get full image to display
}
This way you know the exact row of the image clicked, so you can access your model to get access to the full image to display.
You need to add tag to all images - thumbnail.tag = 100 for example.Then modify your selector to youSelector:(UITapGestureRecognizer *)sender;
In selector add switch
- (void) yourSelector:(UITapGestureRecognizer *)sender {
UIImageView *imageView = (UIImageView *)sender.view;
switch(imageView.tag) {
case 100: {
//This code will be handled if tag == 100;
}
}
}
Please try to subclass the ImageView & add the gesture recognizer to the subclass.
Now for each image create the ImageView object and add the image to that object.
Set some unique property so that you can identify which object click like the name of the image.
I created a custom UITableViewCell class with a UIButton, a UIImage, and two UILabels. The button and the image are overlayed on top of each other, and only one is displayed at a time. The expected behavior is you touch on the button, the button disappears, and it displays the image. The UITableViewCells are set to be reused. Here's my code:
Constructor:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
unheartButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
unheartButton.backgroundColor = [UIColor clearColor];
unheartButton.frame = CGRectMake(10, 13, 20, 18);
[unheartButton addTarget:self action:#selector(onButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[unheartButton setBackgroundImage:[UIImage imageNamed:#"redheart.png"] forState:UIControlStateNormal];
imageView = [[UIImageView alloc] init];
imageView.frame = CGRectMake(12, 13, 16, 16);
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int ndx = 1; ndx < 13; ndx++) {
[array addObject:[UIImage imageNamed:[NSString stringWithFormat:#"icon-loading-%d (dragged).tiff", ndx]]];
}
imageView.animationImages = array;
imageView.animationDuration = 1;
[array release];
[self.contentView addSubview:imageView];
[self.contentView addSubview:unheartButton];
return self;
}
}
- (void) setModel:(MyModel *)myModel {
model = myModel;
if (model.hideImage) {
imageView.hidden = YES;
unheartButton.hidden = NO;
else {
imageView.hidden = NO;
unheartButton.hidden = YES;
}
}
Button click:
- (IBAction) onButtonClick: (id) sender {
model.hideImage = NO;
unheartButton.hidden = YES;
imageView.hidden = NO;
[imageView startAnimating];
[self setNeedsDisplay];
[self.contentView setNeedsDisplay];
[self.unheartButton setNeedsDisplay];
[self.imageView setNeedsDisplay];
}
I'm calling setNeedsDisplay on everything, but nothing seems to happen. If I scroll off the screen and back up, the button is hidden and now the loading icon is shown, but this only happens after a scroll. I'm not sure what I need to do to get the cell to repaint.
The UITableView does some fancy caching to support scrolling and the like; I've had similar issues with refreshing a specific cell when I use custom views.
You can use reloadRowsAtIndexPaths:withRowAnimation: to make the table reload just that row. See this post for more information: Why won't my UITableViewCell deselect and update its text?