I am trying to take advantage of inputAccessoryView and displaying help text and previous and next buttons. However I have many UITextFields spanning across many ViewControllers. So I would like to have a reusable UIView for the inputAccessoryView.
To do this, I have created a xib file ('SetupKeyboardAccessory') and a ViewController ('SetupKeyboardAccessoryViewController') attached to that xib.
SetupKeyboardAccessory:
SetupKeyboardAccessoryViewController:
#interface SetupKeyboardAccessoryViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *helpTextLabel;
#property (weak, nonatomic) IBOutlet UIButton *previousButton;
#property (weak, nonatomic) IBOutlet UIButton *nextButton;
#end
Inside my MainViewController I have my UITextFields. This MainViewController is implementing UITextFieldDelegate:
MainViewController:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
// you can create the accessory view programmatically (in code), or from the storyboard
if (textField.inputAccessoryView == nil) {
SetupKeyboardAccessoryViewController *accessoryView =
[[SetupKeyboardAccessoryViewController alloc] initWithNibName:#"SetupKeyboardAccessory"
bundle:nil];
accessoryView.helpTextLabel.text = #"setting help text here";
textField.inputAccessoryView = accessoryView.view;
}
//self.navigationItem.rightBarButtonItem = self.doneButton;
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
When the text field begins editing, I initialize my SetupKeyboardAccessoryViewController, set the help text, and then set it to the inputAccessoryView. For some reason the help text does not get set.
I know I'm probably doing something wrong here with setting the view of the SetupKeyboardAccessoryViewController to the inputAccessoryView. I'm still fairly new to iOS development. So any help would be appreciated. Thank you!
It's not appropriate to create a view controller for the sole purpose of instantiating a view, only to then discard the view controller.
Your code would be much simpler if you just had a SetupKeyboardAccessoryView class that was a subclass of UIView. Then made the view in the nib file this class, and instantiated it with :
SetupKeyboardAccessoryView *accessoryView = [[[NSBundle mainBundle] loadNibNamed:#"SetupKeyboardAccessoryView" owner:nil options:nil] firstObject]
Figured out what the problem is after a little bit of digging. Turned out when I was trying to set the text of helpTextLabel, helpTextLabel itself was nil.
This is due to outlets not being set until the view controllers view has been fully instantiated. (source: https://stackoverflow.com/a/4005968/986105)
So in my SetupKeyboardAccessoryViewController.m file, I added my own init function: (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil withHelpText:(NSString*)helpText
And then in viewDidLoad function, I would set the text of UILabel.
SetupKeyboardAccessoryViewController.m:
#interface SetupKeyboardAccessoryViewController ()
{
NSString* helperText;
}
#end
#implementation SetupKeyboardAccessoryViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil withHelpText:(NSString*)helpText
{
self = [self initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
helperText = helpText;
return self;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.helpTextLabel.text = helperText;
}
- (IBAction)previousButton:(id)sender {
NSLog(#"prev button pressed");
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
So in my MainViewController, I would just call my init function and remove the line to set the text of the UILabel.
MainViewController:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
// you can create the accessory view programmatically (in code), or from the storyboard
if (textField.inputAccessoryView == nil) {
SetupKeyboardAccessoryViewController *accessoryView =
[[SetupKeyboardAccessoryViewController alloc] initWithNibName:#"SetupKeyboardAccessory"
bundle:nil withHelpText:#"setting help text here"];
textField.inputAccessoryView = accessoryView.view;
}
//self.navigationItem.rightBarButtonItem = self.doneButton;
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
Related
I'm developing an iOS application and I have a strange problem.
The application sends local notifications to the user and when he taps on it, my app programmatically chooses a ViewController, sets its labels and images and then displays it to the user. But it simply doesn't work! Labels and images are not set. Here's my code in AppDelegate.m
- (void) manageLocalNotification:(UILocalNotification *) notification {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
if ([self.theme intValue] == 1) {
ADATheme1ViewController *notifyViewController = [[ADATheme1ViewController alloc] init];
[notifyViewController.titleLabel setText:self.title];
[notifyViewController.bodyLabel setText:self.text];
[notifyViewController.bgImage setImage: [self getImageFromURL:self.background]];
self.window.rootViewController = notifyViewController;
} else {
ADATheme2ViewController *notifyViewController = [[ADATheme2ViewController alloc] init];
[notifyViewController.titleLabel setText:self.title];
[notifyViewController.bodyLabel setText:self.text];
[notifyViewController.offerLabel setText:self.offer];
[notifyViewController.bgImage setImage: [self getImageFromURL:self.background]];
self.window.rootViewController = notifyViewController;
}
}
I made some debugging and my properties (text, title, offer and so on) are properly set. The method getImageFromUrl: returns an UIImage* and it works.
My ViewControllers are very simple, here's the code (but nothing special)
.h file
#import
#interface ADATheme1ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIImageView *bgImage;
#property (strong, nonatomic) IBOutlet UILabel *titleLabel;
#property (strong, nonatomic) IBOutlet UILabel *bodyLabel;
#end
.m file
#import "ADATheme1ViewController.h"
#interface ADATheme1ViewController ()
#end
#implementation ADATheme1ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
#end
and there's a .xib file attached.
Can you help me?
Solved: the view weren't loaded so the properties were set to nil.
I added just a line of code to "force" the loading of my view before setting labels:
[notifyViewController view];
I have a view with a label in it. The lower side of this view is filled with a subview which has it’s own view controller. This subview has a button. My goal: I want to change the label by pressing the button in the subview.
I have tried the code beneath. It works fine when I let the ViewWillAppear method of the delegate call the ‘doSomeTask’ method of the SubviewController. A timer begins to count and after a few seconds, the SubviewController calls the delegates changeLabel method, and the label is changed. However, when I call the ‘doSomeTask’ method manually by pressing the button, the delegate isn’t listening. The call doesn’t reach the changeLabel method.
Probably I am doing something ridiculously stupid here. Forgive me, I’m just learning iOS programming. Thanks in advance for all the feedback.
MyViewController.h
#import <UIKit/UIKit.h>
#import "MySubViewController.h"
#interface MyViewController : UIViewController
#property (strong, nonatomic) IBOutlet UIView *detailView;
#property (strong, nonatomic) IBOutlet UILabel *theLabel;
- (IBAction)changeLabel:(id)sender;
#end
MyViewController.m
#import "MyViewController.h"
#import "MySubViewcontroller.h"
#interface MyViewController ()
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
MySubViewController *subVC = [[MySubViewController alloc] init];
[self addChildViewController:subVC];
[self.detailView addSubview:subVC.view];
// [subVC setDelegate:self]; (no success trying this)
[subVC didMoveToParentViewController:self];
}
-(void)viewWillAppear:(BOOL)animated
{
MySubViewController *mySubVC = [[MySubViewController alloc] init];
[mySubVC setDelegate:self];
[mySubVC doSomeTask]; // this works fine
}
// delegate method
- (void)changeLabel{
self.theLabel.text = #"Hello!";
}
MySubviewController.h
#import <UIKit/UIKit.h>
#protocol MySubViewControllerDelegate <NSObject>
#required
- (void)changeLabel;
#end
#interface MySubViewController : UIViewController
#property (nonatomic, assign) id delegate;
- (IBAction)changeButton:(id)sender;
- (void)doSomeTask;
- (void)goChangeLabel;
#end
MySubViewController.m
#import "MySubViewController.h"
#interface MySubViewController ()
#end
#implementation MySubViewController
#synthesize delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)goChangeLabel
{
[[self delegate] changeLabel];
}
- (void)doSomeTask
{
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(goChangeLabel) userInfo:nil repeats:NO];
}
- (IBAction)changeButton:(id)sender {
// [self doSomeTask]; (no succes trying this)
}
#end
Your problem is this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
MySubViewController *subVC = [[MySubViewController alloc] init];
[self addChildViewController:subVC];
[self.detailView addSubview:subVC.view];
// [subVC setDelegate:self]; (no success trying this)
[subVC didMoveToParentViewController:self];
}
-(void)viewWillAppear:(BOOL)animated
{
MySubViewController *mySubVC = [[MySubViewController alloc] init];
[mySubVC setDelegate:self];
[mySubVC doSomeTask]; // this works fine
}
In these 2 methods you have created 2 separate variables of type MySubViewController. You have only set the delegate on the variable created inside viewWillAppear.
These are not static classes, singletons or anything else similar. If you create a variable of one type it is in no way linked to the other. The same way you can create multiple NSString's that have no bearing on each other.
Create it like so:
#implementation MyViewController
{
MySubViewController *_subVC;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_subVC = [[MySubViewController alloc] init];
}
now you can use _subVC everywhere in that file as the one reference
I'm trying to implement simgle AdBanner instance for multiple views in an iOS app. For implementing AdbannerDelegate in a viewController one has to do
bannerview.delegate= self;
where bannerview is an instance of AdBannerView. This delegate method however has to be implemented in every viewController which amounts up to a lot of repeating code. How can I make up a simple class that implements all delegate methods and then I call use them in every viewController.
I think the viewControllers you are using are subclasses of UIViewController.
And you are saying all the viewControllers have the same delegate methods.
So,what i want to do is create new ViewController class (UIDelgateViewController) by SubClassing UIViewController and add all delegate methods there , and have all the other viewControllers subclass UIDelgateViewController.
The code goes like this,
.h file->
#interface UIDelegateViewController : UIViewController<ADBannerViewDelegate>
#property ADBannerView *bannerView;
#end
.m file ->
#import "UIDelegateViewController.h"
#interface UIDelegateViewController ()
#end
#implementation UIDelegateViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_bannerView = [[ADBannerView alloc] init];
_bannerView.delegate =self;
}
-(void)bannerDelegateMethod{
}
Now your Some viewController ->
#import "UIDelegateViewController.h"
#interface SomeViewController : UIDelegateViewController
#end
#import "SomeViewController.h"
#interface SomeViewController ()
#end
#implementation SomeViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view addSubview:self.bannerView];
self.bannerView.frame = ..../
}
If you want to keep always on the screen the same banner while navigating and changing views, you should consider to use View Controller containtment API
A great example is that remarkable sample code written by Apple, that shows how to keep the same banner instance while moving in a tabbar or navigation controller. It could be also a great start for you project.
This question already has answers here:
Accessing Method from other Classes Objective-C
(8 answers)
Closed 9 years ago.
This is my viewcontroller1.m buttons userinteractionenabled function,
-(void) BtnUserInteractionStatus {
oneBtn2.userInteractionEnabled = NO;
oneBtn3.userInteractionEnabled = NO;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self BtnUserInteractionStatus];
}
This is my viewcontroller2.m buttons userinteractionenabled function access from viewcontroller1.m,
#import "ViewController1.h"
- (void)viewDidLoad {
[super viewDidLoad];
svc = [[StageViewController alloc]init];
[svc BtnUserInteractionStatus];
}
my viewcontroller2.h,
#import "ViewController1.h"
#interface ViewController2 : UIViewController {
StageViewController *svc;
}
#property (assign) StageViewController *svc;
But, this is not working. If there is any wrong please correct it.
This will be your ViewController2.m
#import "ViewController1.h"
- (void)viewDidLoad
{
[super viewDidLoad];
svc = [[ViewController1 alloc]initWithNibName:#"ViewController1" bundle:nil];
[self.view addSubview:svc.view];
}
ViewController2.h
#import "ViewController1.h"
#interface ViewController2 : UIViewController
{
ViewController1 *svc;
}
ViewController1.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
[self BtnUserInteractionStatus]; /*Provide your call to BtnUserInteractionStatus within init function*/
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(void)BtnUserInteractionStatus
{
oneBtn2.userInteractionEnabled = NO;
oneBtn3.userInteractionEnabled = NO;
}
Whenever you want the object library elements of a viewController loaded from another ViewContoller you need to define its xib and then add its corresponding view as either a subview of the present viewcontroller or push the viewcontrller from the current ViewController .Simply calling the BtnUserInteractionStatus method using its currently created instance wont help..
Hope it Helps !!
I am working on a very basic app that displays a popover when the user is entering text into a UITextField. Unfortunately, the popover is not showing up and the default keyboard is appearing (which shouldn't). Here is my relevant code below:
NumberPadViewController.h
#import <UIKit/UIKit.h>
#import "NumberViewController.h"
#interface NumberPadViewController : UIViewController <UITextFieldDelegate> {
IBOutlet UITextField *numTest;
}
#property (nonatomic, strong) NumberViewController *numberPicker;
#property (nonatomic, strong) UIPopoverController *numberPickerPopover;
#end
NumberPadViewController.m
- (BOOL)textFieldShouldBeginEditing:(UITextField *) textField
{
// Create popover controller if nil
if(_numberPickerPopover == nil){ //make sure popover isn't displayed more than once in the view
_numberPickerPopover = [[UIPopoverController alloc]initWithContentViewController:_numberPicker];
}
[_numberPickerPopover presentPopoverFromRect:numTest.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
return NO;
}
My popover class is called NumberViewController.h
#interface NumberViewController : UIViewController {
}
#property (strong, nonatomic) IBOutlet UIButton *oneButton;
NumberViewController.m
#import "NumberViewController.h"
#interface NumberViewController ()
#end
#implementation NumberViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
NSInteger buttonHeight = _oneButton.frame.size.height * 4;
NSInteger buttonWidth = _oneButton.frame.size.width * 3;
self.contentSizeForViewInPopover = CGSizeMake(buttonWidth, buttonHeight);
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I have created the UITextField in Storyboard, and set the delegate there. Can anyone see what I am doing wrong?
Thanks in advance to all who reply.
Ensure the textFieldShouldBeginEditing delegate method is being called. The rest of the code looks correct.
This is just a thought, but when a popover does a popover thing i think it becomes first responder, but your text view is first responder... so it might not be able to over do it.... if this is the error then before you tell the popover to appear you can say [textView resignFirstResponder]; and see if that helps.... it's just a thought though not 100% sure i will have to do some testing ~
also check to see if _numberPicker is not nil aswell i don't know what happens if you try to display a popover with no controller but you can see if that's the problem
Seeing as your popover isn't represented in the storyboard (if I read your post right) I think you need to add the popover view as a subview in code. Something like:
[self addSubview:_numberPickerPopover];
There are potentially a few places to do this. Probably makes the most sense in your textFieldShouldBeginEditing: method, after you've inited it.