Button not working in UITableViewCell subclass when it is a subview of a view inside the UITableViewCell - objective-c

I have a button in a tableView Cell that I need to respond to touch events. Normally this would easily be solved by
[cell.playButton addTarget:self action:#selector(playButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
inside of -tableView:cellForRowAtIndexPath:
The problem I am having is that my button is inside of a custom UITableViewCell subclass and is also the subview of a view that I am creating inside of that class..
for example:
UIView *view = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
self.theView = view;
[self addSubview:view];
[view release];
UIButton *playButton = [UIButton buttonWithType:UIButtonTypeCustom];
playButton.frame = CGRectMake(5, 5, 100, 30);
[playButton setImage:[UIImage imageNamed:#"button_playvid.png"] forState:UIControlStateNormal];
[playButton setImage:[UIImage imageNamed:#"button_playvid_active.png"] forState:UIControlStateHighlighted];
self.playButton = playButton;
[self.theView addSubview:playButton];
When the button is a subview of a view that I create within the custom UITableViewCell then the cell is highlighted instead of the button being pressed so the target that I setup in -tableView:cellForRowAtIndexPath is never called. Not sure why.. any help?
Thanks,
Joel
PS. I realize that there probably isn't a practical reason to create a background view exactly like this since there already is one. This is just example code that I'm using to explain a problem I'm having.. :D
Thanks for Looking!

The UIView you are adding is actually a UIImageView. From the docs:
New image view objects are configured to disregard user events by default. If you want to handle events in a custom subclass of UIImageView, you must explicitly change the value of the userInteractionEnabled property to YES after initializing the object.
I think that either userInteractionEnabled cascades to subviews or the superview will not pass the touch to its subviews in this case, so your button will not be receiving touches. Set your image view to have .userInteractionEnabled = YES and you should be fine.

I had the same problem and tried EVERYTHING. The thing that finally did it was implementing the method
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Just return whatever the height is of your custom cell (look in the NIB file)

Recently I've ran into such issue with legacy code. The reason was that earlier we used to add subviews to custom UITableViewCell instance itself and now we have to add to contentView of the cell instance.
I fixed it by changing:
addSubview(increaseButton)
to
contentView.addSubview(increaseButton)
Of course, isUserInteractionEnabled should be true.

Instead of button, you could try the same with an image. You could define which method to be called when the image is clicked.

Related

UIButton not showing up

I am trying to create a UIButton programmatically instead of using the interface builder. I initialize and set the button frame but the button doesn't seem to appear on the view. My code is as follows:
UIButton *showInfoButton = [[UIButton alloc] init];
CGRect buttonFrame = CGRectMake(0,0, 150, 150);
showInfoButton.frame = buttonFrame;
What am I missing? Please bear with me as I am new to iOS.
You forgot to add your UIButton as a subview to the UIView you want it to display on. Since you are building UI programmatically, you need to manually add the button as a subview to the container view.
You can do so by using this line of code:
[self.view addSubview:showInfoButton];
The button might not still appear as you are making a custom button which has a transparent background colour. In order to see the button, you can set the UIButton's backgroundColor property as follows:
[showInfoButton setBackgroundColor:[UIColor blackColor]];

UIButton inside UIView doesn't respond to touch events

I've put a UIButton inside a custom UIView and the button is not receiving any touch events (it doesn't get into the highlighted state, so my problem is not about being unable to wire up a touch inside up handler). I've tried both putting it into the XIB in Interface Builder, and also tried programatically adding the UIButton into the UIView seperately, both ended with no luck. All my views are inside a UIScrollView, so I first though UIScrollView may be blocking them, so I've also added a button programatically exactly the same way I add my custom view into UIScrollView, and the button worked, elimination the possibility of UIScrollView could be the cause. My View's hiearchy is like this:
The button is over the image view, and the front layer isn't occupying my button completely, so there's no reason for me not be physically interacting with the button. At my custom view's code side, I'm creating my view as such:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIView *sub = [[[NSBundle mainBundle] loadNibNamed:#"ProfileView" owner:self options:nil] objectAtIndex:0];
[self addSubview:sub];
[sub setUserInteractionEnabled:YES];
[self setUserInteractionEnabled:YES];
CALayer *layer = sub.layer;
layer.masksToBounds = YES;
layer.borderWidth = 5.0;
layer.borderColor = [UIColor whiteColor].CGColor;
layer.cornerRadius = 30.0;
/*layer.shadowOffset = CGSizeZero;
layer.shadowRadius = 20.0;
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowOpacity = 0.8;
*/
}
return self;
}
I've tried all combinations of setUserInteractionsEnabled, and had no luck. (Yes, also set them to checked in Interface Builder too). I've also read in another question with a similar problem that I should try overriding 'canBecomeFirstResponder' to return 'YES' and I've also done that too. But the problem persists, I can't click the button. I've not given any special properties, settings to the button, it's just a regular one. My other objects in the view (labels below, image view behind the button etc.) are working properly without problems. What could be possibly wrong here?
Thanks,
Can.
UPDATE: Here is a quick reproduction of the problem: https://dl.dropbox.com/u/79632924/Test.zip
Try to run and click the button.
Looking at the test project, I believe your problem in the way you create TestView, you do not specify the frame for it, so basically the parent view is 0 size, and the subviews you see from XIB extending out of the parent view and thus do not get anything in responder chain.
You should either specify the frame when creating TestView, or adjust the frame after loading XIB file.
I have had this problem as well. The cause for me was that the UIButton superview frame was of height 0, so I believe that even though a touch was happening, it was not being passed down to the button.
After making sure that the button's superview took a larger rectangle as a frame the button actions worked.
The root cause for this problem on my side was a faulty auto layout implementation (I forgot to set the height constraint for the button's superview).
I've found the solution. I was initializing my custom view as:
MyView *view = [[MyView alloc] init];
I've initialized it instead with a frame of my view's size, and it started responding to events:
CGRect rect = CGRectMake(0,0,width,height);
MyView *view = [[MyView alloc] initWithFrame:rect];
Storyboard Solution
Just for anyone wanting a solution to this when using storyboards and constraints.
Add a constraint between the superview (containing the button) and the UIButton with an equal heights constraint.
In my case, I had selected embed UIButton in a UIView with no inset on the storyboard. Adding the additional height constraint between the UIButton and the superview allowed the UIButton to respond to touches.
You can confirm the issue by starting the View Debugger and visually confirm that the superview of the UIButton is not selectable.
(Xcode 11, *- Should also work in earlier versions)

UITableViewCell Delete button screws up textLabel when using line break in text

I have a UITableViewCell, when swipe to bring up the Delete button it screws up the textLabel because I am using a line break in text.
Before:
In delete mode:
This is frustrating because I just want the delete button to go over my text, rather than trying to animate it out of the way which screws it up.
Why does this happen? Because I use a line break in my string?
How can I prevent this from happening?
Why does this happen? Because I use a line break in my string?
It happends because you've added the label to the contentView of the cell (which is good). When the delete button appears the contentView will be automatically resized and the UITableViewCell's textLabel will resize as well because it's autoresizingMask is set to UIViewAutoresizingFlexibleWidth. Unfortunately we cannot override the autoresizingMask of the default textLabel.
How can I prevent this from happening?
You'll have to build a custom cell yourself. Subclass UITableViewCell with a custom UILabel as a property and set it's autoresizingMask to UIViewAutoresizingNone.
//create and set your frame to whatever you want.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 110, 20)];
//set autoresizing
[label setAutoresizingMask:UIViewAutoresizingNone];
//add to view
[[self contentView] addSubview:label];
//set property to acces later
[self myLabel:label];
//release (if you aren't using ARC)
[myLabel release];
add some sample text to test it later on
[[cell myLabel] setText:#"MAX: 72.92 MPH Will fit!"];
If you're using interfacebuilder to create your view/cells make sure the autoresizing mask arrow's are grayed out.
You should be able to access the UITableViewCell's textLabel.Frame property. Subclass UITableViewCell and set this in [UITableViewCell didTransitionToState:(UITableViewCellStateMask)state]

Pointer to custom UIView on UITableViewCell returns 0

enter code hereI have a UITableViewCell, to which i have added a custom UIView which is actually a button. I have added the custom UIView programmatically, and set its .tag = 4. The code to draw the button and set the tag is being done in cellForRowAtIndexPath.
I have a function which receives notifications that events have happened, and in this function i am trying to get a pointer to the button in the UITableViewCell so i can change the text on the button, but when i try to retrieve the viewWithTag property, it keeps being returned as 0.
Any ideas?
This is how the button is added to the code:
CustomBadge *customBadge1 = [CustomBadge customBadgeWithString:[NSString stringWithFormat:#"%d", [plugin items]]<br>withStringColor:[UIColor whiteColor]
withInsetColor:[UIColor redColor]
withBadgeFrame:YES
withBadgeFrameColor:[UIColor whiteColor]
withScale:1.0
withShining:YES];
[customBadge1 setFrame:CGRectMake(cell.frame.size.width - 80, 10, 30, 25)];
customBadge1.tag = 4;
[cell addSubview:customBadge1];
Then in a delegate function, this is how i am trying to get a pointer to the button:
CustomBadge* itemBadge = (CustomBadge*) [[[pluginTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]] contentView] viewWithTag:4];
Does your tableview allow editing? At one point I noticed that iOS would assign its own views with low-numbered-tags when you switched into editing mode. It could be stealing your tag away... Try a high numbered tag, or use a custom UITableViewCell subclass and get an IBOutlet to the UIView (I always go for this option, it saves a lot of heartache down the line.)
Oh FFS.
I forgot the ".contentview" when i was adding the item to the cell subview.
Thanks to Melvin and jsd for the reponses.

EXC_BAD_ACCESS on button press for button dynamically added to UIView within UIScrollView

OK. It's an iPad app. Within the DetailViewController I have added a UIScrollView through IB and within that UIScrollView I have added a UIView (also added through IB) which holds various dynamically added UITableViews, UILabels and UIButtons.
My problem is that I'm getting errors on the UIButton clicks.
I have defined this method:
- (void)translationSearch:(id)sender {
NSLog(#"in transearch");
[self doSearch];
}
This is how I'm adding the UIButton to the UIView:
UIButton *translationButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
translationButton.frame = CGRectMake(6, 200, 200, 20);
translationButton.backgroundColor = [UIColor clearColor];
[translationButton setTitle:#"testing" forState:UIControlStateNormal];
[translationButton addTarget:self action:#selector(translationSearch:) forControlEvents:UIControlEventTouchUpInside];
[verbView addSubview:translationButton];
Now the button is added to the form without any issue but, when I press it, I am getting an EXC_BAD_ACCESS error. I'm sure it's staring me in the face but I've passed my usual time limit for getting a bug like this fixed so any help would be greatly appreciated. The only thing I can think is the fact that the UIButton is within a UIView which is within a UIScrollView which is within the view controller is somehow causing an issue.
Cheers.
Thanks Maz. I have just done that and I have to admit that my assumption about where the error was coming from was wrong. It was a new bit of code, just not the button method call.
Grant me the "dunce" award for this one.