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.
Related
I'm using the following code to detect a touch on a table cell image. How would I go about enlarging the image on that touch?
The part I'm stuck on is how would I make the cell.userSubmittedImageView accessible from the myFunction method?
from cellForRowAtIndexPath: method
...
cell.userSubmittedImageView.userInteractionEnabled = YES;
cell.userSubmittedImageView.tag = indexPath.row;
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(myFunction:)];
tapped.numberOfTapsRequired = 1;
[cell.userSubmittedImageView addGestureRecognizer:tapped];
return cell;
}
-(void)myFunction :(id) sender
{
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *) sender;
NSLog(#"Tag = %d", gesture.view.tag);
}
Assuming that your userSubmittedImageView is an UIImageView you can do
UIImageView * userSubmittedImageView = (UIImageView *)gesture.view;
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.
In my iPhone UITable view application
I need to add Two Buttons when user swipes on table view Cell / Row.
One for Compose mail button one for Send sms button to the contacts.
I implemented following code to add Send Mail (Blue Cloud Button) only for now
//Add a left swipe gesture recognizer in view Did load
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(swipeRow:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[contactsTable addGestureRecognizer:recognizer];
[recognizer release];
- (void)swipeRow:(UISwipeGestureRecognizer *)gestureRecognizer
{
//Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:contactsTable];
NSIndexPath *indexPath = [contactsTable indexPathForRowAtPoint:location];
UITableViewCell *cell = [contactsTable cellForRowAtIndexPath:indexPath];
UIButton *MailButton = [UIButton buttonWithType:UIButtonTypeCustom];
[MailButton setBackgroundImage:[UIImage imageNamed:#"sendData.png"] forState:UIControlStateNormal];
MailButton.frame=CGRectMake(150, 0, 40.0, 30.0);
[MailButton addTarget:self action:#selector(SendMail) forControlEvents:UIControlEventTouchUpInside];
//Add mail button if index path is valid
if(indexPath)
{
[cell addSubview:MailButton];
}
}
It execute fine and add button to the selected cell/row when we swipe on the cell.
But when we swipe another cell the buttons on the previous cell are does not hide / removed repeated as follows
I want to not showing (remove) buttons on the other cells while taping swipe on the other cell Only one cloud button At a time ..
Why not you can keep the button in XIb and add it to respective cell? It is a single object for the entire class, so there will be no duplicate of buttons in previous cells. Please try.
What you need is one ivar for storing the lastIndexPath where you added the cloud button.
And on every time to add new button you have to remove the button from the perviously added indexPath and assign the new indexPath to the ivar.
Your code may be look like this (not tested).
in .h file on property like
#property (strong, nonatomic) NSIndexPath *lastIndexPath;
and in .m file synthesize it.
Now the code will be look like this
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(swipeRow:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[contactsTable addGestureRecognizer:recognizer];
[recognizer release];
- (void)swipeRow:(UISwipeGestureRecognizer *)gestureRecognizer
{
//Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:contactsTable];
NSIndexPath *indexPath = [contactsTable indexPathForRowAtPoint:location];
//New Code
UITableViewCell *cell = [contactsTable cellForRowAtIndexPath:indexPath];
if(lastIndexPath != nil)
UITableViewCell *last = [contactsTable cellForRowAtIndexPath:lastIndexPath];
//End
UIButton *MailButton = [UIButton buttonWithType:UIButtonTypeCustom];
[MailButton setBackgroundImage:[UIImage imageNamed:#"sendData.png"] forState:UIControlStateNormal];
MailButton.frame=CGRectMake(150, 0, 40.0, 30.0);
[MailButton addTarget:self action:#selector(SendMail) forControlEvents:UIControlEventTouchUpInside];
MailButton.tag = 1111;// New code
//Add mail button if index path is valid
if(indexPath)
{
//New Code
UIButton *mb = (UIButton *) [cell viewWithTag:1111];
[mb removeFromSuperview];
//End
[cell addSubview:MailButton];
lastIndexPath = indexPath;// New Code
}
}
I have created a UITableView with a custom UITableViewCell. My cell includes one UIImageView on the left and UITextView on the right.
Inside UITableViewController, I set both image and text in tableview cellForRowAtIndexPath.
Everything shows fine but now I need to implement didSelectRowAtIndex and I need to distinguish if UIImageView or UITextView of the cell has been clicked.
Let's say, image clicking is representing delete action and the rest of the cell editing action.
Rather than adding the gesture recognisers to each individual cell, you can add one to the table view and determine which cell was selected from the point of the users touch, and then determine if the user touched the image or the cell.
First make sure your controller adopts the UIGestureRecognizerDelegate protocol.
#interface MyTableViewController() <UIGestureRecognizerDelegate>
#end
Then add the UIGestureRecognizer to the UITableView when the view loads.
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
singleTap.delegate = self;
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self.tableView addGestureRecognizer:singleTap];
}
This delegate method determines if the handleTap: method should be executed. If it can find an indexPath from the users touch, then it returns YES otherwise it returns NO.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
UITableView *tableView = (UITableView *)gestureRecognizer.view;
CGPoint p = [gestureRecognizer locationInView:gestureRecognizer.view];
if ([tableView indexPathForRowAtPoint:p]) {
return YES;
}
return NO;
}
Once we have determined if the user has clicked in a cell, the handleTap: method is called, which then decides if the user touched the image, or any other part of the cell.
- (void)handleTap:(UITapGestureRecognizer *)tap
{
if (UIGestureRecognizerStateEnded == tap.state) {
UITableView *tableView = (UITableView *)tap.view;
CGPoint p = [tap locationInView:tap.view];
NSIndexPath* indexPath = [tableView indexPathForRowAtPoint:p];
[tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
CGPoint pointInCell = [tap locationInView:cell];
if (CGRectContainsPoint(cell.imageView.frame, pointInCell)) {
// user tapped image
} else {
// user tapped cell
}
}
}
You could subclass UITableViewCell and override touchesEnded.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
UIView *hitView = [self hitTest:location withEvent:event];
if (hitView == myImageView) ...;
if (hitView == myTextView) ...;
}
You need to keep some reference to your UIImageView and UITextView (they should probably be properties of your cell).
You can of course override touchesBegan instead of touchesEnded, depends on what functionality you want to achieve.
a very abstract and general answer is to do the following
For each UIImage and UILabel you add set their tag to be the indexPath.row
//When creating the label and image add a recognizer to them
label.tag = indexPath.row;
imageView.tag = indexPath.row;
Then add a UITapGestureRecognizer on each image and label, like so
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleTap:)];
[label addGestureRecognizer:recognizer];
[imageView addGestureRecognizer:recognizer];
}
- (void) handleTap:(UITapGestureRecognizer*)recognizer
{
UIView *view = recognizer.view;
int row = view.tag;
if ([view isKindOfClass:[UILabel class]]) {
//Row is row
//and the label is pressed
}
if ([view isKindOfClass:[UIImageView class]]) {
//Row is row
//and the imageview is pressed
}
}
Make the image a UIButton. When the button's action is triggered, you know the user tapped the image (cell will NOT be selected). If cell is selected, you know the user tapped somewhere else on the row (including text view or label).
Also, set the button's tag property to, e.g. the cell's row index so you can know which row's image was tapped.
you have two option is to implement :-
1--add UITapGestureRecognizer in your "uitableviewcell" and make it point to image view
and pass "indexpath" as parameter to selector and make the delegate pass it to tableviewcell
UILabel *label = =[UILabel alloc]init];
label.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture =
[[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(labelTap)] autorelease];
[label addGestureRecognizer:tapGesture];
-(void)labelTap{
[delegate performselector#selector(labeltapped:)withobject:indexpath];
}
2- Second way is to check the sender of DidSelectRowAtIndexPath of type [imageview or label];
but i prefer the first way
I have this in my table header view section:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(sectionHeaderTapped:)];
I want to pass the section number in the method sectionHeaderTapped so i can recognize which section got tapped.
My method implementation looks like this:
-(void)sectionHeaderTapped:(NSInteger)sectionValue {
NSLog(#"the section header is tapped ");
}
How can I achieve this?
The method sectionHeaderTapped should have one of the following signatures:
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)sender;
- (void)sectionHeaderTapped;
You have to figure out the cell that was tapped using the coordinates of the tap.
-(void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer
{
CGPoint tapLocation = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *tapIndexPath = [self.tableView indexPathForRowAtPoint:tapLocation];
UITableViewCell* tappedCell = [self.tableView cellForRowAtIndexPath:tapIndexPath];
}
You can probably get the section header using that method. But it may be easier to attach a different gesture recognizer to each section header.
- (UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section
{
// ...
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(sectionHeaderTapped:)];
[headerView addGestureRecognizer:tapGesture];
return headerView;
}
And then
-(void)sectionHeaderTapped:(UITapGestureRecognizer *)gestureRecognizer
{
UIView *headerView = gestureRecognizer.view;
// ...
}
An alternate : You can add UIButton on the tableHeaderView and get click of button.