Dismiss keyboard from UISearchBar when adding as a subview - objective-c

I wanted to add a UISearchBar to my view controller without storyboard so I added it programmatically as a subview. I have set the delegate and yet I can't seem to dismiss the keyboard by clicking on the search button.
here's my code:
#interface ViewController : UIViewController <UISearchBarDelegate>
{
IBOutlet UISearchBar* mySearchBar;
}
----
- (void)viewDidLoad
{
[mySearchBar setDelegate: self];
mySearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, self.navigationController.navigationBar.frame.origin.y, 320, 44)];
[self.view addSubview:mySearchBar];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)mySearchBar
{
[mySearchBar resignFirstResponder];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)mySearchBar
{
[mySearchBar resignFirstResponder];
}

You are setting the delegate before allocating the search bar. Try to set delegate afterwards.
mySearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, self.navigationController.navigationBar.frame.origin.y, 320, 44)];
[mySearchBar setDelegate: self];
It is always helpful to check whether the delegate methods are called in the first place. Set a break point and see :)

Related

Remove subview and send control back

I am invoking "HelpviewController" from UIViewController using following code, which is working fine.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"InnerHelpPageViewController"];
self.pageViewController.dataSource = self;
InnerHelpViewController *startingViewController = [self viewControllerAtIndex:0];
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
Inside my new controller InnerHelpViewController I have done button which should remove this newly added view and send control back to initiated page.
- (IBAction)unwindToMenuFromInnerHelp:(id)sender {
[self.view removeFromSuperview];
}
This call removing the newly added view, but the problem is "MenuController" is frozen. I couldn't do any clicks on it. Any help?
To explain flow--> I have menu screen where one button with name "help" --> When user clicks on this help button first snippet of code in this question executes and shows HelpViewController-->Once done with help, user clicks "Done" button--> Which should close the HelpViewController and move to "menu" screen.
Implement protocol method in InnerHelpViewController.h file class
#protocol InnerHelpViewControllerDelegate
-(void)removeCustomView;
#end
#interface InnerHelpViewController : UIViewController{
}
#property(nonatomic, weak) id<InnerHelpViewControllerDelegate> delegate.
In InnerHelpViewController.m file
#synthesize delegate;
- (IBAction)unwindToMenuFromInnerHelp:(id)sender {
[delegate removeCustomView];
}
in MenuController .h file Adopt InnerHelpViewControllerDelegate.
#interface MenuController : UIViewController<InnerHelpViewControllerDelegate>{
}
Now Confirm your delegate in MenuController.m file while helpviewcontroller object creation.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"InnerHelpPageViewController"];
self.pageViewController.dataSource = self;
InnerHelpViewController *startingViewController = [self viewControllerAtIndex:0];
startingViewController.delegate = self;
NSArray *viewControllers = #[startingViewController];
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];
// Change the size of page view controller
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 30);
[self addChildViewController:_pageViewController];
[self.view addSubview:_pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
//Implement here delegate method
-(void)removeCustomView{
[self.pageViewController removeFromSuperview]
}

UIButton and UIViewContoller IOS7

I'm new to ObjC and I'm trying to create Button outside ViewController file (following MVC paradigm).
What I did:
.h
#interface MainMenu : UIButton
-(UIButton *)addButton;
#end
.m
#implementation MainMenu
-(UIButton *)addButton {
UIButton* button = [[UIButton alloc] initWithFrame:CGRectMake(50.0, 50.0, 200.0, 75.0)];
[button setBackgroundColor:[UIColor colorWithRed:1.0
green:1.0
blue:0.0
alpha:1.0]];
[button setTitle:#"TITLE"
forState:UIControlStateNormal];
return button;
}
#end
In ViewController I want to create button on the screen and make it respond to touch event. So
.m
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
MainMenu *menuButton = [[MainMenu alloc] init];
[menuButton addTarget:self
action:#selector(ButtonClick)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:menuButton];
}
-(void)ButtonClick {
NSLog(#"You clicked on button!!!");
}
#end
I can make it work by implementing all in ViewController.m file, but wish I could have then separated. This code above doesnt show me a button
Second thing: I tried to add addTarget:action:forControlEvents: method to MainMenu.m instead of ViewController.m and I couldnt make it work properly because I need to pass ViewController as a target and method ButtonClick from ViewController.m as a selector (I guess)
So I'm interesting how to make it right according to MVC?
Thanks!
They way you are doing is bit wrong, as you subclassing UIButton and then you have instance method addButton which returns a button, don't make sense. Either you can add Class level method or just subclass and add another init method to fulfill your requirements.
Better would be if you want to create a custom button and want to add target action also do something like this
#interface CustomButton : UIButton
- (instancetype)initWithTarget:(id)target andAction:(SEL)action;
#end
in .m file
#implementation CustomButton
- (instancetype)initWithTarget:(id)target andAction:(SEL)action {
self = [super initWithFrame::CGRectMake(50.0, 50.0, 200.0, 75.0)];
if (self) {
[self setBackgroundColor:[UIColor colorWithRed:1.0
green:1.0
blue:0.0
alpha:1.0]];
[self setTitle:#"TITLE"
forState:UIControlStateNormal];
[self addTarget:target
action:action
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
#end
and you can just use it like this anywhere
[self.view addSubView:[CustomButton alloc] initWithTarget:self andAction:#selector(name)]];
You are almost there. Here is what you have done right:
1) Subclassed UIButton to MainMenu class. (I would typically call this MainMenuButton or something more specific)
2) Set up, created, and configured an instance of MainMenu in ViewController.
Here is what you did wrong:
1) Did not implement a custom init method
2) Tried to setFrame from within the subclass, this should be done from ViewController
3) You need to make modifications to self, which is the current instance of the subclass, not a new variable called button
The addButton method will never be called, since there is nothing to call it. When customizing a UIButton subclass you will want to do all of this in a custom init method. Try replacing your addButton method with this code:
#implementation MainMenu
-(id)init {
self = [super init];
if(self) {
[self setBackgroundColor:[UIColor colorWithRed:1.0
green:1.0
blue:0.0
alpha:1.0]];
[self setTitle:#"TITLE"
forState:UIControlStateNormal];
}
return self;
}
#end
Then in ViewController create an instance of your MainMenu subclass, set the frame, and configure as you did previously. This init method will be called when you call [[MainMenu alloc] init]; and will configure the subclass before returning it to ViewController.
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
MainMenu *menuButton = [[MainMenu alloc] init];
[menuButton setFrame:CGRectMake(50.0, 50.0, 200.0, 75.0)];
[menuButton addTarget:self
action:#selector(ButtonClick)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:menuButton];
}
-(void)ButtonClick {
NSLog(#"You clicked on button!!!");
}
#end

-[UIPopoverController dealloc] reached while popover is still visible

I have a class (ViewOpenAppointments) where I create and display a UIPopover. This is the code to define the popover in my .h file:
#interface ViewOpenAppointments : UIView {
}
#property (nonatomic, retain) UIPopoverController *popoverController;
-(void)createOpenAppointmentsPopover: (UIButton *) obViewOpenAppts;
#end
I have a check in the code that if the popover is visible, dismiss it. This is the code:
// create popover
UIViewController* popoverContent = [[UIViewController alloc] init];
// UIView *popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 650, 416)];
ViewOpenAppointments *popoverView = [[ViewOpenAppointments alloc] initWithFrame:CGRectMake(0, 0, 650, 416)];
popoverView.backgroundColor = [UIColor whiteColor];
popoverContent.preferredContentSize = CGSizeMake(650.0, 416.0);
// create the popover controller
popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverContent];
popoverController.delegate = (id)self;
[popoverController setPopoverContentSize:CGSizeMake(650, 416) animated:NO];
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
}
[popoverController presentPopoverFromRect:CGRectMake(650, 416, 10, 50) inView: obViewOpenAppts
permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
The problem is that the code to dismiss the popover is never hit, which means it's not visible. But I still get the error message (described in the question title).
What am I doing wrong?
Here is a complete popover management example:
#interface ViewController () <UIPopoverControllerDelegate>
#property (nonatomic, strong) UIPopoverController* currentPop;
#end
#implementation ViewController
-(IBAction)doPopover1:(id)sender {
Popover1View1* vc = [[Popover1View1 alloc] initWithNibName:#"Popover1View1" bundle:nil];
UIPopoverController* pop = [[UIPopoverController alloc] initWithContentViewController:vc];
self.currentPop = pop;
[pop presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
pop.passthroughViews = nil;
// make ourselves delegate so we learn when popover is dismissed
pop.delegate = self;
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)pc {
self.currentPop = nil;
}
By checking self.currentPop you can make sure you don't present two popovers at once (illegal anyway).

Mirror text from UITextField on inputAccessoryView - UIToolBar to text on UITextField on navigationController.toolbar

In my app I have a UITextField on the navigationController toolbar.
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic,strong) NSArray *toolBarButtonItems;
#property (nonatomic,strong) UITextField *textField;
#property (nonatomic,strong) UITextField *textField2;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.textField = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
self.textField.delegate = self;
self.textField.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField];
self.toolBarButtonItems = #[flexibleSpace,barButtonItem,flexibleSpace];
self.toolbarItems = self.toolBarButtonItems;
self.navigationController.toolbar.barTintColor = [UIColor blueColor];
[self.navigationController setToolbarHidden:NO animated:NO];
}
When the textField is clicked the keyboard opens up and I create a new inputAccessoryView toolbar with another textField.
-(UIToolbar *)addToolBar{
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:self.navigationController.toolbar.frame];
toolbar.barTintColor = [UIColor darkGrayColor];
self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(0, 0, 60, 40)];
self.textField2.delegate = self;
self.textField2.borderStyle = UITextBorderStyleRoundedRect;
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.textField2];
[toolbar setItems:#[flexibleSpace,barButtonItem,flexibleSpace]];
return toolbar;
}
The idea is to change the firstResponder to the textField on the inputAccessoryView so this way I can see what I'm editing. The reason I am doing this is cause I can't scroll the Navigation toolbar up past the keyboard and I want to see the text that I am editing.
-(void)textFieldDidBeginEditing:(UITextField *)textField{
textField.inputAccessoryView = [self addToolBar];
if(self.textField2.isFirstResponder != NO){
[self.textField2 becomeFirstResponder];
}
}
It doesn't seem to be working when I click on the textField in the navigationController toolbar. The new inputAccessoryView toolbar shows up over the keyboard but I can't edit the field because the responder doesn't seem to be changing. The return key doesn't work either. I have to hit it twice in order to close the keyboard and when I do the text doesn't match up between the two text fields.
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
self.textField.text = self.textField2.text;
return YES;
}
I got it to work like this:
#import "KJMViewController.h"
#interface KJMViewController ()
#property (strong, nonatomic) UITextField *textField1;
#property (strong, nonatomic) UITextField *textField2;
#end
#implementation KJMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.textField1 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
self.textField1.borderStyle = UITextBorderStyleRoundedRect;
self.textField1.delegate = self;
UIToolbar *navToolbar = self.navigationController.toolbar;
[navToolbar addSubview:self.textField1];
UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
self.textField2 = [[UITextField alloc]initWithFrame:CGRectMake(30, 7, 260, 30)];
self.textField2.borderStyle = UITextBorderStyleRoundedRect;
self.textField2.delegate = self;
[toolbar addSubview:self.textField2];
self.textField1.inputAccessoryView = toolbar;
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(firstRes:) name:UIKeyboardDidShowNotification object:nil];
}
- (void)firstRes:(id)sender
{
[self.textField2 becomeFirstResponder];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.textField2) {
self.textField1.text = self.textField2.text;
}
[textField resignFirstResponder];
[self.textField1 resignFirstResponder];
return YES;
}
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter]removeObserver:self forKeyPath:UIKeyboardDidShowNotification];
[super viewDidDisappear:animated];
}
#end
Here's what's happening in viewDidLoad:
Initialise toolbar and textField2
Set the inputAccessory for textField1 (the one hidden by the keyboard) here so it's ready to become firstResponder
Then in the viewDidAppear method:
Sign up for a notification that's sent when the keyboard is shown. You'll then write some code in the "firstRes" method to make textField2 the firstResponder. You need to make it the firstResponder using this notification because you know that it's in the view hierarchy by this time, which means it's able to become firstResponder. Calling it in the -(void)textFieldDidBeginEditing:(UITextField *)textField seems to fire it before textField2 comes on screen, meaning that it can't become firstResponder. We sign up for it in the viewDidAppear method because we only want to get the notification if we're on screen.
After textField2 resignsFirstResponder, textField1 becomes first responder again, so you have to call resignFirstResponder twice in the textFieldShouldReturn method.
Also, if we leave the screen, we need to remove ourself as an observer of the keyboard notification in the viewDidDisappear method.
Here's a link to the project I made in Xcode so you can see how it works:
https://github.com/kylejm/UIToolBar-UITextView

