How do I know which content view is touched? - iphone

I have two questions about content view.
1st question:
There are two content views in tableview cell. How do I know which one is touched?
2nd question:
I only want content view to appear in the first section of the tableview.
But, when I scroll up tableview, content view appears in the third section also.
How can I fix this problem?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imgView, *imgView1;
if(cell == nil)
{
if (indexPath.section == 0) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = #"test";
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(100,0,20,62)];
[imgView setImage:[UIImage imageNamed:#"1.png"]];
imgView.tag = 10;
[cell.contentView addSubview:imgView];
[imgView release];
imgView1 = [[UIImageView alloc] initWithFrame:CGRectMake(200,0,20,62)];
[imgView1 setImage:[UIImage imageNamed:#"2.png"]];
imgView1.tag = 20;
[cell.contentView addSubview:imgView1];
[imgView1 release];
}
}
else
{
if (indexPath.section == 0) {
imgView = (id)[cell.contentView viewWithTag:10];
imgView1 = (id)[cell.contentView viewWithTag:20];
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// How do I know left content view is touched or right content view is touched?
}

1) You can add different recognizers to each view which will call different methods.
// create view
UIImageView *view = [UIImageView ...];
view.userInteractionEnabled = YES;
// create recognizer
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(myViewTapped:)];
// add recognizer to your view
[view addGestureRecognizer:recognizer];
[recognizer release];
// now when user will tap on your view method - (IBAction)myViewTapped:(UIGestureRecognizer); will be called
2) As you are reusing cell, don't forget to nil or remove from content view unneedfull views (as they already been added in previous section and reused in third one).
UIView *view2remove = [cell viewWithTag:itsTag];
[view2remove removeFromSuperview];

The code you posted is missing a brace. You need an extra close brace before the else. Presumably your real code is not, or it would not compile.
In the else clause, assigning something to local variables won't do anything.
You also need to do something if indexPath.section != 0. If you do nothing, it is possible you will get the content of a cell that was built earlier. If you want the views not to appear, you would have to remove them. Something like:
for (UIView *subview in cell.contentView.subviews)
[subview removeFromSuperview];
But I think it will be easier if you just use a different cell identifier for section 1 and other sections. Then you will not get back cells that have been used for section 1 in section 3, and have to reconfigure them. Like:
NSString *CellIdentifier;
if (indexPath.section == 0)
CellIdentifier = #"Section1Cell";
else
CellIdentifier = #"OtherSectionCell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

Related

Detecting a tap on a UILabel using UITapGestureRecognizer not performing action

Edit:
Thanks everyone, but this has gotten to be too general as it is clear there are deeper issues at hand. I'm going to try to delete this question. I appreciate all of your help!
We have a large UITableViewCell with a UILabel inside and we want to detect the user's single tap or touch on that label. We're adding a UITapGestureRecognizer inside of our subclassed UITableViewCell:
CGRect frame = CGRectMake(0, 10, 150, 20);
self.titleLabel = [[UILabel alloc] initWithFrame:frame];
self.titleLabel.text = self.title;
self.titleLabel.userInteractionEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(expandButtonTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self.titleLabel addGestureRecognizer:singleTap];
[cell.contentView addSubview:self.titleLabel];
We've also tried setting the target to the cell's UITableViewController, but same result, the action doesn't get performed. When checking the debugger, the gesture is indeed there and attached to the label.
Edit: After more investigating, if we add a normal UIButton to the cell, it cannot be clicked. Doing more investigating, but here is the cellForRowAtIndexPath method:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (![self.metaDataSections count]) {
return nil;
}
ACMTableCellMetaData *metaData = [self metaDataForIndexPath:indexPath];
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:metaData.reuseIdentifier];
if (cell == nil) {
cell = [metaData createCell];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell = [metaData updateCellWithCellForReuse:cell];
return cell;
}
The createCell method:
- (UITableViewCell *)createCell
{
UITableViewCell *cell = [super createCell];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:self.reuseIdentifier];
cell.frame = CGRectMake(CGRectGetMinX(cell.contentView.frame),
CGRectGetMinY(cell.contentView.frame),
CGRectGetWidth(cell.contentView.frame),
ACM_TABLE_CELL_HEIGHT);
[self setupExpandButtonInCell:cell];
}
return cell;
}
updateCell method:
- (UITableViewCell *)updateCellWithCellForReuse:(UITableViewCell *)cell {
UILabel * titleLabel = (UILabel *)[cell.contentView viewWithTag:TITLE_TAG];
titleLabel = self.titleLabel;
self.cell = [super updateCellWithCellForReuse:cell];
return self.cell;
}
I clipped out some code that I don't believe affects anything. The didSelectRowAtIndexPath that is being over ridden in the the subclassed tableview doesn't have anything that would prevent user taps. But strangely, if I put a break point there, it never gets hit when tapping the cells. So I believe there are other issues at play here. We can't see why this is the case however.
If you are writing this code in class, which inherits UITableViewCell, then instead of
[cell.contentView addSubview:self.titleLabel];
use
[self addSubView:self.titleLabel];
make sure to implement
-(void)expandButtonTapped:(parameter type)parameter{
}
in the same class.
I forgot to mention about
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[TableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
// Configure the cell...
return cell;
}

