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.
Related
Hey I converted my project to ARC automatically and the only thing I had to fix was that Xcode changed array that had a size of [8] to [4] (still don't know what was going on there)
However, I now realized I got another problem: every time I hit a button in my Popup, the app crashed if it is linked to an IBAction. If I remove the reference to the header and main file, the button is clickable, but as soon as i assign it to a method (even if the method is empty), the whole app jut freezes/crashes.
This is how I initiate my popup:
PopUpViewController *popViewController =
[[PopUpViewController alloc] initWithNibName:#"PopUpViewController" bundle:nil];
[popViewController setTitle:#"This is a popup view"];
[popViewController showInView:self.view
animated:YES];
popViewController.view.center=self.view.center;
Pretty basic stuff, I ripped it off a tutorial I found online. My header is this:
#interface PopUpViewController : UIViewController
- (IBAction)baa:(id)sender;
#property (strong, nonatomic) UIButton *ba; // I was trying to add those buttons as properties here
#property (strong, nonatomic) IBOutlet UIButton *kl; //but no luck whatsoever
#property (strong, nonatomic) IBOutlet UIView *popUpView;
#property (strong, nonatomic) IBOutlet UIView *ppp;
- (IBAction)openSomething:(id)sender;
- (IBAction)openYoutube:(id)sender;
- (IBAction)openFacebook:(id)sender;
- (void)showInView:(UIView *)aView animated:(BOOL)animated;
#end
And my main
#import "PopUpViewController.h"
#interface PopUpViewController ()
#end
#implementation PopUpViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)showAnimate
{
// not important for this question
}
- (void)removeAnimate
{
// shortened
}
- (IBAction)baa:(id)sender{
// NSLog(#"asd"); I commented it out, but even an empty method kills the app
// only if I leave a button unassigned to any method, the app "survives" a button click
}
- (IBAction)openSomething:(id)sender
{
// [[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://www.test.de"]];
}
- (IBAction)openYoutube:(id)sender
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"https://www.youtube.com/"]];
}
- (IBAction)openFacebook:(id)sender
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"https://www.facebook.com/"]];
}
- (void) doSomething{
// also tried an empty method with a "new" name over here to eliminate any caching errors, no luck
}
- (IBAction)closePopup:(id)sender {
[self removeAnimate];
}
- (void)showInView:(UIView *)aView animated:(BOOL)animated
{
[aView addSubview:self.view];
if (animated) {
[self showAnimate];
}
}
- (void)viewDidLoad
{
self.view.backgroundColor=[[UIColor blackColor] colorWithAlphaComponent:.0];
self.popUpView.layer.cornerRadius = 5;
self.popUpView.layer.shadowOpacity = 1.0;
self.popUpView.layer.shadowOffset = CGSizeMake(0.2f, 0.2f);
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Any ideas what I could do different? I referenced everything to everything else possible now and I don't even know how it looked before anymore, but I somehow think it has something to do with the referencing.
Thanks a lot in advance, Alex
I was able to figure out on my own:
In the header of my main ViewController I added
#property (strong, nonatomic) PopUpViewController *popViewController;
Which still fired the crash. But then I adjusted the popup "opening" block to
_popViewController =
[[PopUpViewController alloc] initWithNibName:#"PopUpViewController" bundle:nil];
[_popViewController setTitle:#"This is a popup view"];
[_popViewController showInView:self.view
animated:YES];
_popViewController.view.center=self.view.center;
(added the underscores) and now it's working perfectly again.
Actually I am curious why it worked before but I am not going to investigate this any further.
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];
So I'm trying to get a hang of using delegates, and I've watched a few tutorials on how to use them so far. I still find them confusing and after trying to implement one myself, have an issue that I can't seem to solve.
I have two ViewControllers, the first one ViewController contains a UITextField *sampleTextField and a button with the method switchViews. It also contains the protocol declaration with the method sendTextToViewController. SwitchViews is also linked to a segue that switches to the SecondViewController. In SecondViewController the only object is a UILabel *outputLabel When the user taps the button, it calls switchViews and the view changes to SecondViewController, and upon loading outputLabel should be changed to whatever text was entered in sampleTextField in ViewController. However the delegate method sendTextToViewController is never being called. All objects are created in Interface Builder.
Here is the code to make it a bit easier to understand:
ViewController.h
#import <UIKit/UIKit.h>
#protocol TextDelegate <NSObject>
-(void)sendTextToViewController:(NSString *)stringText;
#end
#interface ViewController : UIViewController
- (IBAction)switchViews:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *sampleTextField;
#property (weak, nonatomic) id<TextDelegate>delegate;
#end
Then declared this in ViewController.m
- (IBAction)switchViews:(id)sender {
NSLog(#"%#", self.sampleTextField.text);
[self.delegate sendTextToViewController:self.sampleTextField.text];
}
SecondViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface SecondViewController : UIViewController <TextDelegate>
#property (weak, nonatomic) IBOutlet UILabel *outputLabel;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize outputLabel;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)sendTextToViewController:(NSString *)stringText
{
NSLog(#"Sent text to vc");
[outputLabel setText:stringText];
}
I've looked at this and the first answer makes sense, but for some reason it's not working.
I do think that the problem is where I am setting calling [vc setDelegate:self], but not sure how to fix this. Some pointers in the right direction would be greatly appreciated. Keep in mind I'm new to obj-c so if you can explain what you are saying, that would be great. Thank you.
Your are creating a new instance of ViewController but you don't do anything with it.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
ViewController *vc = [[ViewController alloc]init];
[vc setDelegate:self];
}
The SecondViewController needs to have reference to the FirstViewController to be able to set itself as a delegate.
First you don't have to use delegation to do such a program.
A simpler way would be just creating a property in the SecondViewController that you'll pass the content of the textField into it.
Your code doesn't work because you called sendTextToViewController on a delegate that hasn't been set. You have set the delegate to a new instance of ViewController, not the one presented onscreen.
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;
}
I am new at xcode and I am learning something new each day, I have gotten stuck. I want to create a custom button on a second Storyboard (MapTwoViewController), lets say it is a custom button that looks like a cloud and it goes from left to right.
I have created the custom button in the storyboard and I have created the IBOutlet in the GWSMapTwoViewController.h so it looks like this and is linked to the button:
#import <UIKit/UIKit.h>
#interface GWSMapTwoViewController : UIViewController
#property (nonatomic, strong) IBOutlet UIButton *cloudAnimate;
#end
So in my GWSMapTwoViewController.m in my view did load I have the following:
#import "GWSMapTwoViewController.h"
#interface GWSMapTwoViewController ()
#end
#implementation GWSMapTwoViewController
#synthesize cloudAnimate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Move UIView
cloudAnimate.center = CGPointMake(200.0, 100.0);
[UIView animateWithDuration:2.0 animations:^{ cloudAnimate.center = CGPointMake(100.0, 200.0);}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
It just doesn't want to animate, it just goes straight to the end point, if I remove the animation code then the cloud appears at 200, 100 but if I put the animate code in it just moves to 100, 200 or whatever coordinates i put in. It just doesn't animate so its either in the starting point or the end point.
Can anyone tell when what i am doing wrong?
Move your animation code in
- (void)viewDidAppear:(BOOL)animated
because viewDidLoad is called before the view is visible.
Don't forget to call super