I have a subview within UITableViewCell's that contains a UILabel and a UIButton. When I push the button it unselects the UITableViewCell for some reason.
Is there a way to pass the touch event through to its super view? Or is there a different problem all together?
Here is the code for CellForRowAtIndexPath. I plan on creating a custom subclass of UITableViewCell so I can handle cell reuse properly so don't feel the need to mention that.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CountModel *cellModel = self.viewModel.data[indexPath.row];
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"RootViewControllerMetricCell"];
cell.textLabel.text = cellModel.title;
// Custom background color for selection
UIView *bgColorView = [[UIView alloc] init];
bgColorView.backgroundColor = UIColorFromRGB(0xF3F3F3);
bgColorView.layer.masksToBounds = YES;
[cell setSelectedBackgroundView:bgColorView];
// Construct subview and append to bottom (only visible when selected)
UIView *cellSubView = [[UIView alloc] initWithFrame:CGRectMake(0, 125, cell.frame.size.width, 25)];
// UILabel for display of current count
UILabel *lblCount = [[UILabel alloc] initWithFrame:CGRectMake(15, 0, 25, 25)];
lblCount.text = [NSString stringWithFormat:#"%d", [cellModel.count intValue]];
// Create UIButton for incrementing
UIButton *incrementButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
incrementButton.frame = CGRectMake(45, 0, 25, 25);
[incrementButton setTitle:#"+" forState:UIControlStateNormal];
// Enable touch event for button view
[incrementButton addTarget:self action:#selector(countButtonTouchDown:) forControlEvents:UIControlEventTouchDown];
[cellSubView addSubview:lblCount];
[cellSubView addSubview:incrementButton];
[cell addSubview:cellSubView];
return cell;
}
How about you add the [self.tableView cellForRowAtIndePath:] setSelected:] inside the function responding to the button press to reinstate the same selected/ deselected state.
UPDATE:
Shift the code inside the didSelectCellAtIndexPath to another function, say performActionOnSelectionOfCellAtIndexPath and call performActionOnSelectionOfCellAtIndexPath from inside the didSelectCellAtIndexPath with the indexPath and also call performActionOnSelectionOfCellAtIndexPath from the function responding to the button press.
Related
Hi i am a newbie to iOS.
I have implemented a tableview in ViewController1.In the tableview i am displaying tittle,detailText and disclosure indicator for the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:MyIdentifier];
}
cell.textLabel.text =[listTableArray objectAtIndex:indexPath.row];
cell.textLabel.textColor=[UIColor grayColor];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.detailTextLabel.text=#"4mile";
return cell;
}
Everything works fine,Now i need a image before the disclosure indicator when i do it with
UIImageView *accessoryView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
accessoryView.image=[UIImage imageNamed:#"list.png"];
cell.accessoryView = accessoryView;
Disclosure indicator is replaced by the image.But i need both image along with disclosure indicator without using Custom cell.
How can i do it...? Help me out.
Thanks
similiar to the due date but at the place of time i need image
UITableViewCell have a fixed layout, depending on the style you use when you initialize it. You cannot change that layout, since the cell lays out its subviews as it prefers to have them.
add the - (void)layoutSubviews to your cell subclass like this:
- (void)layoutSubviews {
[super layoutSubviews];
self.imageView.frame = CGRectMake(0.0f , 0.0f, 20.0f, 20.0f);
}
else try this
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = [UIImage imageNamed:#"list.png"];;
[imageView setFrame:CGRectMake(50, 5, 20, 20)]; // customize the frame
[cell.contentView addSubview:imageView];
If you wanna add UIImageView to standard UITableViewCell you need add your imageView to contentView of cell and add all subviews like a textLabel, detailTextLabel and accessoryView
UIImageView *accessoryImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
accessoryImageView.image=[UIImage imageNamed:#"list.png"];
[cell.contentView addSubview:accessoryImageView];
or subclass of UITableViewCell and implement all views inside it
I'm experiencing a problem with regards to adding a button to a tableview cell. Basically, I'm adding a button to a specific cell, but that button also appears on random other cells (not currently in the view).
When I tap a cell, I set a variable (tappedCell=indexPath), and reload that cell. In my cellForRowAtIndexPath I check if the indexPath is equal to the tappedCell, and if it is I add a button to it. That works, but this button also appears on other cells further down in the tableView. These cells are not in the view when I tap it, but further down, so I have to scroll to see them. If I keep scrolling up and down (quickly), more and more cells with buttons appears. This seems to be completely random.
I've tried adding a NSLog() inside the if-statement where I add the button, but this is not called more than once (when I tap the original cell). So it's actually not adding more buttons, it has to be the same one appearing in multiple cells.
I have no idea why this is happening. I've tried adding a button to every cell, and then just set hidden = YES as standard, and hidden = NO when the [self.tappedCell isEqual:indexPath], but this does not change anything...
Here you can see the code I use to add the button to my cell:
UIButton *newBtn=[UIButton buttonWithType:UIButtonTypeCustom];
[newBtn setImage:[UIImage imageNamed:#"open.png"] forState:UIControlStateNormal];
[newBtn setFrame:CGRectMake(220, 0, 100, 86)];
[newBtn addTarget:self action:#selector(openImage:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:newBtn];
I don't know what I'm doing wrong, or if I am doing something wrong at all. It's worth mentioning that I'm using a standard Apple/iOS style=subtitle cell, and not a custom one. This is to keep it consistent throughout my app (The cells are made in the storyboard, and I'm reusing a prototype cell).
Could anyone give me any insight on why it's behaving like it does, and how I can fix it?
Thanks in advance!
EDIT 1:
Here's my full code for cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Set up the item
XYZItem *item = [self.itemsInView objectAtIndex:indexPath.row];
NSString *CellIdentifier = #"itemPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = item.itemName;
if ([self.selectedItem isEqual:indexPath])
{
cell.textLabel.numberOfLines = 2;
UIButton *newBtn=[UIButton buttonWithType:UIButtonTypeCustom];
[newBtn setImage:[UIImage imageNamed:#"open.png"] forState:UIControlStateNormal];
[newBtn setFrame:CGRectMake(220, 0, 100, 86)];
[newBtn addTarget:self action:#selector(openImage:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:newBtn];
}
NSString *detailTextLabelText = [NSString stringWithFormat:#"%lu subitems", (unsigned long)[item.subItems count]];
cell.detailTextLabel.text = detailTextLabelText;
return cell;
}
The button is showing up on cells that have reused a button that previously added it.
There are a few options here.
Make the button part of every cell. Set it's .hidden property every time you create/reuse one to the appropriate value.
Remove the button in the cell's prepareForReuse method.
Assuming self.tappedCell is a UITableViewCell subclass and indexPath is an index path, [self.tappedCell isEqual:indexPath] will always return NO
I faced same issue and i also had multiple headers:
The solution is:
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
headerLabel = [[UILabel alloc] initWithFrame:
CGRectMake(15, 5, self.tableView.frame.size.width, 15.0)];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.textAlignment = NSTextAlignmentLeft;
[headerLabel setFont:[UIFont fontWithName:#"Helvetica Neue Medium" size:13.0]];
headerLabel.tag = 1002;
[cell.contentView addSubview:headerLabel];
button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, HEIGHTROW)];
[button addTarget:self action:#selector(eventAddAlert) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundImage:[UIImage imageNamed:#"add_manually.png"] forState:UIControlStateNormal];
button.hidden = YES;
button.tag = 1001;
[cell.contentView addSubview:button];
}else{
// use viewWithTag to find lblNombre in the re-usable cell.contentView
headerLabel = (UILabel *)[cell.contentView viewWithTag:1002];
button = (UIButton *)[cell.contentView viewWithTag:1001];
}
if(indexPath.section == 0 && indexPath.row == 0){
button.hidden = NO;
}else{
button.hidden = YES;
.........
}
.........
I have seen and checked multiple questions regarding adding an UIButton to a UITableViewCell but somehow I did not manage to find the exact problem that I am facing. When adding an UIButton to an UITableViewCell, the cell's text label overlaps with the button. The button is in the beginning of the row and it should be followed by the text label. I am most probably doing something wrong, but I can not find what. Here is my code for cellForRowAtIndex:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell=[self._tableView dequeueReusableCellWithIdentifier:#"event"];
Event* event =[self eventForIndexPath:indexPath];
if(cell==nil)
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"event"];
[[cell textLabel] setText:event.customer.name];
if(event.startTime!=nil)
[[cell detailTextLabel] setText:event.startTime];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
UIButton *cellButton =(UIButton*) [cell.contentView viewWithTag:CELL_BUTTON_TAG];
if(cellButton == nil){
UIButton *cellButton = [UIButton buttonWithType:UIButtonTypeCustom];
cellButton.tag=CELL_BUTTON_TAG;
[cellButton setFrame:CGRectMake(0.0f, 0.0f, 44.0f, cell.frame.size.height)];
[cellButton setImage:[UIImage imageNamed:#"van_green.png"] forState:UIControlStateNormal];
[cellButton setImage:[UIImage imageNamed:#"location.png"]forState:UIControlStateSelected];
[cellButton addTarget:self action:#selector(carButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
cellButton.layer.borderWidth = 0.0;
[cell.contentView addSubview:cellButton];
}
return cell;
}
Sorry but your code is completely wrong..you are using an incorrect way and also you are adding a button each time.
The tableViewCell are REUSED so you have to add buttons and other UI elements just when you INIT the cell and not each time, or your app will finish in memory warning, crash, not fluid etc.
The correct way to do what you want to do is create your CustomTableViewCell subclassing the class UITableViewCell and add your labels and buttons. It is really simple:
1) Create a new file CustomSearchCell object that extends UITableViewCell:
CustomSearchCell.h
#import <UIKit/UIKit.h>
#interface CustomSearchCell : UITableViewCell
#property (strong, nonatomic) UIButton *button;
#property (strong, nonatomic) UILabel *lblDetails;
#end
CustomSearchCell.m
#import "CustomSearchCell.h"
#implementation CustomSearchCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
_lblDetails = [[UILabel alloc] initWithFrame:CGRectMake(100, 10, 200, 45)];
[_lblDetails setFont:[UIFont systemFontOfSize:20.0]];
[_lblDetails setTextColor:[UIColor blackColor]];
_button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 44, self.frame.size.height)];
[self.contentView addSubview: _lblDetails];
[self.contentView addSubview: _button];
}
return self;
}
#end
2) In your view controller:
#import "CustomSearchCell.h"
and:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ListCellIdentifier";
CustomSearchCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[CustomSearchCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//Settings
return cell;
}
Another your problem is when you press the button. You will receive the sender but the tableViewCell will can be used for a different indexPath when you intercept the touch..be careful..the correct way is another..you need to save in some way the actual indexPath when you press the button...
Problem is in this line [cell.contentView addSubview:cellButton];. When your cell going to be reuse, the cell already contains cell button, and you try to add that button again. Just do the below step to resolve this issue.
1) Add button tag to take from base view.
UIButton *cellButton = [UIButton buttonWithType:UIButtonTypeCustom];
cellButton.tag = CELLBUTTONTAG;
2) Check condition view tag and add it to base view as below.
UIButton *cellButton = [cell.contentView viewWithTag:CELLBUTTONTAG];
if(cellButton == nil)
{
UIButton *cellButton = [UIButton buttonWithType:UIButtonTypeCustom];
cellButton.tag = CELLBUTTONTAG;
...
[cell.contentView addSubview:cellButton];
}
You have given cellbutton's y position as 0.0f.That's y overlapping. try to change some value as you need.
[cellButton setFrame:CGRectMake(0.0f, 0.0f, 44.0f, cell.frame.size.height)];
to
[cellButton setFrame:CGRectMake(0.0f, some big value, 44.0f, cell.frame.size.height)];
I don't see why this would matter, but I'm having some trouble getting it to work.
Disclaimer: This is my first iOS app (or ANY Apple development for that matter, and the app needs to be done yesterday, so excuse any rushed-looking code please).
I'm using the SWRevealViewController library to create a Facebook-esque "side view" when a button on the home view navigation controller is clicked. It works great, love it. This view holds a UITableView with only two static cells, and I just received a request to add a cell to the very bottom of the view.
It didn't seem obvious to try to get that third cell "in" the UITableView, so in my xib I just created a UITableViewCell outside of the UITableView, and put it at the bottom of the view. It then hooked it up to my controller using the standard IBOutlet workflow.
Back in my viewDidLoad I skinned the rogue cell to look like the rest of the tablecells, added some wording, added a handler to make it open up my company's website when clicked, and all of that works fine. I did all of this stuff for the "regular" table cells in my tableView:cellForRowAtIndexPath function.
BUT for some reason when I click on the cell, it's not being highlighted like my other regular cells when I click on it! Why!
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];
} else {
[[cell.contentView viewWithTag:1] removeFromSuperview];
}
UILabel *lblView = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 3.0, 187.0, cell.frame.size.height)];
[lblView setFont:[UIFont fontWithName:#"FuturaStd-Bold" size:12]];
lblView.textColor = [UIColor colorWithRed:(255/255.f) green:(241/255.f) blue:(204/255.f) alpha:1.0];
lblView.tag = 1;
if (indexPath.row == 0){
[lblView setText:#"SCHEDULE"];
} else if (indexPath.row == 1){
[lblView setText:#"SPEAKERS"];
}
lblView.backgroundColor=[UIColor clearColor];
[cell.contentView addSubview:lblView];
UIImageView *av = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 277, 58)];
av.backgroundColor = [UIColor clearColor];
av.opaque = NO;
av.image = [UIImage imageNamed:#"blackBar.png"];
cell.backgroundView = av;
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:(240/255.f) green:(145/255.f) blue:(62/255.f) alpha:1.0]];
[cell setSelectedBackgroundView:bgColorView];
return cell;
}
The above code works fine for my "regular cells". That last bit before I return the cell is what sets the background highlight a weird orange color when it's "being clicked".
The code below is the SAME THING but in my viewDidLoad, and it's not setting the background highlight color when being clicked.
- (void)viewDidLoad
{
[super viewDidLoad];
//... stuff
UILabel *lblView = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 3.0, 187.0, _roguecell.frame.size.height)];
[lblView setFont:[UIFont fontWithName:#"FuturaStd-Bold" size:12]];
lblView.textColor = [UIColor colorWithRed:(255/255.f) green:(241/255.f) blue:(204/255.f) alpha:1.0];
[lblView setText:#"IT'S A SECRET LOL"];
lblView.backgroundColor=[UIColor clearColor];
[_roguecell.contentView addSubview:lblView];
UIImageView *av = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 277, 58)];
av.backgroundColor = [UIColor clearColor];
av.opaque = NO;
av.image = [UIImage imageNamed:#"blackBar.png"];
_roguecell.backgroundView = av;
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:(240/255.f) green:(145/255.f) blue:(62/255.f) alpha:1.0]];
[_roguecell setSelectedBackgroundView:bgColorView];
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[_roguecell addGestureRecognizer:singleFingerTap];
}
Maybe it has something to do with my xib file I have the UITableView extending down the entire view, and the rogue UITableViewCell "on top" of it (but not in it obviously). I tried messing around with the locations of the table and the cell, but that didn't do anything.
Thanks for reading.
I ended up removing my rogue UITableViewCell, and upping the total number of cells in my UITableView from 2 to 4. The 3rd cell I removed my custom background from, didn't add any text to, disabled user interaction from, and set the height using the - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath method to fill up the rest of the table leaving only enough room at the bottom for my "footer" cell.
I not find a solution to modify my custom cell since a button which is inside. I will wish to change the label text when I click the 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:nil];
}
// View
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 250)];
[view setBackgroundColor:[UIColor colorWithWhite:255.0 alpha:0.0]];
// Label
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320-7-7, 16)];
[label setText:#"Hello"];
[label setTextAlignment:UITextAlignmentLeft];
[label setTextColor:[UIColor grayColor]];
[label setFont:[UIFont fontWithName:#"HelveticaNeue-Bold" size:16]];
[label setBackgroundColor:[UIColor clearColor]];
[view addSubview:label];
// Action
UIButton *action = [[UIButton alloc] initWithFrame:CGRectMake(306-54, 0, 54, 54)];
[action setTitle:#"0" forState:UIControlStateNormal];
[action addTarget:self action:#selector(actionMore:) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:action];
// Add view to cell
[cell addSubview:view];
return cell;
}
Edit (add details)
- (void)actionMore:(id)sender{
UIButton *button = (UIButton *)sender;
// Edit current cell, but I do not know how...
}
Thanks.
You can get the cell in which the button was pressed with following lines of code
UITableViewCell * cell = (UITableViewCell*)[[sender superview] superview];
Then use the cell reference to change the label text
cell.yourlabel.text = #"New Text";
Update
I think the above code may not work in iOS 7. The better way is
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.mainTable];
NSIndexPath *indexPath = [self.mainTable indexPathForRowAtPoint:buttonPosition];
Since your UIButton and UILabel are subviews of the same view, you can tag your label, and use viewWithTag to find it from your button's action code:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320-7-7, 16)];
label.tag = 1234;
....
- (void)actionMore:(id)sender{
UIButton *button = (UIButton *)sender;
UILabel *label = [[sender superview] viewWithTag:1234];
// Edit current cell
}
To help you need to give some more details.
Is this a single cell or is it a prototype for multiple?
The code in the actionMore: selector.
What are you trying to do this for? Why a button in a cell to change the label text?
If this cell is being used more than once, a problem could be actionMore: can't isolate which cell is the target for the code. Also you could have a simple typo in the actionMore method but we can't solve that without being able to see all of the interacting code.
If you can provide more details, some one may be able to help. I will edit this answer if I can help you once I have more information.
--EDIT--
First to get cell you can use:
UITableViewCell * cell = (UITableViewCell*)[[sender superview] superview];
Then you can access your cells label by:
cell.label.text = #"Some Text Here";
Your next issue is figuring out where in the list your cell lies. For that use this code:
UITableView * table = (UITableView*)[[[sender superview] superview] superview];
NSIndexPath * indexPath = [table indexPathForCell: cell];
You then can then use a switch statement or if-else statements to find which row was triggered.
- (void)actionMore:(id)sender{
UITableViewCell * cell = (UITableViewCell*)[[sender superview] superview];
UIView *view = [cell.subviews objectAtIndex:0];
UILabel *label = [view.subviews objectAtIndex:0];
[label setText:#"test"];
}
you better add view as a subview of the contentview
pass the indexpath to actionMore or fetch it from there. once you got the indexpath, you are in business.
you may want to set a tag for your textlabel for fetching it from its superview.