I have subclassed a UITableViewCell. What I want to have is when I click on the cell, I added a UIView to the bottom of the cell and adjust the height of the cell accordingly. Here's my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCell* cell = (MyCell *) [self.table cellForRowAtIndexPath:indexPath];
UIView * options = [[UIView alloc] initWithFrame:CGRectMake(0, cell.frame.size.height - 27, cell.frame.size.width, 27)];
UIButton* button1 = [UIButton buttonWithType:UIButtonTypeCustom];
[options addSubview:button1];
UIButton* button2 = [UIButton buttonWithType:UIButtonTypeCustom];
[options addSubview:button2];
UIButton* button3 = [UIButton buttonWithType:UIButtonTypeCustom];
[options addSubview:button3];
//did some layout calculation here to position the button
[cell addSubview:options];
}
Here's a video that illustrates the issue
Also I've tried to change the accessoryView of my cell from my custom UIButton to the regular UITableViewCellAccessoryDisclosure but it didn't work
MyCell * cell = (MyCell *)[self.table cellForRowAtIndexPath:temp];
[cell.accessoryView removeFromSuperview];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
If you're curious what I am trying to do, I am trying to create a tweetbot uitableviewcell, where you press the cell/row and it presents you with other options (retweets, etc) and also it was shown animated.
I don't know if I correctly understand what you are trying to do. But if you do want to animate the change of the UITableViewCell's height try to adjust it within - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath and call
[tableView beginUpdates];
[tableView endUpdates];
Put controls into another cell and use
insertRowsAtIndexPaths:withRowAnimation:
to show it and
deleteRowsAtIndexPaths:withRowAnimation:
to hide it.
Related
I have implemented this button drawer and I've added some buttons to it. That said, I'm unsure how I'll go about sending messages from these buttons in the drawer to the appropriate delegate method to delete the item from my tableView.
How do I get the correct indexPath? Should I make a new NSIndex for uitableviewcells that have had their check button toggled?
Thanks
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
HHPanningTableViewCell *cell = (HHPanningTableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSInteger directionMask = indexPath.row % 5;
if (cell == nil) {
cell = [[HHPanningTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
UIView *drawerView = [[UIView alloc] initWithFrame:cell.frame];
drawerView.backgroundColor = [UIColor grayColor];
cell.drawerView = drawerView;
UIImage *checkImage = [UIImage imageNamed:#"check.png"];
UIButton *checkButton = [UIButton buttonWithType:UIButtonTypeCustom];
[checkButton setImage:checkImage forState:UIControlStateNormal];
cell.frame = CGRectMake(0, 0, cell.frame.size.width, cell.frame.size.height);
checkButton.frame = CGRectMake(10, 10, checkImage.size.width, checkImage.size.height);
[drawerView addSubview:checkButton];
[checkButton addTarget:nil action:#selector(onCheckMarkTap:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)onCheckMarkTap {
NSLog(#"Delete the cell");
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
}
}
This question already has an answer. You get the coordinates of the button that was tapped in the table view's coordinate system using target/action with an event or via a gesture recognizer, then use UITableView's method -indexPathForRowAtPoint: to get the indexPath of the cell containing the button at that point.
Within cellForRowAtIndexPath:
checkButton.tag = indexPath.row
Also inside onCheckMarkTap, do this:
- (void)onCheckMarkTap : (id) sender
{
if (sender.tag == 0)
///code
else if (sender.tag == 1)
///code
}
The way I handle problems like this in my own code is to subclass "UIButton", where I add in a "NSIndexPath" or "tableRow" ivar into the subclassed button. Let's name is "StangButton".
With a subclassed button, you can populate the "indexPath" ivar when you are composing the cell via "cellForRowAtIndexPath:".
Then, when the button is pressed, you'll know which button was pressed and which row it was in.
You can also check to see if the "tableView:didSelectRowAtIndexPath:" table view delegate method is called when the button is touched in the cell.
I have a UITableView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//Where we configure the cell in each row
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
self.myButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.myButton.tag = 5;
self.myButton.frame = CGRectMake(190.0f, 5.0f, 70.0f, 25.0f);
self.myButton.layer.borderColor = [UIColor blackColor].CGColor;
self.myButton.layer.borderWidth = 0.5f;
self.myButton.backgroundColor = [UIColor grayColor];
[self.myButton setTitle:#"Set Active" forState:UIControlStateNormal];
[self.myButton addTarget:self action:#selector(myButton:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview: self.myButton];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
-(void) myButton:(id)sender{
[sender setBackgroundColor:[UIColor redColor]];
}
Assume, there 3 rows in the tableview section. I have the button in 3 rows.
At the first instance, the button in the first row should have red color and the other 2 rows should have gray color.
If I select the button in the 2nd row, then the button in the 2nd row should be red and the other 2 gray and so on. I haven't figured out a way to do it. Any suggestions?
I am able to change the color of the button I have selected from cell. But at the same instance, the previously selected button and all the other buttons(except the selected button) should be default color. At a time only one button will be highlighted, and that will always be the selected button at that instance.
I think the right way to do this - subclass UITableViewCell and declare own protocol that will inform delegate in which cell button was pressed, and in the delegate - loop through all cells and set default color for all and red color for selected.
I made demo project
Easy way is set different tag for each button. Like this:
button.tag = indexPath.row + c;
when 'c' is constant.
And in you method:
-(void) myButton:(id)sender{
for( int i=0; i<numberOfRowsInTable; ++i )
[(UIButton *)[self.view viewForTag:i+c] setBackgroundColor:[UIColor grayColor]];
[(UIButton *)sender setBackgroundColor:[UIColor redColor]];
}
But if you have 2 or more section in table this way may be not work
Take a look at this: How can I loop through UITableView's cells?
Loop through the cells and set the "inactive" buttons to gray.
Just try this code:
-(void) myButton:(id)sender{
NSLog(#"sender Tag=== %d",[sender tag]);
UIButton *btn=(UIButton *)sender;
[btn setBackgroundColor:[UIColor redColor ]];
}
I have one doubt that how to get other control's value when we select a row or tap on button while having custom tableViewCell.
Suppose I have a TableView Cell with a TextField, a Slider and button. Button has action using:
btn.tag = indexPath.row;
[btn addTarget:self action:#selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
Now I can get button on its action method. I need to get textField's value and slider's value on button tap.
The one option is I create a array and store values for these two control in that array and manage this. But I don't think this is correct way to manage it.
Please navigate me to the currect way to get value of UITableViewCell's subview's value.
Thanks
While creating your textfield and slider, give them a constant tag and then add to cell's contentView
textfield.tag= TEXTFIELDTAG; //TEXTFIELDTAG = 100 or any other constant
[cell.contentView addSubview:textfield];
and then in your buttonTapped: method
-(void)buttonTapped:(id)sender
{
int row = ((UIButton*)sender).tag;
NSIndexPath* indexpath = [NSIndexPath indexPathForRow:row inSection:0]; // in case this row in in your first section
UITableViewCell* cell = [table cellForRowAtIndexPath:indexPath];
UITextField* textfield = [cell.contentView viewWithTag:TEXTFIELDTAG];
}
Whenever you create subviews (button , text field etc. ) for your UITableViewCell don't forget to tagged them.
myTextField.tag = 0;
myTextLabel.tag = 1;
[cell addSubview:myTextField];
[cell addSubview:myTextLabel];
Once you tagged, you could access them using below method.
- (UIView *)viewWithTag:(NSInteger)tag
When you select,you could get the subviews of your UITableViewCell's by using ViewWithTag function of UIView.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableview cellForRowAtIndexPath:indexPath];
UITextField* myTextField = [cell viewWithTag:0];
UILabel* myTextLabel = [cell viewWithTag:1];
}
Inside my cellForRowAtIndexPath method, I would like to dynamically create some buttons and place them next to each other in the cells. The problem I'm running into is that the sizeToFit method always puts the x coordinate at the 0 position. Is there a way to offset the position to put it next to the previous button?
Instead of this: . I get this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"cell"] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
if ([indexPath section] == 0) {
UIButton *buttonClean = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[buttonClean addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchDown];
[buttonClean setTitle:#"Clean Cup" forState:UIControlStateNormal];
[buttonClean sizeToFit];
[cell addSubview:buttonClean];
UIButton *buttonAroma = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[buttonAroma addTarget:self
action:#selector(aMethod:)
forControlEvents:UIControlEventTouchDown];
[buttonAroma setTitle:#"Aroma" forState:UIControlStateNormal];
[buttonAroma sizeToFit];
[cell addSubview:buttonAroma];
You should position UIViews by setting their frame property.
This is an option:
[buttonAroma setFrame:CGRectMake(buttonClean.frame.size.width,0,buttonAroma.frame.size.width,buttonAroma.frame.size.height)];
you should also add your views to the cell's contentView, instead of adding them to the cell directly:
[cell.contentView addSubview:buttonAroma];
See UIView's frame property here:
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/instp/UIView/frame
See UITableViewCell's contentView property here:
http://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewCell_Class/Reference/Reference.html#//apple_ref/occ/instp/UITableViewCell/contentView
.. where it says:
If you want to customize cells by
simply adding additional views, you
should add them to the content view so
they will be positioned appropriately
as the cell transitions into and out
of editing mode.
It's not the sizeToFit method that's putting them at y=0, it's the fact that you never set any other position. You can move each button by assigning its center or frame properties; for the latter, you would of course want to read out the property, modify just the origin of the CGRect, and set it back to the property so as to not mess up the sizing.
Little background, the table view is filled by a fetchedResultsController which fills the table view with Strings. Now I'm trying to add a button next to each String in each tableview cell. So far, I've been trying to create a button in my configureCell:atIndexPath method and then add that button as a subview to the table cell's content view, but for some reason the buttons do not show up. Below is the relevant code. If anyone wants more code posted, just ask and I'll put up whatever you want. Any help is greatly appreciated.
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
// get object that has the string that will be put in the table cell
Task *task = [fetchedResultsController objectAtIndexPath:indexPath];
//make button
UIButton *button = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
[button setTitle:#"Check" forState:UIControlStateNormal];
[button setTitle:#"Checked" forState:UIControlStateHighlighted];
//set the table cell text equal to the object's property
cell.textLabel.text = [task taskName];
//addbutton as a subview
[cell.contentView addSubview:button];
}
- (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] autorelease];
}
// Configure the cell.
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
Three comments:
You'll probably need to set the frame of your UIButton. Otherwise it doesn't know how big it's supposed to be and where it's supposed to be placed. It's possible that it comes with a default frame, but I haven't investigated that.
You're leaking your buttons. You don't need to retain after calling [UIButton buttonWithType:...];
You have the possibility of adding multiple buttons to the same cell. If you're reusing a cell, then you should first invoke removeFromSuperview each subview of cell.contentView .