This is part of my code inside UINavigationController subclass.
I've created a custom UIButton that will show most of the time.
How can I hide it in specific views?
I want to be able to setHidden the button inside some ViewControllers. The UIButton is a property.
-(void)viewDidLoad
{
[super viewDidLoad];
_coolBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[_coolBtn setFrame:CGRectMake(0, 0, 56, 39)];
[_coolBtn setImage:[UIImage imageNamed:#"top.png"] forState:UIControlStateNormal];
[_coolBtn addTarget:self action:#selector(doSomethingCool) forControlEvents:UIControlEventTouchUpInside];
[self.navigationBar addSubview:_coolBtn];
}
Adding this inside the ViewDidLoad of the ViewController where I want to hide the button:
SubClassUInav *test =[[SubClassUInav alloc]init];
[test.coolBtn setHidden:YES];
Doesn't work.
Edit:
Maybe it's because I'm creating a new instance of it?
I'm not referencing to this subclass in my code. The only thing I did was to add it as a custom class inside the IB when the UINavigationController is selected.
Here is what you have to do.
In SubClassUINav.h:
#interface SubClassUInav : UINaviagationController {}
#property (nonatomic, strong) UIButton *coolBtn;
In SubClassUINav.m:
#synthesize _coolBtn = coolBtn;
In your MyViewController.m:
#import "SubClassUINav.h"
// get reference of your nav controller, do not create new instance by alloc-init
SubClassUINav *subClassUINavInstance = (SubClassUINav *) self.navigationController
[subClassUINavInstance.coolBtn setHidden: YES]; //Access your properties
Hope now you get a clear view.
you can also do it with using NotificationCenter like bellow
Add observer in NSNotificationCenter from button Define class:-
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(HideButton:)
name:#"HideButton"
object:nil];
-(void)HideButton:(NSNotification *)notification {
hide button code
}
Calling this using Bellow code:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"HideButton" object:self];
What you are doing wrong is this line
SubClassUInav *test =[[SubClassUInav alloc]init];
This creates a new instance and in that instance the button state will be hidden.In your class somewhere you will be doing the same which is added as subview.Use that instance and make it hidden
Related
I have the following code to generate a UIBUtton from a method file called FirstViewController, since the location of the button will change in different secondviewController or thirdViewController, is it possible to set a variable for the location (CGRect) of the unbutton in the FirstViewController and change the CGRect Value in the second or third viewController?
In FirstViewController.m
-(void)method:(UIView *)_view {
UIButton*Touch1= [UIButton buttonWithType:UIButtonTypeRoundedRect];
[Touch1 addTarget:self action:#selector(TouchButton1:) forControlEvents:UIControlEventTouchUpInside];
[Touch1 setFrame:CGRectMake(50,50, 100, 100)];
**//I want to set a variable for the CGRectMake**
Touch1.translatesAutoresizingMaskIntoConstraints = YES;
[Touch1 setBackgroundImage:[UIImage imageNamed:#"1.png"] forState:UIControlStateNormal];
[Touch1 setExclusiveTouch:YES];
[_view addSubview:Touch1];
NSLog(#"test ");
}
In SecondViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
ViewController * ViewCon = [[ViewController alloc]init];
**//Change variable here by defining the new CGRect here.**
[ViewCon method:self.view];
}
This pattern is incorrect:
ViewController * ViewCon = [[ViewController alloc]init];
[ViewCon method:self.view];
as you are allocating a new view controller just to use one of its the method and then you are throwing the view controller instance away. It's extremely inefficient and inconvenient.
Either move the method to a utility class, as a class method:
[Utils method:self.view rect:rect];
or subclass UIViewController and implement the method in that base class and then derive all similar view controllers from that base class, passing any variables into it.
[self method:rect]; // method implemented in MyBaseViewController
You also asked this question before and accepted an answer that promotes the use of this bad pattern. That will mislead others into using this bad pattern.
I'm implementing a function to create a custom UIAlertView. I have extended UIView with a category, and I'm creating my method, called
- (void)showCustomAlertWithTitle:(NSString *)title andMessage:(NSString *)message
I want to add a selector to a button inside my custom alertview, but this selector is contained in my UIViewController. Should I move the selector into the category, or somehow reference it in the viewcontroller? And If I move the selector into the category, I won't be able to access the navigationcontroller...
in UIView+Category.m:
- (void)showCustomAlertWithTitle:(NSString *)title andMessage:(NSString *)message
{
UIView *alert = [[UIView alloc] initWithFrame:CGRectMake((self.frame.size.width/2)-100, (self.frame.size.height/2)-50, 200, 100)];
UIButton *confirmButton = [[UIButton alloc] initWithFrame:CGRectMake(30,40, 50, 50)];
[confirmButton addTarget:self action:#selector(delete:) forControlEvents:UIControlEventTouchUpInside];
[alert addSubview:confirmButton];
[self addSubview:alert];
}
selector method in MyViewController.m
- (IBAction)delete:(id)sender
{
[[self.view viewWithTag:-7] removeFromSuperview];
self.navigationController.navigationBar.hidden = NO;
}
You are bumping up against the limitations of categories. You can't add instance variables to a class in a category, so you don't have a clean way to save a pointer to your presenting view controller.
I would suggest adding a new method to your category:
- (void) addButtonWithTitle: (NSString*) title
target: (id) target
action: (SEL) action
forControlEvents: (UIControlEvents)controlEvents;
Then in the implementation of that method, use the parameters that are passed in to create and configure the button. The method includes a target, selector, and list of events that should trigger the action.
The selector should be implemented in your viewController , since you could be using your alertView in different viewControllers. Therefore sometimes you would need to perform a logic specific to that viewController. Also MVC 101 forbids you from trying to implement an action in a UIView subclass. Therefore again your viewController should implement the action.
I know this question has been asked a few times, but none of the answers have enough detail for me (me = n00b) to understand.
I have a simple little app that I put together via the storyboard, it has two text fields that the user can type into. I want the user to be able to dismiss the keyboard after they edit either field.
I know it has something to do with "resignFirstResponder" but I'm not sure where to put that.
Here is my top secret code
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize thing1;
#synthesize thing2;
// NSArray things = #[thing1, thing2];
// self.thingLabel.text = array[arc4random()%array.count];
- (IBAction)pick:(id)sender {
// create an empty list that will get filled with things
NSMutableArray *things = [NSMutableArray arrayWithObjects:thing1.text,thing2.text, nil];
NSString *theThing = things[arc4random()%things.count];
NSLog(#"the thing is %#", theThing);
}
#end
and here is my ViewController.h file:
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITextField *thing1;
#property (weak, nonatomic) IBOutlet UITextField *thing2;
#end
Since your view controller adopts the UITextFieldDelegate protocol (i.e., <UITextFieldDelegate>), then the easiest technique is to have the view controller implement the following two methods:
// place in ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// note that you could set the text field delegate in IB instead
self.thing1.delegate = self;
self.thing2.delegate = self;
}
// this method gets called by the system automatically when the user taps the keyboard's "Done" button
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField
{
[theTextField resignFirstResponder];
return YES;
}
That's all the code you need. Now when the user taps the keyboard's "Done" button, the keyboard goes away.
You could just add a button beside the textfield and dismiss it when that one is pressed:
UIButton *doneEnteringButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[doneEnteringButton addTarget:addTarget:self action:#selector(dismissKeyboard:) forControlEvents:UIControlEventTouchUpInside];
- (void)dismissKeyboard
{
[self.view endEditing:YES];
}
This single button will dismiss the keyboard, no matter which textfield you are in. If you don't want the button a cool way would be to add a gesture recognizer to the parent view of the textfield and do endEditing:YES there.
Hope this helps! Ask if it doesn't
try this code, when user tap any where to dismiss keyboard
- (void)setupKeyboardDismiss{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
UITapGestureRecognizer *singleTapGR =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapAnywhereToDismissKeyboard:)];
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[nc addObserverForName:UIKeyboardWillShowNotification
object:nil
queue:mainQueue
usingBlock:^(NSNotification *note){
[self.view addGestureRecognizer:singleTapGR];
}];
[nc addObserverForName:UIKeyboardWillHideNotification
object:nil
queue:mainQueue
usingBlock:^(NSNotification *note){
[self.view removeGestureRecognizer:singleTapGR];
}];
}
- (void)tapAnywhereToDismissKeyboard:(UIGestureRecognizer *)gestureRecognizer{
[self.view endEditing:YES];
}
This depends on the UI & functionality you are trying to develop. You can do it in following ways:
Add a "Done" button to your UI for user to take an action once they are done with entering data in text fields and then in the action handler for that button call [yourTextField resignFirstResponder].
Add a custom keyboard down button to your keyboard.
Implement the below delegate methods on UITextField and put logic in them and call [yourTextField resignFirstResponder] once the required criterion is met. For example once user has entered certain number of characters it will auto-dismiss the keyboard.
When user is done and tap outside the textfield view, dismiss the keyboard. Implement 'touchesbegan' on UIView and let the viewcontroller about it.
-(BOOL)textField:(UITextField *)iTextField shouldChangeCharactersInRange:(NSRange)iRange replacementString:(NSString *)iString
-(void)textFieldDidEndEditing:(UITextField *)iTextField
I'm working on an application in which I'm adding UIBarButtonItem to UIToolbar dynamically. When User clicks on a bar button. I'm changing it's tint color to red.
But for some bar buttons it's not working and the application is crashing.
Here is my code:
#interface myClass : UIViewController
#property (nonatomic, retain) NSMutableArray *barButtonItems;
#property (nonatomic, retain) IBOutlet UIToolbar *toolBar;
#end
#implementation myClass
#sythesize barButtonItems, toolBar;
- (void)viewDidLoad
{
[super viewDidLoad];
barButtonItems = [[NSMutableArray alloc] init];
[self initToolBar];
}
//To set the tool bar
- (void)initToolBar
{
[self addBarItem:#"PlantDetails" actionName:#"createPlantDetails:"];
[self addBarItem:#"ElectricalEquipmentInventory" actionName:#"createInventory:button:"];
toolBar.items = barButtonItems;
}
//Create bar button item
- (void)addBarItem:(NSString*)barButtonName actionName:(NSString*)methodName
{
UIBarButtonItem *plantDetails = [[UIBarButtonItem alloc] initWithTitle:barButtonName style:UIBarButtonItemStyleDone target:self action:NSSelectorFromString(methodName)];
[barButtonItems addObject:plantDetails];
[plantDetails release];
plantDetails = nil;
}
//Changes the barbutton tintcolor when user selected
-(void)changeSelection:(UIBarButtonItem *)button
{
NSArray *tempArray = toolBar.items;
for(int loop = 0; loop<[tempArray count]; loop++)
[[tempArray objectAtIndex:loop] setTintColor:[UIColor blackColor]];
[button setTintColor:[UIColor redColor]];
}
//First bar button method
- (void)createPlantDetails:(UIBarButtonItem *)button
{
[self changeSelection:button];
NSLog(#"createPlantDetails");
}
//second bar button method
- (void)createInventory:(int)selectedIndex button:(UIBarButtonItem *)button
{
[self changeSelection:button];
NSLog(#"createInventory");
}
#end
Here my issue is the bar button with only one parameter in it's selector is working perfectly (createPlantDetails) but when I click on the bar button which have two parameter in it's selector (createInventory) the application is crashing on [button setTintColor:[UIColor redColor]]; of changeSelection method.
Crash log is something like: touches event have no method like setTintColor .
I searched a lot but couldn't find a solution. Please help me.
Thanks in advance
The method for the action property has to have one of the following three forms:
- (void)methodName;
- (void)methodName:(id)sender;
- (void)methodName:(id)sender withEvent:(UIEvent *)event;
You can't use any arbitrary format or custom parameters (the button wouldn't know what to pass for them).
The createPlantDetails: method works because it matches the second form.
The createInventory:button: method fails because it doesn't match any of the expected signatures.
Since your method has two parameters, when the button calls the method, the button passes a UIEvent object in the second parameter which in your method is named button.
In changeSelection:, it crashes when it tries to call setTintColor: because button is really a UIEvent and not the UIBarButtonItem (ie. the sender).
I have a main view with 3 buttons. Clicking on any of the buttons adds a SubView.
The buttons have different titles and are all linked to IBAction "switchView"
The "switchView" code is below.
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
[self.view addSubview:myViewController.view];
}
The "secondView" loads up correctly and everything works well.
The problem is I want to be able to know which button was the Sender.
I don't want to create 3 subviews, one for each button. The code and XIB would be absolutely the same>
The only difference would be a variable that I would like to set up in the second view (viewDidLoad method) depending on who is the Sender (which button was clicked)
Is this possible? Or I would need to create 3 subViews - one for each button?
Your help is greatly appreciated!
You can identify different buttons with the tag property.
e.g. with your method:
-(IBAction)switchView:(id)sender {
UIButton *button = (UIButton*)sender;
if (button.tag == 1) {
//TODO: Code here...
} else if (button.tag == 2) {
//TODO: Code here...
} else {
//TODO: Code here...
}
}
The tag property can be set via the InterfaceBuilder.
Hope this helps.
I think you can solve in 2 ways:
Create a property like:
#property (nonatomic, strong) IBOutlet UIButton *button1, *button2, *button3;
in your viewcontroller and link the buttons to them as referencing outlet on the XIB.
Give a different tag to each button on your xib and ask for the tag of the sender with UIButton *b=(UIButton*)sender; b.tag; like Markus posted in detail.
Solving my problem it all came down to transferring data between the mainView and subView.
In my mainView.h I declared an NSString and its #property
...
NSString *btnPressed;
}
#property(nonatomic, retain) NSString *btnPressed;
...
then in my mainView.m inside the switchView method I did this:
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
btnPressed = [NSString stringWithFormat:#"%i", [sender tag]];
[myViewController setBtnPressed:self.btnPressed];
[self.view addSubview:myViewController.view];
}
This line in the code above actually takes care of transferring the data to the newly created subView:
[myViewController setBtnPressed:self.btnPressed];
Then in my secondView.h I declare exactly the same NSString *btnPressed and its #property (though this a completely different object than the one declared in main)
Then in my secondView.m I get the value of the button pressed I'm interested in.
- (void)viewDidLoad {
[super viewDidLoad];
int theValueOfTheButtonPressed = [self.btnPressed intValue];
}
This works well.
Don't forget to #synthesize btnPressed; as well as [btnPressed release]; in both mainView.m and secondView.m