I've did lots of tests and searches and still couldn't find why the UIButton that I added into a UITableViewCell.contentView won't work. I can guarantee I did everything right, the button still won't answer the TouchUpInside event.
code like this won't work:
[self.contentView addSubview:theButton];
But this would work:
[self addSubview:theButton];
As you may expected, self was a subclass of UITableViewCell. and recording to the doc, shouldn't we always add things to contentView?
Sorry for my poor English. I hope I described it clearly.
try this code in cellForRowAtIndexPath method
UIButton *scanQRCodeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
scanQRCodeButton.frame = CGRectMake(260.0f, 6.0f, 45.0f, 25.0f);
scanQRCodeButton.backgroundColor = [UIColor whiteColor];
[scanQRCodeButton setTitle:#"button" forState:UIControlStateNormal];
[cell.contentView addSubview:scanQRCodeButton];
it will work.
if your UITableViewCell has a customer height(not the default 44.0f)。
if so, you should set the code like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
cell.contentView.frame = CGRectMake(0, 0, tableView.width, [self tableView:tableView heightForRowAtIndexPath:indexPath]);
// add a UIButton that you create
}
return cell;
}
the reason for this problem is the cell.contentView.size is default (320.f, 44.0f), if your button is over the rect, then the button could not accept the event, so you should set the cell.contentView.frame yourself, like i do the code。
Good Luck。
Related
I got a really weird problem with a custom UITableViewCell. Btw, i am using an UIViewController. So, i crafted the cell in Storyboard (like in the image bellow) and i set it's class to my custom UITableViewCell class. Then I created all the IBOutlets and IBActions in the custom cell class.
My cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[PostTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
[cell setCellContentWithPost:[PostsArray objectAtIndex:indexPath.row]];
return cell;
}
My custom UITableViewCell class:
#import "PostTableViewCell.h"
#implementation PostTableViewCell
- (void)setCellContentWithPost:(SDPost*)post {
self.alpha = 0.f;
self.postTitleLabel.text = post.title;
[self.thumbnailImageView sd_setImageWithURL:[NSURL URLWithString:post.thumbnailURL] placeholderImage:nil options:SDWebImageHandleCookies];
[UIView animateWithDuration:0.35 animations:^{
self.alpha = 1.0f;
}];
}
-(void)awakeFromNib{
self.postTitleLabel.textColor = [UIColor whiteColor];
self.postTitleLabel.font = [UIFont fontWithName:#"Montserrat-Regular" size:16.5];
self.readingTimeView.backgroundColor = [UIColor colorWithRed:0.33 green:0.74 blue:0.15 alpha:1];
self.readingTimeView.layer.cornerRadius = 4;
self.readingTimeLabel.textColor = [UIColor whiteColor];
self.readingTimeLabel.font = [UIFont fontWithName:#"Montserrat-Bold" size:11.75];
self.commentsCountView.backgroundColor = [UIColor colorWithRed:0.74 green:0.19 blue:0.4 alpha:1];
self.commentsCountView.layer.cornerRadius = 4;
self.commentsCountLabel.textColor = [UIColor whiteColor];
self.commentsCountLabel.font = [UIFont fontWithName:#"Montserrat-Bold" size:11.75];
}
I tried to style the cell from the initWithStyle method of the UITableViewCell, but for some reason it never gets called, so i ended up doing this in awakeFromNib.
So, the problem is: I think i am doing something wrong, because as you can see in this GIF (https://dl.dropboxusercontent.com/s/6crcjbmitr5fmk7/Untitled%20%281%29.gif?m=), the heart button it get's automatically turned on/off as i scroll through the cells.
Can anyone of you guys help me fix this ? Thanks a lot!
Each time the cell is displayed it takes value from your PostsArray array. So when you click on the heart, you should update its corresponding object in the array.
That happens because you have the same CellIdentifier for all your cells, which is fine in this case if you are very careful on how you are handling the "heart" element.
You should have a way to determine which elements on the cell have been "liked". As I suppose you need to know on which elements your user pressed the heart button.
When initialising/reusing your cell you need to be sure that the heart button is set properly to "red/on" or "white/off".
For instance :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
PostTableViewCell *cell = (PostTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[PostTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell setHeartState:[[AnArray objectAtIndex:indexPath.row] hasBeenLikedByUser]]
[cell setCellContentWithPost:[PostsArray objectAtIndex:indexPath.row]];
return cell;
}
It is just a quick draft.
Hope that helps
I managed to solve this by checking if the hearth should be filled or not. I stored the post id using NSUserDefaults and in setCellContentWithPost i added an if statement that checks if the cell's post is favorited.
Thanks for interest guys!
Hi I realize that this question has been asked before. I tried the previous solutions however to no avail unfortunately. What I am trying to do is to get my UISwitch to appear and not duplicate itself when scrolling on the table view. This is my current attempt however the UISwitch is not being displayed at all. Any help as to what I am doing wrong would be greatly appreciated!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"RestaurantCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
Restaurant *restaurant = [restaurants objectAtIndex:indexPath.row];
UISwitch *notificationSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(245, 15, 79, 27)];
[notificationSwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:notificationSwitch];
cell.textLabel.text = restaurant.name;
cell.detailTextLabel.text = restaurant.hours;
return cell;
}
What I am trying to do is to get my UISwitch to appear and not duplicate itself when scrolling on the table view
It seems you want one UISwitch to appear in all of the cells.
To address this issue, instead of creating the object in the -cellForRowAtIndexPath, you should move this code into -viewDidLoad and simply put this object on the resusable cells later.
Basically...
This should be in your -viewDidLoad:
//IMPORTANT: declare "UISwitch *notificationSwitch;" in the .h of this class
notificationSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(245, 15, 79, 27)];
[notificationSwitch addTarget:self
action:#selector(switchChanged:)
forControlEvents:UIControlEventValueChanged];
and only this should be left in your -cellForRowAtIndexPath
[cell.contentView addSubview:notificationSwitch];
thus we create the object just once and add the same object to the cell multiple times instead of creating multiple objects in the -cellForRowAtIndexPath (that only look the same but are infact different objects)
PS: I have assumed that your delegate and datasource are hooked up properly, i.e. the execution flow does reach-cellForRowAtIndexPath
Try to use this code instead of my static text you will put your text.It is working for me!
You can see the structure of cell Attached Image
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"CellIdentifer";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
}
UISwitch *notificationSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(150, 5, 79, 27)];
[notificationSwitch addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[cell.contentView addSubview:notificationSwitch];
cell.textLabel.text = [NSString stringWithFormat:#"text label %d",indexPath.row];
cell.detailTextLabel.text =[NSString stringWithFormat:#"detail label %d",indexPath.row] ;
return cell;
}
I'm trying to to something like apple's alarm clock, when tap the edit button, a custom view cover the custom UITableViewCell.
The code above:
// CGRect frame = [tableView rectForRowAtIndexPath:indexPath];
// CGPoint yOffset = self.tableViewBlock.contentOffset;
// CGRect newFrame = CGRectMake(frame.origin.x, (frame.origin.y - yOffset.y + 45), frame.size.width, frame.size.height);
CallBlock_Date_EditMode *viewController = [[CallBlock_Date_EditMode alloc] initWithNibName:#"CallBlock_Date_EditMode" bundle:nil];
// self.view.frame = newFrame;
// [self.view addSubview:viewController.view];
// [self addChildViewController:viewController];
UITableViewCell *cell = (UITableViewCell*)[self.tableViewBlock cellForRowAtIndexPath:indexPath];
[cell.contentView addSubview:viewController.view];
Cover the specific cell when I put in under:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Just to make sure the size is ok (although when I tap a button in that xib the app crash without even a single error).
But I want to do like apple's alarm clock (actually, mimic it), tap my edit button and my custom UITableViewCell will get cover with this xib as a view.
Maybe there is a better approach to do it?
EDIT:
My updated code is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
CallBlock_TableCell *cell = (CallBlock_TableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[CallBlock_TableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(CallBlock_TableCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
cell.accessoryType = self.isEditing ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
CallBlock_ByDate *callBlock = (CallBlock_ByDate*)[fetchedObjects objectAtIndex:indexPath.row];
cell.labelTime.text = callBlock.startDate;
cell.labelRepeat.text = callBlock.repeat;
cell.labelTextLabel.text = callBlock.label;
cell.switchCallBlock.on = YES;
cell.switchCallBlock.tag = (NSInteger)indexPath.row +1;
[cell.switchCallBlock addTarget:self action:#selector(handleSwitch:) forControlEvents:UIControlEventValueChanged];
cell.switchCallBlock.hidden = self.isEditing ? YES : NO;
if (self.isEditing)
{
cell.switchCallBlock.hidden = YES;
UIButton *btnArrow = [[UIButton alloc] init];
btnArrow.frame = CGRectMake(282.0, 31.0, 18.0, 21.0);
[btnArrow setBackgroundImage:[UIImage imageNamed:#"arrow_FWR_off"] forState:UIControlStateNormal];
[btnArrow setBackgroundImage:[UIImage imageNamed:#"arrow_FWR_on"] forState:UIControlStateHighlighted];
btnArrow = [UIButton buttonWithType:UIButtonTypeCustom];
[btnArrow addTarget:self action:#selector(handleTapToEdit:) forControlEvents:UIControlEventTouchUpInside];
btnArrow.tag = indexPath.row + 1;
[cell.contentView addSubview:btnArrow];
[cell.contentView bringSubviewToFront:btnArrow];
}
}
But I cannot get the btnArrow appear on the UTableView.
The reason you are getting a crash is because nothing is retaining your CallBlock_Date_EditMode view controller. You add its view to your cell as a subview, but nothing maintains a reference to the view controller, so it is deallocated and then, when pressing a button that is supposed to pass a message to your view controller, it is sent to a deallocated object and you get a crash.
There are two possible solutions to this. First, you could store that view controller in one of your properties to maintain a reference to it so that it does not deallocated. This is, for the most part, probably not what you want.
Instead, what I would suggest doing is do not make your CallBlock_Date_EditMode a UIViewController, but instead make it a UIView. You may be wondering "But how can I use a xib without a UIViewController?". I would do something like the following:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
UIView *view = [[[NSBundle mainBundle] loadNibNamed:#"CallBlock_Date_EditMode" owner:self options:nil] objectAtIndex:0];
self.myEditButton = (UIButton *)[view viewWithTag:2];
[self addSubview:view];
}
return self;
}
This would be code inside your custom UIView that would load in a xib file and add it as a subview. In order to get access to your subviews, you have to use tags inside interface builder, so you do lose the convenience of drawing/connecting IBOutlets... But in the end, it is much better than allocating/storing a bunch of unnecessary UIViewControllers.
If I understand you right and you want to mimic the functionality of the alarm clock that comes pre-installed from Apple, your solution is much simpler than creating a custom view. It looks like all they do is set the On-Off switches to hidden and add a disclosure indicator to the cell. This is what I would do...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
bool hide = (tableView.editingStyle == UITableViewCellEditingStyleDelete); // set to true or false depending on if the table is in editing mode
for (UIView *sv in [cell subviews] ) {
if([sv isKindOfClass:[UISwitch class]]) { // find the on-off switch
[sv setHidden:hide]; // hide the switch depending on the t/f value of hide
break;
}
}
if(hide) { // adds the arrow like in apple's alarm clock table if the cell is in edit mode
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;
}
I created custom cells for my table. Basically my cells have UIButton on them. I am reusing those cells.
However i have trouble with those buttons, because when cells is reused then all it's elements also is reused but i am seeking that these Button will be unique to every cells.
Maybe someone could propose a solution for this functionality ?
How about this if you have a property button on your custom cell?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath static NSString *CellIdentifier = #"My Cell Identifier";
MyCustomCellClass *cell = (MyCustomCellClass *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyCustomCellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
UIButton *myButtonForThisCell = [MyButtonArray objectAtIndex:indexPath.row];
cell.button = myButtonForThisCell;
return cell;
}
create a buttonView UIVIEW file with two methods as
-(NSInteger) getGridIndex
{
return gridIndex;
}
-(void) setGridIndex:(NSInteger)value
{
gridIndex = value;
}
Now in cellforrowatindexpath method
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
ButtonView *buttonView=[[ButtonView alloc] initWithFrame:CGRectMake(110, 110, 160, 26)];
buttonView.tag=18;
UIButton *button=[[UIButton alloc]initWithFrame:CGRectMake(55, 0, 60, 26)];
[button addTarget:self action:#selector(ButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[buttonView addSubview:button];
[cell addSubview:buttonView];
}
ButtonView *buttonView=(ButtonView*)[cell viewWithTag:18];
NSArray *d=[buttonView subviews];
UIButton *button=[d objectAtIndex:0];
//here you can change the setting or title of button or whatever u want to do.
[buttonView setGridIndex:indexPath.row];
}
Now in button action :
-(void)ButtonAction:(UIButton*)sender{
ButtonView *view = (ButtonView *)[sender superview];
NSInteger n=[view getGridIndex];
//here n is the indexpath.row at which the button was tapped..you can write its action accordingly.
}
I have a custom cell in TableView and there is a button in the cell. When I select the cell, the background turns to blue and the button disappears. Is there any way to prevent this?
The cellForRowAtIndexPath like this -
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
MyTableCell *cell = (MyTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[MyTableCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
Search *current = [self.retrievedTweets objectAtIndex:indexPath.row];
cell.textLabel.text = current.text;
cell.textLabel.font = [UIFont systemFontOfSize:15.0];
cell.textLabel.numberOfLines = 2;
cell.detailTextLabel.text = current.name;
cell.imageView.image = current.userImage;
btnUncheck =[[UIButton alloc] initWithFrame:CGRectMake(400, 35, 20, 20)];
btnUncheck.backgroundColor = [UIColor redColor];
btnUncheck.layer.cornerRadius = 10;
btnUncheck.hidden =NO;
btnUncheck.tag=indexPath.row;
//[btnUncheck addTarget:self action:#selector(didSelectRowAtIndexPath:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:btnUncheck];
return cell;
}
use custom image for selected table cell. or try with buttons images.
paste below line in your tableview Delegate Method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
///// your code ///////////
cell.selectionStyle=UITableViewCellSelectionStyleNone;
//// your code////////
}
here your blue backgound will not display..
What you can do is this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{[tableView deselectRowAtIndexPath:indexPath animated:YES];}
Hope this helps
Also, if you have already implemented this, what else do you have in this delegate method?
Instead of this line:
btnUncheck = [[UIButton alloc] initWithFrame:CGRectMake(400, 35, 20, 20)];
use:
btnUncheck = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
[btnUncheck setFrame:CGRectMake(400, 35, 20, 20)];
Create a "custom" view with background color clear and set to it.
UIView* vista=[[[UIView alloc] init] autorelease];
vista.backgroundColor=[UIColor clearColor];
cell.selectedBackgroundView=vista;
The way to fix this right, is to create a custom cell that you then add a button to in the xib editor.
So, in xib editor, add a 'UITableViewCell' item. Then add the button to that cell item in the xib editor. You'll then attach your custom cell to the table in the corresponding .m file here:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I have tried this out with just a one row table and the custom cell tied as a property from the xib to the .h file that has the table view. The highlight is there and just grays out the button (still viewable). To get this to work with more rows is more involved. You'll need to load the custom utableviewcell xib and alloc your custom cell dynamically for that to work.