UITableView not scrolling smooth due to removeFromSuperview

What makes scrolling so choppy on the UITableView? In my mind following code is a culprit. I am having very hard time to replace this logic with something other.
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview]; }
This is what I am doing.
- (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];
}
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
BGMArticleAbstract *articleAbstract = [self.section.articleAbstracts objectAtIndex:indexPath.row];
[cell.contentView addSubview:[self getHedlineFromArticleAbstract:articleAbstract]];
[cell.contentView addSubview:[self getThumbnailImageFromArticleAbstract:articleAbstract]];
[cell.contentView addSubview:[self getAbstractParaFromArticleAbstract:articleAbstract]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell; }
I am doing, addSubview to contentview because I am creating a dynamic cell height. Is there any way I can make this scroll view work smooth ? Thank you for your help.
You should design your cell as you need it. Add labels and whatever you need to the cell, and then change the content of these already available subviews.
If you need to display an image, add once an UIImageView to the cell and only change the image property of it. Same for text fields and so on.
The way you do it makes the built-in cache useless, because you regenerate all subviews again and again..
To boost the performance even more, you can do the drawing of the cell by yourself.
Apple has a quite nice example project:
http://developer.apple.com/library/ios/#samplecode/AdvancedTableViewCells/Introduction/Intro.html
You are right that the problem is caused by how you return cells. The correct pattern is as follows...
- (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];
}
// see if cell contains our image views. A reused cell will, but a new cell won't
UIImageView *imageViewA = (UIImageView *)[cell viewWithTag:32];
UIImageView *imageViewB = (UIImageView *)[cell viewWithTag:33];
UIImageView *imageViewC = (UIImageView *)[cell viewWithTag:34];
if (!imageViewA) {
// the cell must be new, so create it's image views
// you should be able to borrow most of this code from your getHeadline/thumbnail/etc methods.
// the good news is that this relatively expensive code runs only for new
// cells and there are only a few of those - only enough to fill the visible frame
imageViewA = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewA];
imageViewA.tag = 32;
imageViewB = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewB];
imageViewB.tag = 33;
imageViewC = [[UIImageView alloc] initWithFrame:CGRectMake(/* frame it here */)];
[cell.contentView addSubview:imageViewC;
imageViewC.tag = 34;
// this too, need only be done upon creation
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// now, whether it's a new cell or a reused cell, we have image views
BGMArticleAbstract *articleAbstract = [self.section.articleAbstracts objectAtIndex:indexPath.row];
// change your methods getHeadline... getThumbnail... etc to answer UIImages
// not UIImageViews, which are setup only for new cells
imageViewA.image = [self getHedlineFromArticleAbstract:articleAbstract]];
imageViewB.image = [self getThumbnailImageFromArticleAbstract:articleAbstract]];
imageViewC.image = [self getAbstractParaFromArticleAbstract:articleAbstract]];
// as a side note, once you get these methods returning images (more like model objects)
// rather than image views (view objects) they might be more appropriately placed
// in the BGMArticleAbstract class rather than the view controller
return cell;
}

why tag changed in tableview to reuseing cells

