UIButton in a subview not response to touch events with objective-c - ios

I want to create a bottom tab that could change the view when user press.
To do that I create a view with view controller and sets it's frame in the init
Here is the bottom panel view controller
#implementation BottomTabViewController
-(id) initWithFrame:(CGRect)frame{
if(self = [super init]){
self.view.frame = frame;
return self;
}else{
return nil;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setUpButtons];
// Do any additional setup after loading the view.
}
-(void) featureBtnClick:(id*) sender{
NSLog(#"featureBtn Clicked");
}
-(void) favBtnClick:(id*)sender{
NSLog(#"Fav Btn Clicked");
}
-(void) setUpButtons{
UIButton *features = [[UIButton alloc]initWithFrame:CGRectMake(10, 10, 50, 50)];
[features setBackgroundImage:[UIImage imageNamed:#"feature.png"] forState:UIControlStateNormal];
features.backgroundColor = [UIColor greenColor];
[features addTarget:self action:#selector(featureBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:features];
UIButton *favBtn = [[UIButton alloc]initWithFrame:CGRectMake([[UIScreen mainScreen]bounds].size.width - 100, 10, 50, 50)];
[favBtn setBackgroundImage:[UIImage imageNamed:#"favorite.png"] forState:UIControlStateNormal];
[favBtn addTarget:self action:#selector(favBtnClick:) forControlEvents:UIControlEventTouchUpInside];
favBtn.backgroundColor = [UIColor greenColor];
[self.view addSubview:favBtn];
}
#end
And I added that to my view with code like this:
-(void) setUpBottom{
BottomTabViewController *botm = [[BottomTabViewController alloc]initWithFrame:CGRectMake(0, [[UIScreen mainScreen] bounds].size.height - 55, [[UIScreen mainScreen]bounds].size.width, 55)];
botm.view.backgroundColor = [UIColor redColor];
// botm.view.userInteractionEnabled = false;
botm.view.userInteractionEnabled = true;
[self.view addSubview:botm.view];
}
Here here is the result seems, note the bottom panel that works, well pretty silly, but it shows up:
But when press the left and right button, there is not log printed which it expected to be to indict that the button works, What have I done wrong? Thanks

you are adding buttons in the view first then adding the bottom view.
if this is what you are doing then it can be overlapped by the bottom view.
In this case buttons cant be tapped because they have bottom view on top of them.
so make sure u add bottom view first then your buttons. (or change their frames to avoid overlapping)

Related

Can't touch UIButton in UIScrollView

I am programmatically creating buttons in a view inside UIScrollView. I also have programmatically created UITextField. I can select and enter data into the text fields all day long. But I cannot get any sign the buttons are being touched. I can add them to the main view and they work. But when added to the view inside the UIScrollView, they are lost in another dimension. I've read plenty of info about setting userInteraction, delayContentTouches, and intercepting via gestureRecognizer. The last might be related to my problem. I return NO via [touch.view isDescendantOfView:self.myScrollViewName]. I can't get it to trigger via [touch.view isKindOfClass:[UIButton class]]. Which makes me think I have a more fundamental error I am missing?
related:
https://stackoverflow.com/a/6825839/4050489
edited to add button code per request:
self.myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
self.myButton.frame = myButtonFrame;
self.myButton.enabled = interface.isActive;
self.myButton.userInteractionEnabled = YES;
self.myButton.exclusiveTouch = YES;
self.myButton.backgroundColor = [UIColor greenColor];
//self.myButton. = YES;
self.myButton.layer.borderWidth=1.0f;
self.myButton.layer.borderColor=[[UIColor blackColor] CGColor];
self.myButton.layer.cornerRadius = 10;
[self.myButton setTag:interface.tag];
[self.myButton setTitle:interface.Name forState:UIControlStateNormal];
[self.myButton addTarget:self action:#selector(navigatePartButtons:) forControlEvents:UIControlEventTouchUpInside];
[self.myButton setEnabled:YES]; //error check
[self.partSetupView addSubview:self.myButton];
partSetupView is a UIView in the UIScrollView.
Try this sample Code:
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *myScroll = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 100, 300, 300)];
myScroll.backgroundColor = [UIColor redColor];
[self.view addSubview:myScroll];
UIView *myView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 300, 200)];
myView.backgroundColor = [UIColor yellowColor];
[myScroll addSubview:myView];
UIButton *myButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 300, 100)];
myButton.backgroundColor = [UIColor blackColor];
[myView addSubview:myButton];
[myButton addTarget:self action:#selector(btnClick) forControlEvents:UIControlEventTouchDown];
}
-(void)btnClick{
NSLog(#"Button Click");
}
#end

Why the sender not called when I click the image of the button in Objective-C?

I am new to IOS and Objective-C , and I try to set Image for a UIButton.
Wen I click the button , the button will change image1. If I click the button one again , it will change to image2
First, I set the image in Viewdidload like the following code.
#interface AITPreviewViewController ()
{
VLCMediaPlayer *mediaPlayer ;
BOOL recording ;
BOOL recordMode;
}
- (void)viewDidLoad
{
recordMode = YES;
UIButton *modeChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 450, 60, 60)];
[modeChangeButton setBackgroundImage:[UIImage imageNamed:#"recordmode.PNG"] forState:UIControlStateNormal];
[self.view addSubview:modeChangeButton];
}
When I click the button , the button will change the image. The code is like the following:
- (IBAction)modeButtonClick:(id)sender {
NSLog(#"modeButtonClick..!!!!!!");
if (recordMode == YES) {
NSLog(#"modeButtonClick..%hhd = " , recordMode);
[self.modeChangeButton setBackgroundImage:[UIImage imageNamed:#"photomode.png"] forState:UIControlStateNormal];
recordMode = NO;
}else if (recordMode == NO){
NSLog(#"modeButtonClick..%hhd = " , recordMode);
[self.modeChangeButton setBackgroundImage:[UIImage imageNamed:#"recordmode.png"] forState:UIControlStateNormal];
recordMode = YES;
}
}
When I click the image on the button , the image of the button become dark in color. It seems the button has been press. But the - (IBAction)modeButtonClick:(id)sender didn't called.
When I click the blank space (the side of image) , the button has been press. The - (IBAction)modeButtonClick:(id)sender has been called. And the image also change to other image.
I am sure I have set action in header file and .m file.
The above describe is like the following picture.
It seems the button is cover by image , and the image and the button is not the same.
Why this happened ??
How to solve this problem ?
Thanks in advance.
Couple of changes that you could implement:
First:
Change the setBackgroundImage to setImage.
For example: [self.modeChangeButton setImage: [UIImage imageNamed: #"recordmode.png" forControlState: UIControlStateNormal];
That way, if you have set an image to the button by mistake, this will overwrite it.
Second:
Make sure you have connected your reference outlets (IBOutlet) and actions (IBActions) in Interface builder - whether XIB files, or storyboard. If you don't link the the interface objects there to those in your code, they won't work.
Third:
If it still does not work, try adding this line to your viewDidLoad
[self.modeChangeButton addTarget:self #selector(modeButtonClick:) forControlEvents:UIControlEventTouchUpInside];
Fourth:
Change this line in your viewDidLoad:
UIButton *modeChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 450, 60, 60)];
to:
self.modeChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 450, 60, 60)];
This should solve your problem.
This code is adding a new button on top of your self.modeChangeButton which I'm assuming is coming from a xib or storyboard.
- (void)viewDidLoad
{
recordMode = YES;
UIButton *modeChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 450, 60, 60)];
[modeChangeButton setBackgroundImage:[UIImage imageNamed:#"recordmode.PNG"] forState:UIControlStateNormal];
[self.view addSubview:modeChangeButton];
}
Do this instead...
- (void)viewDidLoad {
self.recordMode = YES;
}
- (void)setRecordMode:(BOOL)recordMode {
_recordMode = recordMode;
UIImage *imageForMode = recordMode ? [UIImage imageNamed:#"photomode.png"] : [UIImage imageNamed:#"recordmode.png"];
[self.modeChangeButton setBackgroundImage:imageForMode forState:UIControlStateNormal];
}
- (IBAction)modeButtonClick:(id)sender {
self.recordMode = !self.recordMode;
}
Check your button size and make the frame size closer to the image size. And try to maintain the two images as like below.
- (void)viewDidLoad
{
UIButton *modeChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 450, 60, 60)];
[modeChangeButton setImage:[UIImage imageNamed:#"recordmode.PNG"] forState:UIControlStateNormal];
[modeChangeButton setImage:[UIImage imageNamed:#"photomode.png"] forState:UIControlStateSelected];
[modeChangeButton addTarget:self action:#selector(modeButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:modeChangeButton];
}
- (IBAction)modeButtonClick:(id)sender
{
sender.selected = !sender.selected;
}
Try modifying you viewDidLoad method as follows.
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *modeChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 300, 60, 60)];
[modeChangeButton setBackgroundImage:[UIImage imageNamed:#"recordmode.PNG"] forState:UIControlStateNormal];
// You might need to add following two lines into your code.
[modeChangeButton addTarget:self action:#selector(modeButtonClick:) forControlEvents:UIControlEventTouchUpInside];
self.modeChangeButton = modeChangeButton;
[self.view addSubview:modeChangeButton];
}
Above solution should work. As I see, you have referencing property named modeChangeButton in your modeButtonClick: method. But you are not assigning the created button into your property. Also you have to set the action selector to your button.
As a improvement, you can do this to improve performance of your application. Without setting the background image on click event, you can select/deselect the button. With this you don't need to maintain boolean flags, which may introduce new bugs to your application.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *modeChangeButton = [[UIButton alloc] initWithFrame:CGRectMake(200, 300, 60, 60)];
[modeChangeButton setBackgroundImage:[UIImage imageNamed:#"recordmode.png"] forState:UIControlStateNormal];
[modeChangeButton setBackgroundImage:[UIImage imageNamed:#"photomode.png"] forState:UIControlStateSelected];
[modeChangeButton addTarget:self action:#selector(modeButtonClick:) forControlEvents:UIControlEventTouchUpInside];
self.modeChangeButton = modeChangeButton;
[self.view addSubview:modeChangeButton];
}
- (IBAction)modeButtonClick:(id)sender {
NSLog(#"modeButtonClick..!!!!!!");
[self.modeChangeButton setSelected:![self.modeChangeButton isSelected]];
}
Hope this helps.

adding multiple subviews in ios

I'm trying to add multiple subview programmatically, but my buttons inside those subviews are not working. The buttons were also added as subviews programmatically.
Here's the code, hopefully will explain more about what I mean.
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
[self setBackgroundColor:[UIColor clearColor]];
// UIView container of selected image with comment button.
UIView *containerOfSelectedImage = [[UIView alloc] initWithFrame:CGRectMake(0, 20, 0, 350)];
NSLog(#"%f", self.frame.size.width);
// image view of selected photo by user.
UIImageView *userImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"nature_01.jpg"]];
[userImage setFrame :CGRectMake(0, 0, 340, 300)];
// comment button with action of recodering user's comment.
UIButton *commentButton = [UIButton buttonWithType:UIButtonTypeCustom];
//[commentButton setBackgroundColor : [UIColor clearColor]];
float y = userImage.frame.size.height + 5.0f;
[commentButton setFrame : CGRectMake(32.0f, y, 24.0f, 24.0f)];
[commentButton addTarget:self action:#selector(audioRecordAction) forControlEvents:UIControlEventTouchDown];
[commentButton setImage:[UIImage imageNamed:#"comments-24.png"] forState:UIControlStateNormal];
[containerOfSelectedImage addSubview:userImage];
[containerOfSelectedImage addSubview:commentButton];
[self addSubview:containerOfSelectedImage];
[self addSubView:self.commentContainerView];
return self;
You need to increase the frame of the containerOfSelectedImage. Currently the width is 0.
The containerOfSelectedImage's frame has to be big enough so the button fits inside it. If the button is outside that frame it will show up but you can't touch him.
To debug this issues you can use a tool like Reveal App. If any of your buttons is outside the frame of the parent then the touch will not be detected.
Change [commentButton addTarget:self action:#selector(audioRecordAction) forControlEvents:UIControlEventTouchDown]; to [commentButton addTarget:self action:#selector(audioRecordAction) forControlEvents:UIControlEventTouchUpInside];

Drawing a line between two UIlabels when tapped or pressed together

I want to draw a line between two UILabels when i tap or hold both of them at the same time with code, i have no idea how to do this, it will be most appreciated if anyone has an advice , it will be most appreciated
This is how I would do it. My answer is tested btw...
To manage the tappable labels I would create my own label called LabelControl that extends UIControl. This custom control is going to have a UILabel (read-only for simplicity) as a subview. By doing this we will be able to add the Target-Action events UIControlEventTouchDown and UIControlEventTouchUpInside.
Here is the custom label:
The .h file:
#interface LabelControl : UIControl
#property (nonatomic, retain, readonly) UILabel *theLabel;
#end
The .m file:
#implementation LabelControl
#synthesize theLabel = _theLabel;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_theLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
_theLabel.backgroundColor = [UIColor clearColor];
_theLabel.userInteractionEnabled = NO;
[self addSubview:_theLabel];
}
return self;
}
-(void)dealloc {
[_theLabel release];
[super dealloc];
}
Then for the "line" that you want to draw, I would use a UIView because that way you could just use it's hidden property to hide/show the line. Add this code inside your ViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.label1 = [[[LabelControl alloc] initWithFrame:CGRectMake(60, 50, 200, 40)] autorelease];
self.label1.theLabel.text = #"Hello";
self.label1.userInteractionEnabled = YES;
self.label1.backgroundColor = [UIColor blueColor];
[self.label1 addTarget:self action:#selector(touchDown:) forControlEvents:UIControlEventTouchDown];
[self.label1 addTarget:self action:#selector(touchUp:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.label1];
self.label2 = [[[LabelControl alloc] initWithFrame:CGRectMake(60, 150, 200, 40)] autorelease];
self.label2.theLabel.text = #"World";
self.label2.userInteractionEnabled = YES;
self.label2.backgroundColor = [UIColor purpleColor];
[self.label2 addTarget:self action:#selector(touchDown:) forControlEvents:UIControlEventTouchDown];
[self.label2 addTarget:self action:#selector(touchUp:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.label2];
//the position of the line is hard-coded. You will have to modify this yourself
self.theLine = [[UIView alloc] initWithFrame:CGRectMake(60, 120, 200, 3)];
self.theLine.backgroundColor = [UIColor blueColor];
self.theLine.hidden = YES;
[self.view addSubview:self.theLine];
}
-(void)showOrHideLine {
if (self.label1.selected && self.label2.selected) {
NSLog(#"Both are selected");
self.theLine.hidden = NO;
} else {
self.theLine.hidden = YES;
}
}
-(void)touchDown:(id)sender {
//When any of the custom label gets the touch down event set the `selected` property
//to YES. (This property is inherited form `UIControl`
NSLog(#"Touch down");
LabelControl *labelControl = (LabelControl*)sender;
labelControl.selected = YES;
[self showOrHideLine];
}
-(void)touchUp:(id)sender {
//When any of the custom label gets the touch up event set the `selected` property
//to NO. (This property is inherited form `UIControl`
NSLog(#"Touch Up");
LabelControl *labelControl = (LabelControl*)sender;
labelControl.selected = NO;
[self showOrHideLine];
}
Let me know if you have any questions. Hope this helps!
I am going to outline it and give you some code (untested) but you have some work to make the full effect work.
Programtically, you could subclass UIButton. Inside your new subclass, put your touch recognition methods. Call it something like "customUIButton".
From your main view controller, create two instances of your UIButton and add them as subviews
customUIButton *Label1 = [[customUIButton alloc] init];
[Label1 setTitle:#"Your First Label" forState:UIControlStateNormal];
[Label1 addTarget:self action:#selector(itemClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:Label1];
customUIButton *Label2 = [[customUIButton alloc] init];
[Label2 setTitle:#"Your Second Label" forState:UIControlStateNormal];
[Label2 addTarget:self action:#selector(itemClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:Label1];
When you push the buttons, it will try to call the method "itemClicked". Make that method and receive (id)sender... - (void)itemClicked: (id)sender { Put some logic in there to indicate that the button is being pushed. You know which button by referring to the sender that was sent.
Also in your view controller, go to the DrawRect method and put in the drawing logic.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 3.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, Label1.center.x, Label1.center.y);
CGContextAddLineToPoint(context, Label2.center.x, Label2.center.y);
CGContextStrokePath(context);
CGContextRestoreGState(context);
Put this in an "if statement" so that if both buttons have focus, it will be drawn (else skip the drawing code).
How about placing a line in IB using an Image View. Hide the Image View in your viewDidLoad method. Then, whenever the user taps one of the the UILabels, unhide the Image View holding your line. It may be tricky depending on your experience with Objective-C to detect touches on a UILabel. If it is, you can place invisible buttons over each label and that should do the trick for you. For more info about detecting touches on UILabels, check this link:
Handling Touch Event in UILabel and hooking it up to an IBAction

scroll view + segment button +iOS

I have 2 scroll views. I put many buttons onto the first scroll view. When I click one button in the first scroll view, related buttons fill the second scroll view.
I want the buttons in the first scroll view to have the effect as if they are segment control. i.e. when one button is clicked, its image becomes dim and can't be clicked again until other buttons in the first scroll vew are clicked.
How to achieve this? any sample code is appreciated! thanks!
Can't you just keep track of which button was last clicked, and reset that one to be in the active state, and set the one you're now clicking to the inactive state? Just create a property, lastClicked, and do this:
-(IBAction) buttonClicked:(UIButton *)sender {
[self.lastClicked setUserInteractionEnabled:YES];
[self.lastClicked setImage:[UIImage imageNamed:#"enabledImage"] forState:UIControlStateNormal];
[sender setUserInteractionEnabled:NO];
[sender setImage:[UIImage imageNamed:#"disabledImage"] forState:UIControlStateNormal];
self.lastClicked = sender;
}
Try adding a segmented control inside a scroll view.
- (void)viewDidLoad
{
[super viewDidLoad];
journals = [[NSMutableArray alloc]init];
self.tableView.dataSource = self;
self.tableView.delegate = self;
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 49, 320, 29)];
self.segmentedControl.frame = CGRectMake(0, 0, 640, 29);
scrollView.contentSize = CGSizeMake(self.segmentedControl.frame.size.width, self.segmentedControl.frame.size.height -1);
scrollView.showsHorizontalScrollIndicator = NO;
self.segmentedControl.selectedSegmentIndex = 0;
[scrollView addSubview:self.segmentedControl];
[self.view addSubview:scrollView];
[self fillJournals];
// Do any additional setup after loading the view, typically from a nib.
}
Super simple, very ugly, but it works. You could optimize this out further by having it check the image and the interaction state of the button, so you aren't setting an image every time this loops through.
-(void) buttonClicked:(UIButton *)sender {
for (UIButton *btn in self.scrollView.subviews) {
if ([sender isKindOfClass:[UIButton class]]) {
if (btn == sender) {
[btn setUserInteractionEnabled:NO];
[btn setImage:[UIImage imageNamed:#"disabledImage"] forState:UIControlStateNormal];
} else {
[btn setUserInteractionEnabled:YES];
[btn setImage:[UIImage imageNamed:#"enabledImage"] forState:UIControlStateNormal];
}
}
}
}

Resources