UIButton target not recognized when adding button superview controller to another viewController - iphone

I created a sub-class of UIViewController called toolbarViewController , I declare a UIButton in this view controller and specified it's target as following
UIButton *button = [[UIButton alloc]initWithFrame:myFrame];
[button addTarget:self action:#selector(doSomething) forContorlEvents:UIControlEventTouchUpInside];
then i do the following in a different view controller
toolbarViewController *toolbar = [[toolbarViewController alloc]init];
[self.view addSubview:toolbar.view];
the problem is that when i press the button i get the exception: Unrecognized selector ( doSomething ) send to instance , what am i doing wrong here ?
doSomething declaration in toolbarViewController.h
-(void)doSomething;
and in toolbarViewController.m
-(void)doSomething{ NSLog("doSomething got called"); }

Check the declaration of doSomething. If you declare IBAction something like -(IBAction)doSomething:(id)sender, you should add selector like
[button addTarget:self action:#selector(doSomething:) forContorlEvents:UIControlEventTouchUpInside];
instead of
[button addTarget:self action:#selector(doSomething) forContorlEvents:UIControlEventTouchUpInside];

if you use ARC,you alloc toolbarViewController,but it has relese。you can try to this:
ViewController.h
#interface ViewController : UIViewController{
toolbarViewController * toolbar;
}
#property(nonatomic,strong) toolbarViewController * toolbar;
ViewController.m
#synthesize toolbar = _toolbar;
toolbar = [[toolbarViewController alloc]initWithNibName:#"toolbarViewController" bundle:[NSBundle mainBundle]];
and you alloc button can do this:
UIButton *bt = [UIButton buttonWithType:UIButtonTypeRoundedRect];
bt.frame = myFrame;
[bt addTarget:self action:#selector(dosomething) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:bt];

One possible case is if you add a UITapGestureRecognizer to the UIButton's superview.
On iOS5 it seems there is an issue with UITapGestureRecognizers that do not cancel the tap in view.
So all you need to do is set the
tapGesture.cancelsTouchesInView = NO;
let me know if it helped!

Related

Click event of UIButton is not getting fired

I made a simple app in which i am loading different .xib on each orientation,
I have two xib's Portxib and Landxib, in both xibs, i dragged a button and assigned a
tag value to it as 1 in both xib's.
and i wrote this code in my viewDidLoad
UIButton *btn=(UIButton *)[self.view viewWithTag:1];
[btn addTarget:self action:#selector(BtnClick:) forControlEvents:UIControlEventTouchUpInside];
here is the selector method,
-(void)BtnClick:(id)sender
{
NSLog(#"BtnClick");
}
Click event of UIButton is not getting fired...
OR
Is there any other way to call the same method of button from both the orientation ??
EDIT :
.h file
.m file
Make sure...
Button is placed in root view in xib as you are finding it in self.view OR make sure it is placed in correct view and use that view with viewWithTag
You have assigned tag 1, so just make sure no other control within
same view have tag 1 other wise button will not be recognized by tag. If this is going to be your case then just change tag of button to very unusual number for that view like 999 or any thing else and test.
EDIT
I am feeling like you view is not getting recognized at viewDidLoad where you have setup your code. So just comment out that code in viewDidLoad and shift in your changeOrientation method after loading nib.
-(void)changeOrientation
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if(orientation==UIInterfaceOrientationPortrait || orientation==UIInterfaceOrientationPortraitUpsideDown)
{
[[NSBundle mainBundle] loadNibNamed:#"PortraitXib" owner:self options:nil];
}
else
{
[[NSBundle mainBundle] loadNibNamed:#"LandscapeXib" owner:self options:nil];
}
//Adding this code here makes sense that nib is loaded and after that we are recognizing button from loaded view of nib.
UIButton *btn = (UIButton*)[self.view viewWithTag:1];
[btn addTarget:self action:#selector(BtnClick:) forControlEvents:UIControlEventTouchUpInside];
}
Hope this helps.
In header file add
IBOutlet UIButton *btn;
reference this btn from your xib files.
Here in your case the btn you are using is not referenced from the xib files so the method is not firing
-(IBAction)BtnClick:(id)sender
{
NSLog(#"BtnClick");
}
make the function as IBAction and reference this from nib btn.
In this case you no need to addtarget explicitly.
If you are not adding the button in the nib, then dont forget to init and addsubview to the view
You can see this tutorial http://www.idev101.com/learn/interface_builder_connections.html
EDIT Check what is printing?
for (UIButton *but in [self.view subviews])
{
NSLog("but.tag %d",but.tag);
if(but.tag==1)// compare for same row elements
{
NSLog("Button Added");
[btn addTarget:self action:#selector(BtnClick:) forControlEvents:UIControlEventTouchUpInside];
}
}
You can add a button like this.
Add this to you didLoad method
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:1];
[aButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aView addSubview:aButton];
}
// then ...
- (void)buttonClicked:(UIButton*)button
{
NSLog(#"Button %d clicked.", [button tag]);
}

Programmatically added button getting crash in storyboard

I am adding a button in UIScrollView in StoryBoard
Below is the code i am using.
-(void)addScrollView
{
for(int i=0;i<[array count];i++)
{
UIScrollView *subScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 400, SUBSCROLLVIEW_WIDTH, SUBSCROLLVIEW_HEIGHT)];
UITextView *txtVwDetail = [[UITextView alloc] initWithFrame:CGRectMake(342, 0, TEXTVIEW_WIDTH, TEXTVIEW_HEIGHT)];
txtVwDetail.text = SAMPLE_STRING;
[self addSubScrollView:subScrollView];
[self.view addSubview:subScrollView];
[self.view addSubview:txtVwDetail];
}
}
-(void)addSubScrollView:(UIScrollView *)aSubScrollView
{
for(int i=0;i<[array count];i++)
{
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
aButton.frame = CGRectMake(intBtnX, (aSubScrollView.frame.size.height - 80)/2, 50, 80);
[aButton setImage:[UIImage imageNamed:[self.items objectAtIndex:i]] forState:UIControlStateNormal];
**[aButton addTarget:self action:#selector(btnSubImageClicked) forControlEvents:UIControlEventTouchUpInside];**
aSubScrollView.contentSize = CGSizeMake(intScrollViewWidth, aSubScrollView.frame.size.height);
[aSubScrollView addSubview:aButton];
}
}
In addSubScrollView method I have added Button and its click event which is getting crashed.
-(void)btnSubImageClicked
{
NSLog(#"btnSubImageClicked");
}
I am having scenario as
MyMainViewController is the sourceViewController for my created customSegue which is the UIStoryboardSegue class
MyMainViewController having a UIView as PlaceHolderView in which I am adding MydestinationViewContoller's View which is this Scrollview
-(void)perform
{
BrowseScreenVC *srcObj = (BrowseScreenVC *)[self sourceViewController];
UIViewController *dstObj = (UIViewController *)[self destinationViewController];
for(UIView *vw in srcObj.viewPlaceHolder.subviews)
{
[vw removeFromSuperview];
}
NSLog(#"dest : %#",dstObj.view);
NSLog(#"destobj :%#",dstObj);
srcObj.currentViewController = dstObj;
[srcObj.viewPlaceHolder addSubview:[dstObj.view retain]];
}
UPDATE
With answer I also have to change the line
srcObj.currentViewController = dstObj;
to
srcObj.addChildViewController = dstObj;
to make it working
you have to add target as follow:
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
#selector(), within these braces you have to provide the method that you want to perform. the ":" represents that the method has some argument. In this case the argument would be the button itself that is calling the method.
You have to implement your method then its signature would look like this
- (void)btnSubImageClicked:(id)sender{
// sender would be the button that is calling the method. you can use this object according to your requirements if you want.
// your code
}
if you want to call this method from somewhere else as well you can call it by passing sender argument nil. e.g [self btnSubImageClicked:nil];
Your action needs to accept an (id) sender argument, even if you are not using it:
-(void)btnSubImageClicked:(id) sender
{
NSLog(#"btnSubImageClicked");
}
In the addSubScrollView:
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
Button target should like
-(void) btnSubImageClicked:(id)sender{}
try this.
Updated:-
Please correct your code,change this line
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
Now working i checked.
Instead of
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
write this,
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
and for better practice always write this,
-(void) btnSubImageClicked:(id)sender{}

how to call global function from another global function with one parameter in iphone?

HiI am very new to iphone development.I am java background developer.So my approach is like java .
Here my requirement is that i want to call one global function from every view controller.
and from there i pass self.navigationController as a parameter. In that function i add some buton. when user click on that button it should call one more function and it should carry same object as a parameter.
please give me guidance. i tried as following but it is showing error at compiletime
Utilities.m
+(void)setBacKButton:(UINavigationController *)navigationController
{
for(UIButton *btn in navigationController.navigationBar.subviews){
if([btn isKindOfClass:[UIButton class]]){
[btn removeFromSuperview];
}
}
UIButton *btn2=[UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame=CGRectMake(708, 0, 50, 54);
[btn2 setImage:[UIImage imageNamed:#"btn_back.png"] forState:0];
[btn2 setImage:[UIImage imageNamed:#"btn_back_h.png"] forState:UIControlStateSelected];
// here i need to call bellow function when click on this button
//[btn2 addTarget:self action:#selector() forControlEvents:UIControlEventTouchUpInside];
[navigationController.navigationBar addSubview:btn2];
}
+(void)gotoBack:(UINavigationController *)navigationController
{
[navigationController popViewControllerAnimated:YES];
}
and i call that function from my viewcontroller as
[Utilities setBacKButton:self.navigationController];
please tell me how we can achieve this
add a function in your app delegate.and call that function in all your view controllers.with an object of appdelegate.then with in that function add one button with id sender and do watever u want in the method.
Just make a navigation controller in your app Delegate ... and push your view controller using this.. follow the following code...
//YourAppdelegate.h
UINavigationController *navController;
#property(nonatomic,retain)UINavigationController *navController;
// your appdelegate.m
navController = [UINavigationController alloc]initWithRootViewController:self.viewController];
self.window.rootViewController = navController ;
and now make your global function here (in appdelegate.m) like.......
- (void)setBacKButton:(UINavigationController *)navigationController{
// put your code here
}
now call it from your view controllers where you have needed like this...
// yourViewController.m
import "yourAppdelegate.h"
and when you have to call that function just write these two lines..
YourAppdelegate *appdelegate = (YourAppdelegate*)[[UIApplication sharedApplication]delegate];
[appdelegate setBacKButton:self.navigationController];
may this will help you
you would want to create a category of UINavigationBar.
UINavigationBar+customBackButton.h
#import <UIKit/UIKit.h>
#interface UINavigationBar (customBackButton)
- (void)setCustomBackButton;
#end
UINavigationBar+customBackButton.m
#import "UINavigationBar+customBackButton.h"
#implementation UINavigationBar (customBackButton)
- (void)setCustomBackButton
{
for(UIButton *btn in self.subviews)
{
if([btn isKindOfClass:[UIButton class]])
{
[btn removeFromSuperview];
}
}
UIButton *btn2=[UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame=CGRectMake(708, 0, 50, 54);
[btn2 setImage:[UIImage imageNamed:#"btn_back.png"] forState:0];
[btn2 setImage:[UIImage imageNamed:#"btn_back_h.png"] forState:UIControlStateSelected];
// here i need to call bellow function when click on this button
//[btn2 addTarget:self action:#selector() forControlEvents:UIControlEventTouchUpInside];
[self addSubview:btn2];
}
#end
Then in any view controller you can import it like this
#import "UINavigationBar+customBackButton.h"
[self.navigationController.navigationBar setCustomBackButton];
Following the response from #ewiinnnnn above, I came up with a way to use Custom Categories and have the back button navigate as expected:
// UIViewController+customBackButton.h
#import <UIKit/UIKit.h>
#interface UIViewController (customBackButton)
- (void)setCustomBackButton;
#end
// UIViewController+customBackButton.m
#import "UIViewController+customBackButton.h"
#implementation UIViewController (customBackButton)
// sets my custom back button
- (void)setCustomBackButton
{
UINavigationItem *navItem = self.navigationItem;
UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *addButton = [UIImage imageNamed:#"backButton.png"];
UIImage *addButtonSelected = [UIImage imageNamed:#"backButtonHighlighted.png"];
[customButton setBackgroundImage:addButton forState:UIControlStateNormal];
[customButton setBackgroundImage:addButtonSelected forState:UIControlStateHighlighted];
customButton.frame=CGRectMake(0.0, 0.0, addButton.size.width, addButton.size.height);
[customButton addTarget:self action:#selector(navigateBack) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView: customButton];
navItem.leftBarButtonItem = barButtonItem;
}
// the action that is triggered when the back button is pressed
- (void)navigateBack {
[self.navigationController popViewControllerAnimated:YES];
}
#end
And then within a UIViewController:
// MyViewController.m
#import "UIViewController+customBackButton.h"
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// add back button to navcontroller
[self setCustomBackButton];
}

Can you skin a UIButton application wide in an iPhone app

Anywhere there is a UIButton in my app i would like it to have a specific background image. This background image will always be the same.
What i dont want to have to do is call a method on every button that i put into my UI.
Can i do this via a category or something similar?
You can't change global appearance of your button via simple code (in current SDK).
BUT, You can subclass your UIButton. For example:
.h
#interface MyButton : UIButton
#end
---
.m
#implementation MyButton
// your customization code
#end
And if you want to insert an UIButton instance like:
UIButton *button = // init your button
// customize your button
[self.view addSubview:button];
you have to change UIButton to MyButton
Mybutton *button= // init your button
[self.view addSubview:button];
Don't forget about #import "MyButton.h" in your .m / .h file.
EDIT: Where should you make customizations:
#implementation UIButton (MyCategory)
+ (id)buttonWithFrame:(CGRect)frame {
return [[[self alloc] initWithFrame:frame] autorelease];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// HERE YOU CAN DO SOME CUSTOMIZATION
}
return self;
}
Then, somewhere in your viewController:
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(x, y, width, height)];
or:
UIButton *btn = [UIButton buttonWithFrame:CGRectMake(x, y, width, height)];

Passing button title to a new view

I have a button on a view which when pressed opens another second view. I want to set a label in the second view to change depending on the label of the button that was pressed. I have tried passing (id) sender in my switchViews function but that does not work. Please help!
On your second view controller, create a the UILabel as a property i.e.
#interface MyViewcontroller : UIViewController {
UILabel *titleLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *titleLabel;
and, in interface builder, attach it to the label that you want to change.
Then, in your first view controller's switchViews method, after you create your second view you can set the title like this :
...
MyViewController *newViewController = [[MyViewController alloc] initWithNibName:'something' bundle:nil];
newViewController.view.titleLabel.text = #"Your new title goes here";
...
Hope that helps.
Passing sender should work. Just cast sender to UIButton * and take title for the state with titleForState:. Here is working code:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window makeKeyAndVisible];
UIButton * myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
myButton.frame = CGRectMake(100, 100, 100,80);
[myButton setTitle:#"test title" forState:UIControlStateNormal];
[myButton addTarget:self action:#selector(myButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[window addSubview:myButton];
}
- (void)myButtonClicked:(id)sender{
UIButton * clickedButton = (UIButton *)sender;
NSString * buttonTitle = [clickedButton titleForState:UIControlStateNormal];
NSLog(#"title: %#",buttonTitle);
UILabel * myLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 250, 100,80)];
myLabel.text = buttonTitle;
[window addSubview:myLabel];
}