UITableViewCell configuration - objective-c

I have a UITableView in my app, which stores a list of URLs. Above table there are UITextField and UIButton.
When user types some URL on textField and then presses the button I add those URL like the top element in the tableView.
Next, when user selects any of URLs, I want to create a button within selected UITableViewCell to let user to follow that URL (actually, it's not important). Here's didSelectRowAtIndexPath method definition:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.recentUrlsTableView cellForRowAtIndexPath:indexPath];
UIButton *button = [UIButton new];
button.frame = CGRectMake(cell.frame.size.width - 34, cell.frame.origin.y + 10, 24, 24);
button.backgroundColor = [UIColor lightGrayColor];
[button setTitle:#">" forState:UIControlStateNormal];
[cell.contentView addSubview:button];
[button release];
}
But I want those button to disappear when I deselect cell. So, I tried this thing (I kow it looks stupid, but unfortunately I didn't know better way to find my button in there):
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.recentUrlsTableView cellForRowAtIndexPath:indexPath];
for (UIView *subview in cell.subviews)
{
if ([subview isKindOfClass:[UIButton class]])
if ([[(UIButton*)subview titleLabel].text isEqualToString:#">"])
{
[subview removeFromSuperview];
[subview release];
}
}
}
But this stuff seemed to work incorrectly - instead of releasing and disappearing at all, button started to in another rows - even those, which were empty.
After that I tried to do same actions for every row in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method. But it also didn't help.
I guess, that there are some trivial issue, but I can't find it. So, I will highly appreciate any of your help!

When you scroll up/down the table cells get reused and cell (with button) can be populated with completely diffetent contents (i.e. is used for different indexpath). That's why you're experiencing this.
So there is always only one button (or none) on your table.
You'd be best off if you create (reatin & keep reference of it) one button from outside the table. Your didDeselectRowAtIndexPath would then look like:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.recentUrlsTableView cellForRowAtIndexPath:indexPath];
//you have outside reference for this button
[button removeFromSuperView];
button.frame = CGRectMake(cell.frame.size.width - 34, cell.frame.origin.y + 10, 24, 24);
[cell.contentView addSubview:button];
}
If this doesn't work you should use combination of reloadData and cellForIndexPath. Like so:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.recentUrlsTableView reloadData];
}
- (void)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//create your cell as usually
if ([cell isSelected]) { //i'm not sure if this is the right way to detect selected cell
[button removeFromSuperView];
button.frame = CGRectMake(cell.frame.size.width - 34, cell.frame.origin.y + 10, 24, 24);
[cell.contentView addSubview:button];
}
}

Related

UIView addSubview nor working in UITableViewCell

barView I have a Table View and, in each cell, I want to draw some statistic bars. I have an empty UIView created in my custom cell, its name is mainView and it is the view where the chart is drawn.
In cellForRowAtIndexPath I'm doing this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCellIdentifier";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
CGRect barRect = CGRectMake(0, 0, 100, 10);
UIView *barView = [[UIView alloc] initWithFrame:barRect];
[barView setBackgroundColor:[UIColor redColor]];
[cell.mainView addSubview:barView];
return cell;
}
The barView is not displaying on loading. It only shows after I change and return from another tab or after the cell goes out of the screen.
Notes:
I have tried [cell.mainView setNeedsDisplay];
I have a header made with another custom cell.
Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCellIdentifier";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
CGRect barRect = CGRectMake(0, 0, 100, 10);
UIView *barView = [[UIView alloc] initWithFrame:barRect];
[barView setBackgroundColor:[UIColor redColor]];
[cell addSubview:barView]; // use cell.mainView if you have that created somewhere other than here (like IB)
}
return cell;
}
dequeueResuable... can return a nil cell. So you need to have a check, to see if you should alloc/init a new cell. In the code I gave you if dequeueResuable... returns you a proper cell then it would have been created with the subview intact already. So no need to re-add it (hence creating it only in if (!cell))
Your description clearly indicates you are filling your barView outside this function. So that it becomes visible only after transition.
Or you are simply overwriting it (or even overwriting mainview) outside what you have provided here.
Check your viewdidload and viewdidappear and the likes.
I have solved it easily with:
- (void)viewDidAppear:(BOOL)animated
{
[self.tableView reloadData];
}
It seems that adding a subview cant be done before the view is created in the window, before the cells are completely loaded.

Looping through subview of a custom cell in didSelectRowAtIndexPath to get UITextField text