Creating multiple subviews inside view controller

I have a view controller named ViewController.
ViewController displays a UIView that has a button on it, which allows me to advance to a second view controller - SecondViewController.
SecondViewController also has a button on it, which allows me to advance to a third view controller.
However, I am having trouble displaying ThirdViewController. When I tap the button in SecondViewController it throws an error:
Warning: Attempt to present ... on ... whose view is not in the window hierarchy!
I have been to a bunch of other sites and posts that address this issue, but cannot seem to find a working solution. I have implemented quite a few solutions, but none seem to work.
Here is my code:
- (void)secondaryView:(UIView *)secondaryView
{
UIView *theView = secondaryView;
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.frame = [UIScreen mainScreen].bounds;
[viewController.view addSubview:theView];
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:viewController animated:YES completion:nil];
}
secondaryView is a UIView that I am constructing elsewhere in the application. I add it to the viewController then present the viewController.
Is there any way to dynamically create UIViewControllers, add a UIView to each one, and add them to the window hierarchy?
If you can use navigation in your ViewControllers, you can try the below code
In the place where you call the firstViewController,
-(void)callFirst
{
FirstViewController *first = [FirstViewController alloc] init];
UINavigationController *navigationController = [UINavigationController alloc] initWithRootViewController:first];
navigationController.modalPresentaionStyle = UIModalPresenationFormSheet;
[self presentModalViewController:navigationController animated:YES];
}
And in the FirstViewController button action ,you can write
-(void)callSec
{
SecondViewController *sec = [SecondViewController alloc] init];
[self.NavigationController pushViewController:sec animated:YES];
}
And in SecondViewController you can do the same
-(void)callThird
{
ThirdViewController *third = [ThirdViewController alloc] init];
[self.NavigationController pushViewController:third animated:YES];
}
Try this...And in these ViewControllers you can do whatever coding you want to meet the requirement like
-(void)viewDidLoad
{
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(20,20,400,400)];
newView.backGroundColor = [UIColor redColor];
[self.view addSubView:newView];
}