searched already some possible fixes but all did not solve mine.
i keep clicking the cell in the uitableview rather than the buttons inside it.
here is my code:
- (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];
}
cell.backgroundColor = [UIColor blackColor];
UIView *v = nil;
NSArray *array = [cell subviews];
for (v in array) {
NSLog(#"%#",[v class]);
if( [v isKindOfClass:[UIView class]] ){
[v removeFromSuperview];
}
}
//tb
if (tableView == self.tb) {
v = [[UIView alloc] initWithFrame: CGRectMake(0, 0, self.tb.bounds.size.width, 120.0)];
if([feeds count]>0){
UIImageView *box=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"statusBox.png"]];
box.userInteractionEnabled = YES;
[v addSubview:box];
AsyncImageView *imageView1 = [[AsyncImageView alloc] initWithFrame:CGRectMake(10, 20.0f, 34.0f, 34.0f)];
imageView1.contentMode = UIViewContentModeScaleAspectFill;
imageView1.clipsToBounds = YES;
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:imageView1];
if (users1 != nil && users1.imagelink != nil && (id) users1.imagelink != [NSNull null]){
imageView1.imageURL = [NSURL URLWithString:users1.imagelink];
}
else{
imageView1.image=[UIImage imageNamed:#"default_ProfilePic.png"];
}
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(myFunction:)];
tapped.numberOfTapsRequired = 1;
[imageView1 addGestureRecognizer:tapped];
[tapped release];
imageView1.userInteractionEnabled = NO;
[v addSubview:imageView1];
UIFont *font = [UIFont fontWithName:#"TrebuchetMS-Bold" size:11];
UILabel *descLabel1 = [[UILabel alloc] initWithFrame: CGRectMake(52, 23, 160, 48)];
descLabel1.text = [NSString stringWithFormat:#"%# %#",users1.userfirstn,users1.userlastn];
descLabel1.textColor = [UIColor blackColor];
descLabel1.font = font;
descLabel1.adjustsFontSizeToFitWidth=YES;
descLabel1.numberOfLines = 0;
CGSize expectedLabelSize = [descLabel1.text sizeWithFont:descLabel1.font
constrainedToSize:descLabel1.frame.size
lineBreakMode:UILineBreakModeWordWrap];
CGRect newFrame = descLabel1.frame;
newFrame.size.height = expectedLabelSize.height;
descLabel1.frame = newFrame;
descLabel1.numberOfLines = 0;
descLabel1.userInteractionEnabled = NO;
[v addSubview:descLabel1];
UILabel *descLabel2= [[UILabel alloc] initWithFrame: CGRectMake(52, 43, 200, 48)];
StatusClass *stat1=[feeds objectAtIndex:indexPath.row];
descLabel2.text = [stat1 statcreate];
descLabel2.textColor = [UIColor blackColor];
descLabel2.font = font;
descLabel2.adjustsFontSizeToFitWidth=YES;
descLabel2.numberOfLines = 0;
CGSize expectedLabelSize2 = [descLabel2.text sizeWithFont:descLabel2.font
constrainedToSize:descLabel2.frame.size
lineBreakMode:UILineBreakModeWordWrap];
CGRect newFrame2 = descLabel2.frame;
newFrame2.size.height = expectedLabelSize2.height;
descLabel2.frame = newFrame2;
descLabel2.numberOfLines = 0;
descLabel2.userInteractionEnabled = NO;
[v addSubview:descLabel2];
UILabel *descLabel3= [[UILabel alloc] initWithFrame: CGRectMake(10, 63, 280, 80)];
StatusClass *stat=[feeds objectAtIndex:indexPath.row];
descLabel3.text = [stat stattext];
descLabel3.textColor = [UIColor blackColor];
descLabel3.font = font;
descLabel3.adjustsFontSizeToFitWidth=YES;
descLabel3.numberOfLines = 0;
descLabel3.userInteractionEnabled = NO;
[v addSubview:descLabel3];
//comment button
UIButton *buttonC = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[buttonC addTarget:self action:#selector(sendComment:) forControlEvents:UIControlEventTouchUpInside];
[buttonC setImage:[UIImage imageNamed:#"comment.png"] forState:UIControlStateNormal];
buttonC.frame = CGRectMake(2, 160, 145, 35);
buttonC.userInteractionEnabled = YES;
[v addSubview:buttonC];
//share button
UIButton *buttonS = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buttonS.tag = indexPath.row;
[buttonS addTarget:self action:#selector(sendShare:) forControlEvents:UIControlEventTouchUpInside];
[buttonS setImage:[UIImage imageNamed:#"share.png"] forState:UIControlStateNormal];
buttonS.frame = CGRectMake(150, 160, 140, 35);
buttonS.userInteractionEnabled = YES;
[v addSubview:buttonS];
}
v.userInteractionEnabled = YES;
[cell addSubview:v];
}
return cell;
}
I also tried the UITapGestureRecognizer for the buttons and still not working.
Thanks.
I'm just baffled by this issue....
I managed to fix this problem by doing this on one project:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("RegCell", forIndexPath: indexPath) as! CustomCell
cell.contentView.userInteractionEnabled = false // <<-- the solution
return cell
}
but the same did not work for a different project. I have no idea why...
There is another potential cause of problems like this one, and that is UITableViewCells now have a contentView. This can and will be placed in front of other views in your custom table view cells in order to pick up touches and detect cell selection. In doing so, it may block touches to any views behind it. I've especially noticed this annoyance when creating cells using nibs.
The accepted means for dealing with this is to ensure that all subviews are added not to the tableview cell itself, but to its contentView. This is a read-only property that adjusts its own frame under certain circumstances, for example when slid sideways to reveal the delete button, or during editing mode. You should therefore ensure that any items you do add to the contentVieware intelligently sized and have the correct resizing behaviour.
Also be aware that by adding cells to the contentView, you may yourself block touches to it and thus prevent the cell from being selected. I personally try not to allow cell selection in tableviews containing cells with custom user-enabled controls. It only leads to confusion and awkward interfaces. In fact, I'm seriously considering replacing all UITableViews in my future projects with UICollectionViews, which are far more adaptable.
-Ash
I was doing this:
let plusButton: UIButton = {
let v = UIButton()
v.setImage(plusImg, for: .normal)
v.tintColor = .dark
v.translatesAutoresizingMaskIntoConstraints = false
// adding targets here did not work
v.addTarget(self, action: #selector(plusButtonHandler), for: .touchUpInside)
return v
}()
And it appears invoking the addTarget method inside of the closure did not work.
When I factored the addTarget method out and instead put it in the initializer, everything worked!
In my case I tried to added the UIButton direct to the cell by self.addSubview(myButton), so I changed to self.contentView.addSubview(myButton) and it worked
It seems the contentView was in front of the myButton so the button won't receive the tap gesture.
Your UIButton='s y offset is given as 160 and UIView's height is just given as 120. Please change the UIButton's y offset and try.
The UITableViewCell is handling all the gestures by default.
Set cell.selectionStyle = UITableViewCellSelectionStyleNone; to make it disable the default behaviour.
For Swift 3 and Storyboard
For me, I had to enable multiple touch inside the content view, and enable user interaction on everything - the table view, table view cell, content view, and UIButton. I was using storyboard.
I also set up my tableview cell as a subclass.
Since I couldn't find an answer here when I was exploring the problem, I posted another question on stack overflow about this. You can see my code and download a project with this working here: Can't click button inside UITableViewCell?
I ran into this problem, but in my case it was not related to the table view, instead it was because I was using subviews in my button for which userInteractionEnabled was true, setting that value for false (NO) for all the button's subviews fixed the issue for me.
I have the same issue, and somehow I figured out my mistake.
After I changed the constraints with self(UITableViewCell) to constraints with contentView of self(UITableViewCell),my cell's button is clickable again.
Update swift 4.2
in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
add it : cell.buttonCheckBox.isUserInteractionEnabled = false
OR, uncheck User Interaction Enabled inspector
Now you can select the button as well as a cell.
This works for me :)
Create a custom UITableViewCell. Refer this link.
Say you have a UIButton by the name of displayButton, you can do something like this:
Inside your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, after you create your cell,
[cell.dislayButton addTarget: self
action: #selector(replyButtonPressed:withEvent:)
forControlEvents: UIControlEventTouchUpInside];
And the create the method like so in your ViewController:
- (void) replyButtonPressed: (id) sender withEvent: (UIEvent *) event
{
UITouch * touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView: self.tableView];
NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint: location];
}
try this
public override void SetSelected(bool selected, bool animated)
{
// this.interestsButton.Selected = true;
if (selected)
{
// this.TextLabel.TextColor = UIColor.Red;
//this.interestsButton.ShowsTouchWhenHighlighted = true;
this.interestsButton.BackgroundColor = UIColor.Purple;
//this.interestsButton.SetTitleColor(UIColor.Red, UIControlState.Highlighted);
}
else
{
}
// cell.ContentView.UserInteractionEnabled = false;
base.SetSelected(selected, animated);
}
Tested on "Mvvmcross.iOS" only
Just to add to the discussion:
FOR SWIFT 5+
Is important to set the variable as lazy var when invoking the addTarget method inside of the closure. See:
lazy var plusButton: UIButton = {
let v = UIButton()
v.setImage(plusImg, for: .normal)
v.tintColor = .dark
v.translatesAutoresizingMaskIntoConstraints = false
v.addTarget(self, action: #selector(plusButtonHandler), for: .touchUpInside)
return v
}()
Now, about the contentView of the tableViewCells that appears above the cell stoping the click at the cell: I used the code above and also set the contentView to .ishidden = true and it worked!
Probably there is something linked to the lifecycle of the methods.
Hope it helps too.
If you have no alternative selector for the UIButton pressed inside some UITableViewCell you need turn off userInteractionEnabled for the button
cellButton.userInteractionEnabled = false
In this case any button touch will propagate to the cell touch.
Related
I am experiencing performance problems when using some subviews on my UITableViewCells. After I keep scrolling it eventually starts getting very slow.
First step I am doing is creating a common UIView for every cell, essentially this is creating a white cell with a rounded effect on the cell with a shadow. The performance for this seems to be normal so I don't think it's the culprit.
Here is the code I am using to do this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *NewsCellIdentifer = #"NewsCellIdentifier";
NewsItem *item = [self.newsArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NewsCellIdentifer];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NewsCellIdentifer];
cell.contentView.backgroundColor = [UIColor clearColor];
UIView *whiteRoundedCornerView = [[UIView alloc] initWithFrame:CGRectMake(10,10,300,100)];
whiteRoundedCornerView.backgroundColor = [UIColor whiteColor];
whiteRoundedCornerView.layer.masksToBounds = NO;
whiteRoundedCornerView.layer.cornerRadius = 3.0;
whiteRoundedCornerView.layer.shadowOffset = CGSizeMake(-1, 1);
whiteRoundedCornerView.layer.shadowOpacity = 0.5;
[cell.contentView addSubview:whiteRoundedCornerView];
[cell.contentView sendSubviewToBack:whiteRoundedCornerView];
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
cell.layer.opaque = YES;
cell.opaque = YES;
}
[cell.contentView addSubview:[self NewsItemThumbnailView:item]];
return cell;
}
Here is the method that returns the thumbnail view of the graphic and text:
- (UIView *) NewsItemThumbnailView:(NewsItem *)item
{
UIView *thumbNailMainView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 50, 70)];
UIImageView *thumbNail = [[UIImageView alloc] initWithImage:[UIImage imageNamed:item.ThumbNailFileName]];
thumbNail.frame = CGRectMake(10,10, 45, 45);
UILabel *date = [[UILabel alloc] init];
date.frame = CGRectMake(10, 53, 45, 12);
date.text = item.ShortDateString;
date.textAlignment = NSTextAlignmentCenter;
date.textColor = [BVColors WebDarkGrey];
CGFloat fontSize = 10.0;
date.font = [BVFont Museo:&fontSize];
date.opaque = YES;
thumbNail.opaque = YES;
thumbNailMainView.opaque = YES;
[thumbNailMainView addSubview:thumbNail];
[thumbNailMainView addSubview:date];
return thumbNailMainView;
}
The performance problem seems to be when I add the thumbnail view to the cell because when I comment that line out, I don't seem to have it. The thumbnail information is dynamic and will change with each cell. I would appreciate any advice on how I should do this without degrading the performance.
UITableView will call tableView:cellForRowAtIndexPath: each time a cell comes into view, and dequeueReusableCellWithIdentifier: will reuse existing cell objects if they are available. These two facts combine to put you in a scenario where every time you scroll, the same finite number of cell objects end up with an increasing number of subviews.
The proper approach is to create a custom UITableViewCell subclass that has a property for thumbnailView. In the setter for that property, remove the previous thumbnail (if any) and then add the new one to the contentView. This ensures that you'll only ever have one thumbnail subview at any time.
A less optimal approach would be adding a tag to the UIView returned from NewsItemThumbnailView (thumbNailMainView.tag = someIntegerConstant) and then searching for any view with that tag and removing it before adding another:
// remove old view
UIView *oldThumbnailView = [cell.contentView viewWithTag:someIntegerConstant];
[oldThumbnailView removeFromSuperview];
// add new view
[cell.contentView addSubview:[self NewsItemThumbnailView:item]];
I ended up leveraging a solution found on this stackoverflow post:
How should I addSubview to cell.contentView?
Essentially when the cell is first initialized I am setting the view as mentioned by Nishant; however once the cell is reused I am extracting out the items I need to change, such as an UIImageView and then a UILabel. Since these are pointers I can modify just what I need when I need to and the performance is fast again. Here is a abbreviated version of what I did.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *NewsCellIdentifer = #"NewsCellIdentifier";
NewsItem *item = [self.newsArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NewsCellIdentifer];
UIView *thumbNailMainView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 50, 70)];
UIImageView *thumbNail;
UIView *textMainView = [[UIView alloc] initWithFrame:CGRectMake(20,20,80,80)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(52,-5, 70, 20)];
UILabel *teaserLabel = [[UILabel alloc] initWithFrame:CGRectMake(50,20, 210, 40)];
UIView *newsItemCornerMainView = [[UIView alloc] initWithFrame:CGRectMake(255.7, 55.2, 55, 55)];
UIImageView *cornerIconView;
// If the cell doesn't existing go ahead and make it fresh.
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NewsCellIdentifer];
// Configure all the various subviews
..... //Sample below
// Make the title view
headerLabel.text = item.Title;
CGFloat textfontSize = 16.0f;
headerLabel.font = [BVFont Museo:&textfontSize];
headerLabel.textColor = [BVColors WebBlue];
headerLabel.textAlignment = NSTextAlignmentLeft;
headerLabel.numberOfLines = 0;
headerLabel.tag = 50;
// Make the Teaser view
teaserLabel.text = item.Teaser;
teaserLabel.numberOfLines = 0;
CGFloat tfontSize = 13.0f;
teaserLabel.textAlignment = NSTextAlignmentLeft;
teaserLabel.textColor = [BVColors WebDarkGrey];
teaserLabel.font = [BVFont HelveticaNeue:&tfontSize];
[teaserLabel sizeToFit];
teaserLabel.tag = 51;
[textMainView addSubview:headerLabel];
[textMainView sendSubviewToBack:headerLabel];
[textMainView addSubview:teaserLabel];
[cell.contentView addSubview:textMainView];
....
}
thumbNail = (UIImageView *) [cell viewWithTag:47];
[thumbNail setImage:[UIImage imageNamed:item.ThumbNailFileName]];
headerLabel = (UILabel *) [cell viewWithTag:50];
headerLabel.text = item.Title;
teaserLabel = (UILabel *) [cell viewWithTag:51];
teaserLabel.text = item.Teaser;
cornerIconView = (UIImageView *) [cell viewWithTag:48];
[cornerIconView setImage:[UIImage imageNamed:item.CornerIconFileName]];
return cell;
}
You should change thumbNailMainView content only everytime but you should not add its content on cell everytime.
So add this line where you are allocating cell
[cell.contentView addSubview:[self NewsItemThumbnailView:item]];
add this inside braces. and then access thumbNailMainView from cell and pass that item data which you need to change for each cell.
Assign a tag to thumbNailMainView and its subview thumbNail then access it as
UIView *_thumbNailMainView = [cell.contentView viewWithTag:_thumbNailMainView_tag];
UIImageView *_thumbNail = [_thumbNailMainView viewWithTag:thumbNail_tag];
_thumbNail.image = [UIImage imageNamed:item.ThumbNailFileName];
Hope it helps you.
In my cellForRowAtIndexPath, I'm doing some custom formatting on a subview for when that cell is selected. The complete function is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UIView *left;
UIImageView *leftImage;
UILabel *label;
ArticleButton *btn;
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (!cell)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"UITableViewCell"] autorelease];
left = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, 155, 139)] autorelease];
leftImage = [[[UIImageView alloc] initWithFrame:CGRectMake(7,9,141,77)] autorelease];
label = [[[UILabel alloc] initWithFrame:CGRectMake(6,87,141,48)] autorelease];
btn = [[[ArticleButton alloc] initWithFrame:CGRectMake(0,2,155,139)] autorelease];
left.tag = 0;
leftImage.tag = 1;
label.tag = 2;
btn.tag = 3;
[btn addTarget:self action:#selector(selectArticle:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:left];
[cell.contentView addSubview:leftImage];
[cell.contentView addSubview:label];
[cell.contentView addSubview:btn];
}
else
{
left = (UIView*)[cell viewWithTag:0];
leftImage = (UIImageView*)[cell viewWithTag:1];
label = (UILabel*)[cell viewWithTag:2];
btn = (ArticleButton*)[cell viewWithTag:3];
}
...load *entry
NSURL *url = [NSURL URLWithString:[entry imageUrl]];
FeedEntry* selectedEntry = [detailViewController detailItem];
NSString* selectedTitle = selectedEntry.title;
if ([selectedTitle isEqualToString:entry.title])
{
[left setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"cellbackground_sel.png"]]]; <-- PROBLEM IS THIS IMAGE NEVER CHANGES
NSLog(#"selected row %#", selectedTitle);
}
else{
[left setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"cellbackground2.png"]]];
}
[left setNeedsDisplay];
[leftImage setImageWithURL:url placeholderImage:[UIImage imageNamed:#"placeholder.gif"]];
[leftImage setContentMode:UIViewContentModeScaleAspectFill];
leftImage.clipsToBounds = YES;
[label setBackgroundColor:[UIColor clearColor]];
label.textColor = [UIColor whiteColor];
label.text = [entry.title stringByAppendingString:#"\n\n"];
label.numberOfLines = 3;
label.lineBreakMode = UILineBreakModeClip;
label.font = [UIFont fontWithName:#"Arial-BoldMT" size:12];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
The problem I'm having is with this section:
if ([selectedTitle isEqualToString:entry.title])
{
[left setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"cellbackground_sel.png"]]];
NSLog(#"selected row %#", selectedTitle);
}
else{
[left setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"cellbackground2.png"]]];
}
Everything else works, but although I'm logging that it gets called, but the background of my subview to indicate that the row in question is a selected row, never changes. I've tried calling setNeedsDisplay, I've tried scrolling up and down trying to get the cells to dequeue and get recreated, it just never users the other image, even though it logs that the row being drawn was a selected row.
(Once I get this working, I need to implement the "right" section to have two "cells" in the one row and only one will be selected. That's why I'm doing it this way with subviews in the cell).
What am I doing wrong?
I think it is a problem to set the tag to zero. The documentation says:
viewWithTag:
Return Value
The view in the receiver’s hierarchy whose tag property matches the value in the tag parameter.
Discussion
This method searches the current view and all of its subviews for the specified view.
If think that most views tag is zero, even that of the current cell's view. I think that you dont get the correct view out of it. Try not to use 0 as a tag to work with.
Whenever a particular UITableViewCell is selected, this particular delegate is called -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Try to see if your button taps are being first responded by this delegate rather than going to selectArticle: selector you have defined...
Instead of setting this in tableview:cellForRowAtIndexPath:, try doing it in the tableview:willSelectRowAtIndexPath:
See the protocol reference for further details.
I'm trying to figure out how to place a subview to a custom UITableViewCell with centered position. As stated in the documentation (Customizing Cells) one should "...add subviews to the contentView property of the cell object or ...". As I noticed it works fine with UITableViewStylePlain. In UITableViewStyleGrouped tables, subviews can not be placed centered. They are shifted to the right hand side.
If the subview is added to UITableViewCell directly, it's fine with both modes. The same is true, if I subclass the UITableViewCell and load the cell from XIB.
Unfortunately, I can't upload screenshots. Can anyone help fix the issue? Or do I miss something vital, as the misalignment seems to match the dimension to be shrunken in grouped table.
Many thanks,
El
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier1 = #"AddToCell";
static NSString *cellIdentifier2 = #"AddToContentView";
static NSString *aVeryLongLine = #"---------------------------------------------";
UITableViewCell *cell = nil;
if (indexPath.section == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier1];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier1] autorelease];
CGRect frame = cell.frame;
CGRect labelFrame = CGRectMake((frame.size.width-270)/2, (frame.size.height-40)/2, 270, 40);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.textAlignment = UITextAlignmentCenter;
label.text = aVeryLongLine;
[cell addSubview:label];
[label release];
}
}
else if (indexPath.section == 1) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier2];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier2] autorelease];
CGRect frame = cell.contentView.frame;
CGRect labelFrame = CGRectMake((frame.size.width-270)/2, (frame.size.height-40)/2, 270, 40);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.textAlignment = UITextAlignmentCenter;
label.text = aVeryLongLine;
[cell.contentView addSubview:label];
[label release];
}
}
else {
}
return cell;
}
Instances of UITableViewCell resize their content views under a number of circumstances (for example, when temporarily adding a delete button to allow the user to remove a row).
When cells are displayed in a grouped style table view, they're resized to provide a margin between the cells and the left and right edges of the table view. So for your subviews to stay positioned correctly, you'll need to set their autoresizing masks appropriately, something like this:
mySubview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
(or
[mySubview setAutoresizingMask:(UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin)];
for folks who prefer the old syntax.)
Did you check the frame's value, which come from cell.contentView.frame or cell.frame ?
When the cell is initialized with style and identity, it maybe have a CGZeroRect for his frame value.
I have a tableview cell with a custom textview in it, I am now left wondering how do I possibly access the text in the textbox after text has been edited/added.
I would normally know how this is done when I draw the textfield through IB, but my textviewcell is dynamically drawn.
(i.e. I would like to capture the data that is updated in detailLabel.text)
Here is the related code to adapt to your answer.
Thanks again!
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
//Big Text Box
UITextView *detailLabel = [[UITextView alloc] initWithFrame:CGRectMake(30, 80, 500, 150)];
detailLabel.tag = 20;
[cell.contentView addSubview:detailLabel];
detailLabel.layer.borderWidth = 1;
detailLabel.layer.borderColor = [[UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.9] CGColor];
detailLabel.layer.cornerRadius = 10;
detailLabel.font = [UIFont fontWithName:#"Helvetica" size:17];
[detailLabel release];
}
UITextView * detailLabel = (UITextView *) [cell.contentView viewWithTag:20];
switch (indexPath.row) {
case 0:
detailLabel.text = #"no";
break;
default:
detailLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
detailLabel.hidden = NO;
}
You'll want to listen for messages sent by the UITextView. So look to implement the UITextViewDelegate protocol and register the implementing class with the detailLabel using its delegate property.
When your delegate is notified of a change in the UITextView you'll have to identify the cell which currently owns the UITextView. In doing so you must remember that cells can be reused.
I would start by looking at the following method in the UITableView class:
- (NSArray *)visibleCells
We know that if the user has made a change to the UITextView's contents it must currently be on screen and therefore be present in the pre-mentioned array. To find it we use the pointer to the UITextView which changed (it's a parameter in the textViewDidChange protocol method). So simply iterate over the visibleCells array and retrieve the UITextView and compare it against the UITextView which changed.
- (void)textViewDidChange:(UITextView *)textView {
....
cellsLabel = (UITextView *) [cell.contentView viewWithTag:20];
if (cellsLabel == textView)
...
You'll now have a handle to a cell in the UITableView. To find the index use the following UITableView method:
- (NSIndexPath *)indexPathForCell:(UITableViewCell *)cell
When writing a customized subclass of UITableViewCell, I find that the results work well for the rectangular cells of a plain-styled UITableView, but do not work at all for the rounded cells in a grouped-styled table.
Is there a way to reliably subclass UITableViewCell to draw cells which work for grouped-style tables? (Without using Interface Builder.)
Could the answer be as simple as first calling [super layoutSubviews] inside your UITableViewCell subclass’s layoutSubviews method?
Here is my code.
First I create the UITextField and add it to the contentView in the initWithStyle: method:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
inputField = [[UITextField alloc] initWithFrame:CGRectZero];
[self.contentView addSubview:inputField];
inputField.borderStyle = UITextBorderStyleLine;
[inputField release];
}
return self;
}
Then in layoutSubviews, I’ve got this:
-(void)layoutSubviews
{
inputField.frame = CGRectMake(5, 5, 100, 20);
}
With that code, the text field is 5px from the left of the screen, which is, of course, 5px to the left of the table cell when it’s in grouped mode. In other words, OUTSIDE of the table view cell. No good.
Use this code and the inputField is placed 5px to the right of the cell, like I want it to be:
-(void)layoutSubviews
{
[super layoutSubviews]; // the magic line
inputField.frame = CGRectMake(5, 5, 100, 20);
}
I could have totally misunderstood the problem you were having, though!
Erik
I used to have lots of problems with UITableViewCell subclasses, but then I just stopped subclassing.
Adding subviews to the contentView property of a UITableViewCell seems to accomplish the same thing in any instance that I've run across, so I just do that inside my UITableViewController.
Here's an example that has a title and value:
- (UITableViewCell *)tableView:(UITableView*)tableView
cellForRowAtIndexPath: (NSIndexPath*)indexPath
{
static NSString* CellIdentifier = #"AccountDetailsCell";
UILabel* mainLabel = nil;
UILabel* valueLabel = nil;
const CGFloat kAccountDetailFontSize = 14.0;
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
if ( cell == nil )
{
cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier: CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake( 10.0, 0.0, 150.0, 44.0 )] autorelease];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont boldSystemFontOfSize: kAccountDetailFontSize];
mainLabel.textAlignment = UITextAlignmentLeft;
mainLabel.textColor = [UIColor darkGrayColor];
mainLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight;
mainLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview: mainLabel];
valueLabel = [[[UILabel alloc] initWithFrame: CGRectMake( 150.0, 0.0, 150.0, 44.0 )] autorelease];
valueLabel.tag = VALUELABEL_TAG;
valueLabel.font = [UIFont boldSystemFontOfSize: kAccountDetailFontSize];
valueLabel.textAlignment = UITextAlignmentRight;
valueLabel.textColor = [UIColor darkTextColor];
valueLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
valueLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview: valueLabel];
}
else
{
mainLabel = (UILabel*)[cell.contentView viewWithTag: MAINLABEL_TAG];
valueLabel = (UILabel*)[cell.contentView viewWithTag: VALUELABEL_TAG];
}
mainLabel.text = (NSString*)kCellTitles[indexPath.section][indexPath.row];
valueLabel.text = [self tableView: tableView valueLabelTextForRowAtIndexPath: indexPath];
return cell;
}
I've noticed this problem as well. My workaround has been to just make my table cells smaller (300 width instead of 320). It's not a great solution, but it works well.
I don't believe you can get rid of the table view insets on an individual basis when in "grouped" mode. I could be wrong though!
What problem are you having? In drawRect you are given a rect, and know your total size - just conform to that space. If you are using layoutSubviews, same thing.