Objective C > UITableViewCell button not depressing - objective-c

I have the following button being created in the cellForRowAtIndexPath section for this tableView:
UIButton *sched_button_a1 = [UIButton buttonWithType:UIButtonTypeCustom];
sched_button_a1.frame = CGRectMake(0, 0, 110, 52);
CGRect frame_a1 = sched_button_a1.frame;
// Resize height based on length of appointment
frame_a1.size.height = heightCalc;
sched_button_a1.frame = frame_a1;
[sched_button_a1 addTarget:self action:#selector(showAppointment:) forControlEvents:UIControlEventTouchUpInside];
[sched_button_a1 setTitle:[NSString stringWithFormat:#"APPT: %#", APPT_ID ] forState:UIControlStateNormal];
sched_button_a1.layer.backgroundColor = [UIColor redColor].CGColor;
[sched_a1 addSubview:sched_button_a1];
As you can see it's calling showAppointment which is presently just:
-(void)showAppointment:(UIButton*)sender {
NSLog(#"Button pushed");
}
showAppointment is also defined here:
-(void)showAppointment:(UIButton*)sender;
The button shows up fine and gets the correct text and background and appears to be in the foreground, however, when I click on it nothing happens and it doesn't look like the button even gets depressed.
What am I doing wrong or missing?
Edit: I have gone back and removed the sched_a1 view so that the button is directly created in the contentView and this had no effect. It still appears that the only gesture being recognized is the one used to scroll the table. Tapping the button does not appear to change the color of the text or otherwise indicate that the button has been pressed and no log entry is created.
Edit 2: Added cellForRowAtIndexPath to paste bin
http://pastebin.com/WXezfW96

I had a similar issue recently, which I struggled to understand. The solution I came up with was to set the bounds of the button as well and also check for UIControlEventTouchDown rather than UIControlEventTouchUpInside.

Have you tried using cancelsTouchesInView? If you added tap gesture, I think the tap gesture or the tap in table cell overrides the touches in your button. Try using this code:
UIGestureRecognizer *tap= [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(yourAction)];
tap.cancelsTouchesInView = NO;
tap.delegate = self;
[yourButton addGestureRecognizer:tap];
But don't forget to add <UIGestureRecognizerDelegate> in your .h file
But I agree on Mike. Make it short and simple when creating table cell. I think you can use custom cell subclass and xib file.
I'm also new to objective C so if I say something wrong I'm sorry, I'm just trying to help.

UIButton *sched_button_a1 = [UIButton buttonWithType:UIButtonTypeCustom];
in this change UIButtonTypeCustom to UIButtonTypeRoundedRect

Scott, you may want to try my famous troubleshooting technique:
Determine whether the button or the action is the root cause:
UIImage *image = [UIImage imageNamed:#"image.png"];
[button setBackgroundImage:image forState:UIControlStateHighlighted|UIControlStateSelected]
Instead of:
-(void)showAppointment:(UIButton*)sender {
try
-(void)showAppointment:(id*)sender {
Use breakpoints.
If none of the above works consider refactoring your code that looks a bit messy.

Hey i have checked the code you wrote, it is working fine. Can you check if you have written similar to the code below in your cellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Identifier = #"Identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:Identifier];
}
UIButton *sched_button_a1 = [UIButton buttonWithType:UIButtonTypeCustom];
sched_button_a1.frame = CGRectMake(0, 0, 110, 52);
CGRect frame_a1 = sched_button_a1.frame;
[sched_button_a1 addTarget:self action:#selector(showAppointment:) forControlEvents:UIControlEventTouchUpInside];
[sched_button_a1 setTitle:#"Your Text" forState:UIControlStateNormal];
sched_button_a1.layer.backgroundColor = [UIColor redColor].CGColor;
[cell.contentView addSubview:sched_button_a1];
return cell;
}
I was not able to debug further as you have not kept your entire cellForRowAtIndexPath code. Hope this could help you to solve your problem

Since you are using a button type of UIButtonTypeCustom, you will need to set the attributes for UIControlStateHighlighted and UIControlStateSelected so that you achieve the effect you want for appearing to press the button.
You can change the title color or the background image for the highlighted and selected states using one of the following UIButton methods:
- (void)setTitleColor:(UIColor *)color forState:(UIControlState)state
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state
As an additional note regarding the code in the cellForRowAtIndexPath, you shouldn't be getting the data from sql in the method it would be destructive to your table view performance, get all the data you need before and have them stored in object in an array and then in the cellForRowAtIndexPath method you would just update the values labels from the object for the row.

Related

Touch UITableView background while scrolling (Kind of an easter egg)

I need to do a hidden button at the bottom of the table view, not in a cell, in the background of the table view itself.
I saw something like this in a game "Where is my water", if you scroll out of bounds you can find a hidden button.
first, I created a simple button, and placed in the bottom of the table view
self.tableView.backgroundColor = [UIColor purpleColor]; //just to see better
UIButton *venom = [[UIButton alloc] initWithFrame:CGRectMake(50.0, self.tableView.contentSize.height+80.0, 100.0, 40.0)];
venom.backgroundColor = [UIColor redColor];
[venom addTarget:self action:#selector(venomAction) forControlEvents:UIControlEventTouchDown];
[self.tableView addSubview:venom];
Because of the self.tableView.contentSize.height+80.0, I need to scroll out of the bounds of the table view to see the button, having something like this:
The result is correct, I want this to be sort of hidden, but the problem is, I cannot click on the button, to see the button, I need to be scrolling and I cannot multitouch.
Can anyone assist me with that? or point me to the right direction
I'd make the button not the tableView's subview, but rather a sibling view above the tableView.
For example, your code could look like this
- (void)viewDidLoad {
[super viewDidLoad];
// Just creating a simple UITableView
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
tableView.dataSource = self;
tableView.delegate = self;
self.tableView = tableView;
[self.view addSubview:tableView];
// Creating the Easter Egg Button
UIButton *easterEggButton = [UIButton buttonWithType:UIButtonTypeSystem];
[easterEggButton setTitle:#"Easter Egg Button" forState:UIControlStateNormal];
[easterEggButton addTarget:self
action:#selector(easterEggButtonPressed)
forControlEvents:UIControlEventTouchUpInside];
self.easterEggButton = easterEggButton;
// NOTE that we add the Easter Egg Button to self.view over the Table View, not into Table View
[self.view addSubview:easterEggButton];
}
So we have the button placed over the tableView. This detaches it from interfering with tableView's gestureRecognizer.
Now you need some code to adjust the button's frame to be placed somewhere under the tableView's last cell. It may look something like this:
- (void)updateButtonFrame {
UIButton *button = self.easterEggButton;
// Just the easiest way calculate the width and height of the button depending on it's content
[button sizeToFit];
CGRect frame = button.bounds;
// Now, we want to place the button under all the cells
frame.origin.y = self.tableView.contentSize.height;
frame.origin.y += 60.0f; // add some padding to place it even lower
/* We have calculated button's frame in tableView's coordinate space, so we need to convert it to
* button superview's coordinate space. */
frame = [self.tableView convertRect:frame toView:button.superview];
// And finally apply the frame to the button
button.frame = frame;
}
And of course you need to call this layout method in appropriate moments, that is, whenever tableView reloads it's data (because contentSize may change), and whenever tableView scrolls.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
/* Button resides in self.view and is unaware of Table View scrolling, so we need to update
* it's frame whenever Table View's content offset changes */
[self updateButtonFrame];
}
You may also call it viewDidLayoutSubviews to be safe if tableView's cell height depends on screen orientation and such.
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// It's safe to recalculate button's frame whenever self.view layout updates
[self updateButtonFrame];
}
You may have a look at this example implementation
https://gist.github.com/bartekchlebek/429906e05fcbd976291d

Weird behaviour of UIButton with tintColor on enabled/disabled states

UPDATE:
Even UIBarButtonItems do not respond to state change, visually.
The scenario:
I have a UIButton of type UIButtonTypeSystem initialized as below:
sendButton = [UIButton buttonWithType:UIButtonTypeSystem];
sendButton.backgroundColor = [UIColor clearColor];
[sendButton setTintColor:UIColorFromRGB(SEND_BUTTON_COLOR)];
sendButton.opaque = YES;
sendButton.clearsContextBeforeDrawing = NO;
sendButton.frame = CGRectMake(275, 6, 50, 35);
UIImage* sendImage = [UIImage imageNamed:#"toilet_paper"];
[sendButton setImage:[UIImage imageWithCGImage:sendImage.CGImage scale:sendImage.scale orientation:UIImageOrientationLeft]
forState:UIControlStateNormal];
sendButton.enabled = NO;
[sendButton addTarget:self action:#selector(post) forControlEvents:UIControlEventTouchUpInside];
The Purpose:
It is associated with a UITextView such that it is set to enabled if there is some text in the textView AND my host is available (checked through Reachability) and it's enabled property is changed in textViewDidChange: delegate method with the following:
sendButton.enabled = [APP_DELEGATE hostAvailable] && [myTextView.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" \n"]].length > 0;
According to this enabled state, the button must toggle between SEND_BUTTON_COLOR (enabled = YES) and grayColor (enabled = NO).
The Problem:
Up until now, the code used to work fine. It was gray when there was no text in the textView and it became SEND_BUTTON_COLOR as soon as there was some text in the textView. However, out of the blue, it has stopped this behaviour. What happens is, it stays gray all the time irrespective of the content of the textView. Once it is pressed, it becomes SEND_BUTTON_COLOR and stays that way, again irrespective of the textView text.
How do I regain the behaviour of the button I used to have on my UIButton?
You have to set your button's tint color again in the textViewDidChange delegate method.
In your delegate where you are setting the enabled state:
sendButton.enabled = [APP_DELEGATE hostAvailable] && [myTextView.text stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#" \n"]].length > 0;
if(sendButton.enabled){
[sendButton setTintColor:UIColorFromRGB(SEND_BUTTON_COLOR)];
}
else{
//Set Another Color For Disabled State
}
As it appears, the problem was on my part. I had subclassed UIButton in the .m file of a different VC (not imported by the VC in question, or any other VCs it had imported):
#implementation UIButton (Border)
- (void) setEnabled:(BOOL)enabled {
if (enabled) {
self.layer.borderColor = UIColorFromRGB(0x888888).CGColor;
} else {
self.layer.borderColor = UIColorFromRGB(0xdddddd).CGColor;
}
[super setEnabled:enabled];
[self setNeedsDisplay];
}
#end
Somehow, this interfered with my button. After weeks of further subclassing, changing images, changing titles, etc, I was able to diagnose the issue (accidentally) by jumping to definition (CMD + Click) of the enabled method, and it took me straight to the source of the issue (the subclass code). Commented it out, and voila. Things were back to normal.
I hope this helps someone in the future who faces the same issue (or makes the same mistake I did).

refresh the uitableview contents

I have added uitableview in which I am trying to add custom UIButton. It is added successfully with this code:
image=[UIButton buttonWithType:UIButtonTypeCustom];
image.frame=CGRectMake(240, 7, 25, 25);
image.tag=101;
image2=[UIButton buttonWithType:UIButtonTypeCustom];
image2.frame=CGRectMake(240, 7, 25, 25);
image2.tag=102;
if ([outputlabel.text isEqualToString:#"Yes"]||[outputlabel.text isEqualToString:#"Yes"]) {
[image setImage:[UIImage imageNamed:#"tick.png"] forState:UIControlStateNormal];
[cell1.contentView addSubview:image];
[cell1.contentView bringSubviewToFront:image];
}
else
{
[image2 setImage:[UIImage imageNamed:#"cross.png"] forState:UIControlStateNormal];
[cell1.contentView addSubview:image2];
[cell1.contentView bringSubviewToFront:image2];
}
Its working fine at first. When table view reload it overlaps the uibutton old image. I am unable to refresh the whole table with new values. Someone has an idea what I am doing wrong in code.
Updated. Always Create content view for cell in cell == nil block. Use that contentview outside by the tag.. Then only it wont overlap and reuse ur cell perfectly..
if (cell == nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIndentifier];
//Add your button here.. set the tag.
UIButton image=[UIButton buttonWithType:UIButtonTypeCustom];
image.frame=CGRectMake(240, 7, 25, 25);
image.tag=101;
}
UIButton *btn = (UIButton *)[cell.contentView viewWithTag:101];
if ([outputlabel.text isEqualToString:#"Yes"]||[outputlabel.text isEqualToString:#"Yes"])
{
[btn setImage:[UIImage imageNamed:#"tick.png"] forState:UIControlStateNormal];
}
else
{
[btn setImage:[UIImage imageNamed:#"cross.png"] forState:UIControlStateNormal];
}
Just do like this in cellForRowAtIndexPath.. It will helpful for you..
Basically, if we want to refersh the contents of tableview then need to use this reloadData. Did you try :-
[yourTableView reloadData];
Make sure you implement -cellForRowAtIndexPath:. Then refresh your tableViewCells by calling reloadRowsAtIndexPaths:withRowAnimation: on the tableView in question.
The tableView will in turn call cellForRowAtIndexPath, and you simply return the configured cells there.
If you have static cells, you can simply access whatever you need to change by hooking the controls up to an IBOutlet.
Try refreshing your cell's view using
[cell1.contentView setNeedsDisplay:TRUE];
every time you set the image.
I am suspecting, that you adding this images in -tableView:cellForRawAtIndexPath: method.
First of all - if you reusing cell with some reuse identifier, the Cell will stay in memory and will reused when it needed. It's means that all subviews of your cell will be retained. In this case you need to prepare cell for reusing every time. For example - remove all subViews of cell.
But better way, I recommend in case of less number of operations - to create subclass of UITableViewCell and add UIButton as a property of that cell.
Then you will only need to change this property depend of your condition.
if ([outputlabel.text isEqualToString:#"Yes"]) {
[cell1.button setImage:[UIImage imageNamed:#"tick.png"] forState:UIControlStateNormal];
}
else
{
[cell1.image setImage:[UIImage imageNamed:#"cross.png"] forState:UIControlStateNormal];
}
Of course, you button must be added in cell.contentView in the Cell initialiser. Usually it is method -initWithStyle:reuseIdentifier: of your custom cell .m file.

one button in each section of uiTableView objective-C

I have a uitableview and in my table I have different section and in each section different rows,I want to add one button in last row of each sections
I used sectionFooter, and here is my code, but I don't know why I have it just in my last section of table and also it's not appear with scroll.
Here is my code:
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 50;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
if(footerView == nil) {
footerView = [[UIView alloc] init];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
// [button setBackgroundImage:image forState:UIControlStateNormal];
//the button should be as big as a table view cell
[button setFrame:CGRectMake(10, 3, 300, 44)];
//set title, font size and font color
[button setTitle:#"Report New Time" forState:UIControlStateNormal];
[button.titleLabel setFont:[UIFont boldSystemFontOfSize:20]];
[button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
//set action of the button
[button addTarget:self action:#selector(removeAction:)
forControlEvents:UIControlEventTouchUpInside];
//add the button to the view
[footerView addSubview:button];
}
//return the view for the footer
return footerView;
}
what is wrong here, Would you please help me!
Thanks in advance!
You need to remove the if statement in your tableView:viewForFooterInSection: method. That's causing only one view to be created.
One UIView has to have only one superview. You have to create footerView for every section.
You are reusing the footerView for every section, partly by just keeping one footerView instance variable, partly by just creating it once. Every time UITableView asks you for a footer view for a section and it gets back the same view, that view is moved since it can't stay in all those places at the same time. The solution is to not use a single view.
Use an NSMutableDictionary to hold NSNumbers with the section number as key and the appropriate footer view as the value. Change the code to work with the section's "slot" in the dictionary instead of a single instance variable.

Objective C: UITable Method "didSelectRowAtIndexPath" does not work if label is added to cell

In my implementation, I had to add a custom label to the cell. However, I realize that by doing so, the cell area that is covered by the custom label will not react to the user's 'click' and hence will not trigger the method "didSelectRowAtIndexPath".
CustomOHAttributLabel *questionLabel = [[CustomOHAttributLabel alloc]initWithFrame:CGRectMake(10, (60-labelHeight)/2, 280, labelHeight)];
[cell.contentView addSubview:questionLabel];
Is there a way to allow the whole cell area to be responsive to the user's touch even after adding a Custom label to it?
Make a custom button and put that over the lavel and onClick call the same code, see this
CustomOHAttributLabel *questionLabel = [[CustomOHAttributLabel alloc]initWithFrame:CGRectMake(10, (60-labelHeight)/2, 280, labelHeight)];
UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];
btn.frame=CGRectMake(10, (60-labelHeight)/2, 280, labelHeight);
[btn addTarget:self action:#selector(doSomeThing) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:questionLabel];
[cell.contentView addSubview:btn];
-(void)doSomeThing
{
//write code which you write in didSelectRowAtIndexPath method
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self doSomeThing];
}