i know im asking a very common question. but after going through a lots of similar questions and articles im not able understand
How can i access UITextfield inside UITableViewCell inside didSelectRowAtIndexPath delegate method.
im posting my code below. i may b not going with expected way although..
i want to make textfield (of selected row) [becomeFirstResponder] in didSelectRowAtIndexPath
so that i can display uiPicker below to this textfield. Please help me out with 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(self.isTableForHospital)
{
UIView *myview=[self createRowViewForHospitalTable:[customArray objectAtIndex:indexPath.row]];
myview.tag=indexPath.row;
[cell addSubview:myview];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
}
else
{
cell.textLabel.text=[customArray objectAtIndex:indexPath.row];
}
}
return cell;
}
-(UIView *)createRowViewForHospitalTable:(NSString *)rowText
{
UIView *hospital_row_view=[[UIView alloc]init];
UILabel *lblRowText=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 300, 50)];
lblRowText.text=rowText;
txtDepartment=[[UITextField alloc]initWithFrame:CGRectMake(310, 0, 185, 30)];
//...rest styling for textfield goes here..
txtRole=[[UITextField alloc]initWithFrame:CGRectMake(495, 0, 185, 30)];
[hospital_row_view addSubview:lblRowText];
[hospital_row_view addSubview:txtDepartment];
[hospital_row_view addSubview:txtRole];
return hospital_row_view;
}
- (void)textFieldDidEndEditing:(UITextField *)textField { }
- (void)textFieldFinished:(id)sender{
NSString *value=#"sa";
[sender resignFirstResponder];
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cellSelected = [tableView cellForRowAtIndexPath: indexPath];
UIView *myview=[cellSelected.contentView viewWithTag:indexPath.row];
for(UIView *item in [myview subviews])
{
if([item isKindOfClass:[UITextField class]])
{
[item becomeFirstResponder];
}
}
}
In terms of iterating through the cell subviews and getting the UITextField, I think I have your answer.
I found this on another thread here, and modified it to be more generic:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITextField* textField = [[UITextField alloc] init];
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
UIView* subview = [[cell.contentView subviews] lastObject]; // Make sure your UITextField really *is* the last object you added.
if ([subview isKindOfClass:[UITextField class]]) {
textField = (UITextField*)subview;
}
[textField becomeFirstResponder];
}
...where "textField" is the placeholder for your actual text field object.
Hope this helps!
I don't think you need to alloc init the textfield, for it will ultimately be pointing to the cell's textfield (if any).
I believe you are allocating it unnecessarily.

Activate cell's accessory view (UISwitch) when didSelectRowAtIndexPath is called

Every cell of my tableView has a UISwitch as an accessoryView:
UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = mySwitch;
[mySwitch addTarget:self action:#selector(SwitchToggle:) forControlEvents:UIControlEventValueChanged];
Switch is toggled when the user taps it, but I also want it toggled when the didSelectRowAtIndexPath is called (when the user taps on that cell).
I tried this (but it doesn't work):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UISwitch *tempSwitch = (UISwitch *)[tableView cellForRowAtIndexPath:indexPath].accessoryView;
[tempSwitch addTarget:self action:#selector(SwitchToggle:) forControlEvents:UIControlEventValueChanged];
[tableView deselectRowAtIndexPath:indexPath animated:YES]; // cell selection fadeout animation
}
Thanks.
The code must look like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UISwitch *tempSwitch = (UISwitch *)[tableView cellForRowAtIndexPath:indexPath].accessoryView;
[tempSwitch setOn:!tempSwitch.on animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Remember that you also have to update your model.

UIView background color does not take effect

Can someone tell me why this is not working right?
I have these lines of code below within my table view cell for tableView:didSelectAtIndexRowPath: method.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[tableView viewWithTag:199]removeFromSuperview];
CGSize cellSize = [tableView cellForRowAtIndexPath:indexPath].frame.size;
UIView *subSelectionView = [[UIView alloc]initWithFrame:CGRectMake(10, 0, (int)cellSize.width - 20, 100)];
[subSelectionView setBackgroundColor:[UIColor blueColor]];
subSelectionView.layer.borderColor = [UIColor grayColor].CGColor;
subSelectionView.layer.borderWidth = 1;
subSelectionView.tag = 199;
[[tableView cellForRowAtIndexPath:indexPath]addSubview:subSelectionView];
}
Notice the code:
[subSelectionView setBackgroundColor:[UIColor blueColor]];
Obviously, I want to change the color of the subview that I added to the UITableViewCell but why is it not working ?
jus reload the table after adding the subview on the table
[[tableView cellForRowAtIndexPath:indexPath]addSubview:subSelectionView];
[tableview reloadData];
Add the following line to the start of the method
[tableView deselectRowAtIndexPath:indexPath animated:NO];
So ur method would be
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[[tableView viewWithTag:199]removeFromSuperview];
....
}

UITextField unable to become first responder if added to UITableViewCell via accessoryView

Like many other users, I'm trying to set throw a UITextField into a UITableViewCell to be used for editing a row. But instead of adding a new view, I'm trying to use the accessoryView property. At first I tried this...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITextField *textField =[[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 44.0f)];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryView = textField;
[textField becomeFirstResponder];
}
...and the UITextField is added properly, but I need to tap it again to get the keyboard to show. However if I do this...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITextField *textField =[[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 44.0f)];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell addSubview:textField];
[textField becomeFirstResponder];
}
...it works, the keyboard shows up but, I don't get any of the other benefits of having it as the accessoryView (easier positioning with other views moving around it). I suppose the addSubview: call is altering the responder chain or something and allowing my UITextField to become the first responder, but thought maybe there was another way to do this allowing me to set the cell's accessoryView instead. Thanks.
I hate my solution, but it works and am up for a better way.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
CGRect detailTextLabelFrame = cell.detailTextLabel.frame;
detailTextLabelFrame.origin.x -= 100.0f;
detailTextLabelFrame.size.width += 100.0f;
UITextField *textField = [[UITextField alloc] initWithFrame:detailTextLabelFrame];
cell.detailTextLabel.hidden = YES;
cell.accessoryView = textField;
// These are the two lines that made it work, but it feels ugly
[cell.accessoryView removeFromSuperview];
[cell addSubview:cell.accessoryView];
[cell.accessoryView becomeFirstResponder];
}
I hope you know about textfield delegate.Try this way....may be it will help you.
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
if(theTextField == yourtextfieldname) {
[yourtextfieldname resignFirstResponder];
}
return YES;
}