I am creating custom cell contain UILabel , UIImageView ,using constant tag for UILabel , UIImageView using dynamic tag, the table have 11 cells, the first 7 cells loading correctly, the 8, 9, 10, 11 cell image view change when I am changing the 1, 2, 3, 4, cell respectively in the table, also the tags are same in the cells, I am using the images to check box in table,UITapGestureRecognizer used to change imageview in the table,
I am using this code.....
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier =#"Cell";
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
cell.selectionStyle=UITableViewCellSelectionStyleGray;
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
UIImageView *imageview=[[UIImageView alloc]initWithFrame:CGRectMake(5, 12, 20, 20)];
imageview.tag=n;
[cell.contentView addSubview:imageview];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tabimage:)];
imageview.userInteractionEnabled=YES;
[imageview addGestureRecognizer:tap];
imageview.image=[UIImage imageNamed:#"img1.jpeg"];
UILabel *titleLabel=[[UILabel alloc]initWithFrame:CGRectMake(30, 2, 260,26)];
titleLabel.tag=222;
titleLabel.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:titleLabel];
UILabel *dateLabel=[[UILabel alloc]initWithFrame:CGRectMake(30, 31, 260, 13)];
dateLabel.tag=333;
dateLabel.font=[UIFont systemFontOfSize:10];
dateLabel.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:dateLabel];
}
UIImageView *imageview1=(UIImageView*)[cell.contentView viewWithTag:n];
if([array containsObject:[NSNumber numberWithInt:imageview1.tag]]) {
imageview1.image=[UIImage imageNamed:#"img2.jpeg"];
} else {
imageview1.image=[UIImage imageNamed:#"img1.jpeg"];
}
UILabel *titlelable=(UILabel*)[cell.contentView viewWithTag:222];
titlelable.text=[task objectAtIndex:indexPath.section];
NSLog(#"%i",indexPath.section);
UILabel *dateLabel=(UILabel*)[cell.contentView viewWithTag:333];
dateLabel.text=[date objectAtIndex:indexPath.section];
n++;
return cell;
}
- (void)tabimage:(id)sender {
UIImageView *iv=(UIImageView *)[sender view];
int i=iv.tag;
NSLog(#"------------%i",i);
if (iv.image==[UIImage imageNamed:#"img1.jpeg"]) {
iv.image= [UIImage imageNamed:#"img2.jpeg"];
[array addObject:[NSNumber numberWithInt:i]];
} else {
iv.image= [UIImage imageNamed:#"img1.jpeg"];
[array removeObject:[NSNumber numberWithInt:i]];
}
}
You should change your cell identifier from static to dynamic that will solve your problem.
You should replace this
static NSString *CellIdentifier =#"Cell";
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:CellIdentifier];
with this
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:[NSString stringWithFormat:#"%d %d"], indexPath.row, indexPath.section];
Whatever problem you see, use of that "n" is most probably the problem. There is no good reason to use a shared variable to tag (and retrieve) views on table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is called many times, it may be called several times for the same cell, and sometimes it finds a cell to reuse, and sometimes not.
I have of course no idea what n is, and how you use it elsewhere in your code, but you change it with every call here, and you cannot make assumptions when this method is called, so it's worthless.
You know for sure that every cell has one image with that tag, but if it will ever be accessible after the first run through this method or not is totally undefined, so with every reuse you basically get random behavior (either a fresh new cell or a reused one with a tag you don't know).
Ask yourself (or maybe at SO in another question): What are you trying to accomplish here?
i am getting solution for my app,
to using dynamic cell identifier in my code
NSString *CellIdentifier =[NSString stringWithFormat:#"%i-%i", indexPath.section,indexPath.row];
I suggest subclass the UITableViewCell add there all your custom elements, create setters for it. And in cellForRowAtIndexPath just call your setters.
As you are setting tag to imageview in if(cell == nil) block means tag will be set when cell is getting created. In your case 7 cells are getting created after that cells are reused by dequeuing. Hence for 8 onwards previously created cells will be used. This is why your tags are same as 1,2,3...for 8,9,10...cells.
Well, Alex suggested standard way to do it. But if you have not used custom cells yet, you can try this-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier =#"Cell";
UITableViewCell *cell = [tableview dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imageview = nil;
if(cell){
for (UIView *view in cell.contentView.subviews){
if([view isKindOfClass:[UIImageView class]]){
imageview = (UIImageView*)view;
break;
}
}
}
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
cell.selectionStyle=UITableViewCellSelectionStyleGray;
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
imageview=[[UIImageView alloc]initWithFrame:CGRectMake(5, 12, 20, 20)];
[cell.contentView addSubview:imageview];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tabimage:)];
imageview.userInteractionEnabled=YES;
[imageview addGestureRecognizer:tap];
imageview.image=[UIImage imageNamed:#"img1.jpeg"];
UILabel *titleLabel=[[UILabel alloc]initWithFrame:CGRectMake(30, 2, 260,26)];
titleLabel.tag=222;
titleLabel.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:titleLabel];
UILabel *dateLabel=[[UILabel alloc]initWithFrame:CGRectMake(30, 31, 260, 13)];
dateLabel.tag=333;
dateLabel.font=[UIFont systemFontOfSize:10];
dateLabel.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:dateLabel];
}
imageview.tag=n;
if([array containsObject:[NSNumber numberWithInt:imageview.tag]]) {
imageview.image=[UIImage imageNamed:#"img2.jpeg"];
} else {
imageview.image=[UIImage imageNamed:#"img1.jpeg"];
}
UILabel *titlelable=(UILabel*)[cell.contentView viewWithTag:222];
titlelable.text=[task objectAtIndex:indexPath.section];
NSLog(#"%i",indexPath.section);
UILabel *dateLabel=(UILabel*)[cell.contentView viewWithTag:333];
dateLabel.text=[date objectAtIndex:indexPath.section];
n++;
return cell;
}

contentView tag question

I created contentViews and assigned tags. When I click row in simulator, I cannot get right tag value. Tag value is always 0.
What is wrong with my code?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imgView, *imgView1;
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = #"test";
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(100,0,20,62)];
[imgView setImage:[UIImage imageNamed:#"1.png"]];
imgView.tag = 10;
[cell.contentView addSubview:imgView];
[imgView release];
imgView1 = [[UIImageView alloc] initWithFrame:CGRectMake(200,0,20,62)];
[imgView1 setImage:[UIImage imageNamed:#"2.png"]];
imgView1.tag = 20;
[cell.contentView addSubview:imgView1];
[imgView1 release];
}
else
{
imgView = (id)[cell.contentView viewWithTag:10];
imgView1 = (id)[cell.contentView viewWithTag:20];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.contentView.tag == 10) // tag is always 0. What's wrong?
NSLog(#"10");
else if (cell.contentView.tag == 20)
NSLog(#"20");
}
You're querying the tag of the contentview, but adding the tag to a subview of the contentview.
CellView
ContentView //You're asking for the tag of this
Subview //But assigning the tag to this
Try ((UIView*)[cell.contentview subviews] objectAtIndex:0]).tag
cell.contentView.tag returns the tag of the cell contentView but in your code, you set the tag of the subviews (image view) of contentView.

Adding UIImageView or UIView to the cell of the grouped table

I am having a problem setting a UIImageView or UIView on the cell of the Grouped table on the iPhone.
For this I am using this code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
NSArray *listData =[self.tableContents objectForKey:[self.sotreKeys objectAtIndex:[indexPath section]]];
UITableViewCell * cell = [tableView
dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if(cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
if(indexPath.section == 1 && indexPath.row ==1)
{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(240, 14, 40, 40)];
imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"Back.png",nil]];
[cell.contentView addSubview:imageView];
[imageView release];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
But it is not placed on the cell . When ever I select the row it will display for that time only, what is the problem?
Does anyone have any idea what the problem is. I think the image is getting overwritten by the cell .
Thanks in advance
try making
cell.accessoryType = UITableViewCellAccessoryNone;
It seems that you are adding image on accessory view.
If yes, you can add cell.accessoryView = imageView;
I do have some ideas of what might be happening.
You are adding an image view to the contentView then you are setting the text of the textLabel which is a part of the contentView and is probably sitting on top of the image. Try this and see if you can at least see your image on the left side.
cell.imageView.image = [UIImage imageNamed:#"Back.png"];
Now when you dequeue cells you need to remember that all the views you added last time you created the cell are still there, so as you scroll you will just be stacking back buttons on top of each other.
Also the following line [tableView deselectRowAtIndexPath:indexPath animated:YES]; is dead code because it occurs after a return statement. You might want to place that in the delegate call – tableView:willDisplayCell:forRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
NSArray *listData =[self.tableContents objectForKey:[self.sotreKeys objectAtIndex:[indexPath section]]];
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if(cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
if(indexPath.section == 1 && indexPath.row ==1)
{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(240, 14, 40, 40)];
imageView.image = [UIImage imageNamed:#"Back.png"];
[cell.contentView addSubview:imageView];
[imageView release];
}
cell.textLabel.text = [listData objectAtIndex:indexPath.row];
return cell;
}
Make sure that your image is named "Back.png" not "back.png" because the iOS on the phone is key sensitive.