I have a total of 5 text fields in a view controller. 1 of them opens the keyboard to fill in data. 2 of them open up the picker view to select the value. 1 opens up the Date Picker. And the last one segues to a Table View Controller.
The pickers and keyboard open up fine as I transition from one text field to another. If I click on the text field to segue to the table view, it opens as well. The problem occurs when I try to open the Table View if there is currently a picker or keyboard already active. The picker or keyboard from the previous selected text field shows in front of the table view. How do I hide the picker or keyboard before going to the table view?
Link to sample project http://www.filedropper.com/test_9
.h file
#import <UIKit/UIKit.h>
#interface AddAEntryViewController : UIViewController<UITextFieldDelegate,UIPickerViewDataSource,UIPickerViewDelegate>
#property (weak, nonatomic) IBOutlet UITextField *textEntryName;
#property (weak, nonatomic) IBOutlet UITextField *textEntryStatus;
#property (weak, nonatomic) IBOutlet UITextField *textEntryLocation;
#property (weak, nonatomic) IBOutlet UITextField *textEntryGender;
#property (weak, nonatomic) IBOutlet UITextField *textDOB;
#property (weak, nonatomic) IBOutlet UIPickerView *pickerAddEntryInfo;
#property (weak, nonatomic) IBOutlet UIDatePicker *datepickerAddEntryInfo;
#end
.m file
#import "AddAEntryViewController.h"
#interface AddAEntryViewController ()
#property(strong, nonatomic)NSArray *arrayEntryStatus;
#property(strong, nonatomic)NSArray *arrayEntryLocation;
#property(strong, nonatomic)NSArray *arrayEntryGender;
#end
#implementation AddAEntryViewController{
}
#synthesize textEntryName=_textEntryName;
#synthesize textEntryStatus = _textEntryStatus;
#synthesize textEntryLocation = _textEntryLocation;
#synthesize textEntryGender = _textEntryGender;
#synthesize textDOB =_textDOB;
#synthesize pickerAddEntryInfo = _pickerAddEntryInfo;
#synthesize datepickerAddEntryInfo = _datepickerAddEntryInfo;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
//TOOLBAR SETUP
CGRect cgRect =[[UIScreen mainScreen] bounds];
CGSize cgSize = cgRect.size;
UIToolbar* toolbar = [[UIToolbar alloc] init];
toolbar.frame=CGRectMake(0, 0, cgSize.width, 35);
toolbar.barStyle = UIBarStyleBlackTranslucent;
//PICKER SETUP
_pickerAddEntryInfo.hidden=YES;
_arrayEntryStatus = [[NSArray alloc]initWithObjects:#"Single",
#"Married", nil];
_arrayEntryGender = [[NSMutableArray alloc] initWithObjects:#"Female",#"Male", nil];
_textEntryStatus.inputView = _pickerAddEntryInfo;
_textEntryGender.inputView = _pickerAddEntryInfo;
_textEntryStatus.inputAccessoryView=toolbar;
_textEntryGender.inputAccessoryView=toolbar;
//DATEPICKER SETUP
_datepickerAddEntryInfo.hidden=YES;
[_datepickerAddEntryInfo setMaximumDate:maxDate];
[_datepickerAddEntryInfo setMinimumDate:minDate];
[_datepickerAddEntryInfo setDate:startDate];
_textDOB.inputView = _datepickerAddEntryInfo;
_textDOB.inputAccessoryView = toolbar;
}
#pragma mark - Text Field Editing Begins
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
//Picker - these text fields open up the Picker View
if (_textEntryStatus.editing == YES || _textEntryGender.editing == YES)
{
_pickerAddEntryInfo.hidden=NO;
}
//DatePicker - this text field opens up a Date Picker
if (_textDOB.editing == YES)
{
_datepickerAddEntryInfo.hidden=NO;
}
//TableView for Entry Location - This text field will segue to a Table View Controller populated with data
if (_textEntryLocation.editing == YES)
{
[textField resignFirstResponder];
}
}
#pragma mark - Text Field Editing Ends
-(void) textFieldDidEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
}
Use prepareForSegue: to perform any actions before segueing to another view controller.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"segueToMyTableView"]) {
// send resignFirstResponder to all textFields
[textEntryName resignFirstResponder];
[textEntryStatus resignFirstResponder];
[textEntryLocation resignFirstResponder];
[textEntryGender resignFirstResponder];
[textDOB resignFirstResponder];
// and remove all pickers views from the superview
[pickerAddEntryInfo removeFromSuperview];
[datepickerAddEntryInfo removeFromSuperview];
}
}
You can assign name to your segue in Storyboard like this (don't forget to select it on scheme)
Related documentation is here.
Related
I'm currently developing an app that has three buttons at the bottom of the layout (for customization reasons I couldn't use TabBar Controller or Segmented Control).
When I click one of these buttons, a new view should show up and inherite the buttons bar, along with its state (buttons can be in selected or unselected state).
I'm completely new to iOS development, so I tried following this guide (http://www.thinkandbuild.it/working-with-custom-container-view-controllers/), but problem is when I click a button, child view doesn't show up.
ContainerViewController.h
#interface ContainerViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *firstButton;
#property (weak, nonatomic) IBOutlet UIButton *secondButton;
#property (weak, nonatomic) IBOutlet UIButton *thirdButton;
#property (weak, nonatomic) IBOutlet UIView *detailView;
- (IBAction)click:(id)sender;
#end
ContainerViewController.m
#import "ContainerViewController.h"
#import "FirstViewController.h"
#interface ContainerViewController ()
#property UIContainerViewController *currentDetailContainerViewController;
#end
#implementation ContainerViewController
#synthesize firstButton, secondButton, thirdButton;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)click:(id)sender
{
// switch buttons state
// ...
[self addDetailController:sender];
}
- (void)presentDetailController:(UIContainerViewController*)detailVC{
//0. Remove the current Detail View Controller showed
if(self.currentDetailContainerViewController){
[self removeCurrentDetailContainerViewController];
}
//1. Add the detail controller as child of the container
[self addChildContainerViewController:detailVC];
//2. Define the detail controller's view size
detailVC.view.frame = [self frameForDetailController];
//3. Add the Detail controller's view to the Container's detail view and save a reference to the detail View Controller
[self.detailView addSubview:detailVC.view];
self.currentDetailContainerViewController = detailVC;
//4. Complete the add flow calling the function didMoveToParentContainerViewController
[detailVC didMoveToParentContainerViewController:self];
}
- (void)removeCurrentDetailContainerViewController{
//1. Call the willMoveToParentContainerViewController with nil
// This is the last method where your detailContainerViewController can perform some operations before neing removed
[self.currentDetailContainerViewController willMoveToParentContainerViewController:nil];
//2. Remove the DetailContainerViewController's view from the Container
[self.currentDetailContainerViewController.view removeFromSuperview];
//3. Update the hierarchy"
// Automatically the method didMoveToParentContainerViewController: will be called on the detailContainerViewController)
[self.currentDetailContainerViewController removeFromParentContainerViewController];
}
- (CGRect)frameForDetailController{
CGRect detailFrame = self.detailView.bounds;
return detailFrame;
}
- (void)addDetailController:(id)sender {
FirstViewController *detailVC = [[FirstViewController alloc]initWithString:#"First view"];
[self presentDetailController:detailVC];
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#class ContainerViewController;
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
- (id)initWithString:(NSString*)string;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController (){
NSString *text;
}
#end
#implementation FirstViewController
- (id)initWithString:(NSString*)string {
self = [super init];
if(self){
text = string;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.label.text = text;
}
#end
In my iOS application, I have a main View Controller with three buttons, which work like a tab bar: when I click one of the buttons, a new view controller is invoked.
I tried to implement this via container view containers, so I tried following this guide (http://www.thinkandbuild.it/working-with-custom-container-view-controllers/) and invoke the presentDetailController method in the viewDidLoad of the main controller.
Actually, no views are showed: someone can help me figuring out why? Thanks.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *btnOne;
#property (weak, nonatomic) IBOutlet UIButton *btnTwo;
#property (weak, nonatomic) IBOutlet UIButton *btnThree;
#property (weak, nonatomic) IBOutlet UIView *detailView;
- (IBAction)click:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "FirstViewController.h"
#interface ViewController ()
#property UIViewController *currentDetailViewController;
#end
#implementation ViewController
#synthesize btnOne, btnTwo, btnThree;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstViewController *fvc = [[FirstViewController alloc]initWithString:#"I'm the first Controller!"];
[self presentDetailController:fvc];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)click:(id)sender
{
// button selection stuff
[self addDetailController:sender];
}
- (void)presentDetailController:(UIViewController*)detailVC{
//0. Remove the current Detail View Controller showed
if(self.currentDetailViewController){
[self removeCurrentDetailViewController];
}
//1. Add the detail controller as child of the container
[self addChildViewController:detailVC];
//2. Define the detail controller's view size
detailVC.view.frame = [self frameForDetailController];
//3. Add the Detail controller's view to the Container's detail view and save a reference to the detail View Controller
[self.detailView addSubview:detailVC.view];
self.currentDetailViewController = detailVC;
//4. Complete the add flow calling the function didMoveToParentViewController
[detailVC didMoveToParentViewController:self];
}
- (void)removeCurrentDetailViewController{
//1. Call the willMoveToParentViewController with nil
// This is the last method where your detailViewController can perform some operations before neing removed
[self.currentDetailViewController willMoveToParentViewController:nil];
//2. Remove the DetailViewController's view from the Container
[self.currentDetailViewController.view removeFromSuperview];
//3. Update the hierarchy"
// Automatically the method didMoveToParentViewController: will be called on the detailViewController)
[self.currentDetailViewController removeFromParentViewController];
}
- (CGRect)frameForDetailController{
// newFrame's height should be currentFrame's height minus buttons' height
CGRect detailFrame = CGRectMake(0, 0, self.detailView.bounds.size.width, self.detailView.bounds.size.height-self.btnOne.frame.size.height);
return detailFrame;
}
- (void)addDetailController:(id)sender {
FirstViewController *detailVC = [[FirstViewController alloc]initWithString:#"First button clicked"];
[self presentDetailController:detailVC];
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#class ViewController;
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet UIButton *btnOne;
#property (weak, nonatomic) IBOutlet UIButton *btnTwo;
#property (weak, nonatomic) IBOutlet UIButton *btnThree;
- (id)initWithString:(NSString*)string;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController (){
NSString *text;
}
#end
#implementation FirstViewController
- (id)initWithString:(NSString*)string {
self = [super init];
if(self){
text = string;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.label.text = text;
}
#end
As part of creating FirstViewController, you are calling [super init] which produces a bare UIViewController. From your diagram, it seems as if you want to load a FirstViewController from your storyboard instead.
I suggest a sequence where you create your controller using instantiateViewControllerWithIdentifier:, then set a string property in the controller that you want to use as the label, and finally assign the string to the label when the controller's view loads.
I'm having problems passing data between two view controllers.
I've seen two ways to do this.
One involves implementing prepareForSeque: in the segue's source view controller and another involves setting properties in the viewDidLoad: method of the segue's destination view controller.
e.g.-
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toEmailReservationViewController"]) {
FLSendEmailViewController *controller = (FLSendEmailViewController *)segue.destinationViewController;
if (!controller.startDateField.text) {
controller.startDateField.text = #"today";
}
}
}
and
- (void)viewDidLoad
{
[super viewDidLoad];
self.startDateField.text = ((FLViewController *)self.presentingViewController).startDate;
}
I've got these to work on simple apps using two UIViewController. However, I can't get them to work on an app that has a UITabViewController connected to some UINavigationViewController connected to custom subclasses of UIViewController. When I click the button to perform the push seque, I get to the view I want, but the startDateField.text doesn't have the text from the segue's source view controller.
Why are these methods of sharing data not working with the tab controller and navigation controller setup?
I noticed that in prepareForSegue: I can't set controller.startDateField.text; as shown when I try to set it and use NSLog to display it. Could this be the problem? Is it possible that the property controller.startDateField.text doesn't exist yet?
I'm trying to grab the date from a datePicker in an instance of FLViewController, store this date in the property NSString *startDate, and in an instance of FLSendEmailViewController set NSString *startDateField.text to the `NSString *startDate'.
Here are the UIViewController subclasses I created:
FLViewController.h
#import <UIKit/UIKit.h>
#import "FLSendEmailViewController.h"
// import frameworks to use ad
#import AddressBook;
#import AddressBookUI;
#interface FLViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIScrollView *theScroller;
#property (weak, nonatomic) NSString *startDate;
#property (weak, nonatomic) NSString *stopDate;
- (IBAction)exitToReservations:(UIStoryboardSegue *)sender;
#end
FLViewController.m
#import "FLViewController.h"
#interface FLViewController ()
#property (weak, nonatomic) IBOutlet UIDatePicker *startReservationDatePicker;
#property (weak, nonatomic) IBOutlet UIDatePicker *stopReservationDatePicker;
#end
#implementation FLViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.theScroller setScrollEnabled:YES];
[self.theScroller setContentSize:CGSizeMake(280, 1000)];
//setup reservationDatePicker
[self.startReservationDatePicker addTarget:self
action:#selector(startDatePickerChanged:)
forControlEvents:UIControlEventValueChanged];
[self.stopReservationDatePicker addTarget:self
action:#selector(stopDatePickerChanged:)
forControlEvents:UIControlEventValueChanged];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// add method called when user changes start date
- (void)startDatePickerChanged:(UIDatePicker *)datePicker
{
NSDateFormatter *dateFortmatter = [[NSDateFormatter alloc] init];
[dateFortmatter setDateFormat:#"dd--MM-yyyy HH:mm"];
// get date using stringFromData: method and getter datePicker.date
self.startDate = [dateFortmatter stringFromDate:datePicker.date];
NSLog(#"The start date is %#", self.startDate);
}
// add method called when user changes stop date
- (void)stopDatePickerChanged:(UIDatePicker *)datePicker
{
NSDateFormatter *dateFortmatter = [[NSDateFormatter alloc] init];
[dateFortmatter setDateFormat:#"dd--MM-yyyy HH:mm"];
// get date using stringFromData: method and getter datePicker.date
self.stopDate= [dateFortmatter stringFromDate:datePicker.date];
NSLog(#"The stop date is %#", self.stopDate);
}
- (IBAction)exitToReservations:(UIStoryboardSegue *)sender {
// execute this code upon unwinding
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toEmailReservationViewController"]) {
FLSendEmailViewController *controller = (FLSendEmailViewController *)segue.destinationViewController;
if (!controller.startDateField.text) {
controller.startDateField.text = #"today";
NSLog(#"in vc startDate is null but set to %#",controller.startDateField.text );
}
}
}
#end
FLSendEmailViewController.h
#import <UIKit/UIKit.h>
#class FLViewController;
#interface FLSendEmailViewController : UIViewController
#property (retain, nonatomic) IBOutlet UITextField *startDateField;
#property (retain, nonatomic) IBOutlet UITextField *stopDateField;
#end
FLSendEmailViewController.m
#import "FLSendEmailViewController.h"
#import "FLViewController.h"
#interface FLSendEmailViewController ()
- (IBAction)sendEmail:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *numberOfDoggies;
#property (weak, nonatomic) IBOutlet UITextField *emailAddressField;
- (IBAction)hideKeyboard:(id)sender;
#end
#implementation FLSendEmailViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.startDateField.text = ((FLViewController *)self.presentingViewController).startDate;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)sendEmail:(id)sender {
NSString *emailString = [NSString stringWithFormat:#"I would like you to watch my %# doggies from %# to %#. Thank you.", self.numberOfDoggies.text, self.startDateField.text, self.stopDateField.text];
NSLog(#"%#",emailString);
}
- (IBAction)hideKeyboard:(id)sender {
[self.startDateField resignFirstResponder];
}
#end
Import the FLSendEmailViewController.h to the "InitialViewController.h"
Add this property to the FLSendEmailViewController.h
#property (nonatomic, strong) NSString *exportedData;
Add this to the FLSendEmailViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.startDateField.text = self.exportedData
}
4.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toEmailReservationViewController"]) {
FLSendEmailViewController *controller = (FLSendEmailViewController *)segue.destinationViewController;
if (!controller.startDateField.text) {
controller.exportedData = #"today";
}
}
}
This "sharing method" works in any case when from a controller go to another controller.
So, in case of a navigation controller, if you want push another viewController passing the data, you have just to set the trigger in the Storyboard (if you are using storyboard) from the button, and the new viewController.
So, you will not met troubles. Otherwise, you are committing other type of errors, and in this case, update your question.
i'm new to developing with xcode,and i'm following the apple's tutorial:"Second's ios app tutorial". I've add a button to my scene "Add Sighting View Controller",and i want to switch this view to another(BirdsViewController)that have a list of bird's names. in my storyboard i've create a segue between the button and BirdsViewController and also connect the button to touch up inside, but when i run the app the button doesn't appear.Can anybody help me?thank you.
here's my code(i don't have implemented any other methods):
AddSightingViewController.h
#class BirdSighting;
#interface AddSightingViewController : UITableViewController
#property (weak, nonatomic) IBOutlet UITextField *birdNameInput;
#property (weak, nonatomic) IBOutlet UITextField *locationInput;
#property (strong, nonatomic) BirdSighting *birdSighting;
#property (strong, nonatomic) UIButton *showBirds;
-(IBAction)displayBirds:(id)sender;
AddSightingViewController.m
#import "AddSightingViewController.h"
#import "BirdSighting.h"
#import "BirdsViewController.h"
#import <UIKit/UIKit.h>
#class BirdSighting;
#interface AddSightingViewController ()
#end
#implementation AddSightingViewController
#synthesize showBirds;
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
if((textField == self.birdNameInput) || (textField == self.locationInput)) {
[textField resignFirstResponder];
}
return YES;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"ReurnInput"]) {
if ([self.birdNameInput.text length] || [self.locationInput.text length])
{
BirdSighting *sighting;
NSDate *today = [NSDate date];
sighting = [[BirdSighting alloc] initWithName:self.birdNameInput.text
location:self.locationInput.text date:today];
self.birdSighting = sighting;
}
}
}
BirdsViewController *viewController;
-(IBAction)showBirds:(id)sender {
viewController =
[[BirdsViewController alloc]
initWithNibName:#"BirdsViewController" bundle:nil];
[[self navigationController] pushViewController:viewController animated:YES];
}
I dont see any allocation and adding of button as subview to the viewcontroller's view.
I think in the app like other textfields, button is also IBOutlet. Declare button as an IBOutlet and connect the outlet to the button in the interface builder file.
#property (weak, nonatomic) IBOutlet UIButton *showBirds;
Or allocate the button and add as subview to viewcontroller's view.
I have two views. The first one is having 2 buttons and second one is having a label and a button. Am trying to change the text of the label based on the button pressed. In the code below, am calling an instance of second view and trying to change text in the label. But the problem is the text is not changing. Will appreciate if some one can help me here
#interface firstview : UIViewController {
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
}
#property(nonatomic, retain) IBOutlet UIButton *button1;
#property(nonatomic, retain) IBOutlet UIButton *button2;
-(IBAction)push:(UIButton *)sender;
#end
#import "firstview.h"
#import "secondview.h"
#implementation firstview
#synthesize button1;
#synthesize button2;
-(IBAction)push:(UIButton *)sender{
button1.tag = 1;
button2.tag = 2;
if(sender.tag == button1.tag){
secondview *v2 = [[secondview alloc]initWithNibName:#"secondview" bundle:Nil];
v2.title =#"first button";
v2.l1.text = #"BUTTON1";
[self.navigationController pushViewController:v2 animated:YES];
[v2 release];
}
else if(sender.tag == button2.tag){
secondview *v2 = [[secondview alloc]initWithNibName:#"secondview" bundle:Nil];
v2.title =#"Select";
v2.l1.text = #"BUTTON2";
[self.navigationController pushViewController:v2 animated:YES];
[v2 release];
}
}
#end
second view
#import <UIKit/UIKit.h>
#interface secondview : UIViewController {
IBOutlet UIButton *b2;
IBOutlet UILabel *l1;
}
#property(nonatomic, retain)IBOutlet UIButton *b2;
#property(nonatomic, retain)IBOutlet UILabel *l1;
-(IBAction)pop:(id)sender;
#end
#import "secondview.h"
#implementation secondview
#synthesize b2;
#synthesize l1;
-(IBAction)pop:(id)sender{
}
#end
At the time you are trying to set the label text, the view has not been loaded in your second view controller, so the label is nil.
Try moving the calls to after you push the view controller, or, better still (since only a view controller should change its views properties) have string properties on the second view controller for the label values, and set the label text value inside viewWillAppear.
From jrturton: The view is not been loaded in your second view controller, so the label is nil. What can you is declare a NSString property in secondview and you can set value of this property from firstview and then you can set this value to the label in viewWillAppear or viewDidLoad method.