I don't know if the title explains the question itself but here it is ...
I have a UINavigationController which is the parentViewController of a UINavigationController. The thing is the childViewController behaves strange, when I add it as a child it first has the gap for the statusBar (it doesn't occupy the entire screen) and if I "solve" that "bug" by hiding and showing the navigationBar, the gap goes away but now the child doesn't respect the frame I set manually.
Then I tried to continue and when I presented a modal on the child and dismiss it, the entire child goes away ...
What would be wrong there? The parent-child relationship with both containers or what?
Thanks in advice
EDIT: Here's an example project showing the strange behavior
http://www.mediafire.com/?8saa68daqfkf335
EDIT 2: I found a solution actually and I didn't find it really clear on Apple Docs, it says the childViewControllers take its frame from the parentViewController they belong to, but it doesn't say that if the parentViewController "reappears" (like a push on it) the childViewControllers get resized again by the parentViewController frame ... Hope this helps anyone
I believe it would be better to present the second navigation view controller as a modal view controller.
For example, replace your current presentController selector with something like:
- (void)presentController:(id)sender {
ChildViewController1 *cvc = [[ChildViewController1 alloc] initWithNibName:#"ChildViewController1" bundle:nil];
nc3 = [[UINavigationController alloc] initWithRootViewController:cvc];
nc3.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:nc3 animated:YES completion:nil];
UIBarButtonItem *i = [[UIBarButtonItem alloc] initWithTitle:#"X" style:UIBarButtonItemStyleBordered target:self action:#selector(close)];
cvc.navigationItem.leftBarButtonItem = i;
}
Then, your close selector could become:
- (void)close {
[nc3 dismissViewControllerAnimated:YES completion:nil];
}
(though I'd recommend moving the creation of the button and handling the close actually in ChildViewController1.m).
Of course, this would take all the creation of the navigation controller off ViewController.m's viewDidLoad selector:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor blueColor];
UIButton *b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
b.frame = CGRectMake(0, 100, 100, 40);
[b setTitle:#"present" forState:UIControlStateNormal];
[b addTarget:self action:#selector(presentController:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:b];
}
Hope it works!
Related
I haven't embedd navigation controller with my view controller. Now i'm using a code to go back to home screen to with the use of back button but there nothing appears, i don't know why. I don't want to use navigation controller in my vc. This is the code,
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"car_marker.png"]
style:UIBarButtonItemStylePlain
target:self.navigationController
action:#selector(popViewControllerAnimated:)];
self.navigationItem.leftBarButtonItem = backButton;
It should look like this only,
You will need to change your approach because you cannot pop without a navigation controller.
You should embed your viewcontroller into navigation controller and then you can hide with [[self navigationController] setNavigationBarHidden:YES animated:YES]; and then you can add any kind of custom button to perform pop action.
For adding a custom back button to your view
- (void)addCustomBackButtonToView
{
UIButton *backButton = [[UIButton alloc] initWithFrame: CGRectMake(20, 20, 44.0f, 30.0f)];
[backButton setImage:[UIImage imageNamed:#"back.png"] forState:UIControlStateNormal];
[backButton addTarget:self action:#selector(popVC) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backButton];
}
- (void) popVC{
[self.navigationController popViewControllerAnimated:YES];
}
You can hide your navigation controller by below code self.navigationController.navigationBar.isHidden = true
and use swipegesture option to move back, even though you have to use navigation controller,#iPeter has a valid point.
1) Add two ViewControllers make first as initial controller(entry point).
2) Add view on both ViewController with size you wish to have.
3) Add buttons on both views as subviews.
4) create segue from firstButton ->(use show) -> second controller.
5) From second ->(use show) -> first controller.
see the image below-:
This is not preferred way of doing pop/push. You must use Navigation Controller(that works like a stack for controllers you push) that will provide you default Back button or you can create custom .
You can not push or pop view controllers as you are not using the Navigation controller. Try using Present & dismiss controller which can called from any controller Instace.
Step 1 : Present to " Controller which is shown with no navigation bar but back button"
[self presentViewController:#"<ViewControllerToBePresented>" animated:NO completion:nil];
Step 2: add backBatton in ViewDidLoad
-(void)addBack{
UIButton *backBtn = [[UIButton alloc] initWithFrame: CGRectMake(20.0f, 20.0f, 50.0f, 30.0f)];
[backBtn setTitle:#"back" forState:UIControlStateNormal];
[backBtn addTarget:self action:#selector(dismissViewController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backBtn];
}
Step 3: Dismisscontroller to go back to previous scene
-(void) dismissViewController{
[self dismissViewControllerAnimated:NO completion:nil];
}
I have a ViewController that contains a textfield. When the user begins editing the text, I want to display
a ViewController that the user can use to select the font for the textfield. I am using Xcode 5 with
storyboards and compiling for IOS 7. This is where I present the view controller...
- (void)textViewDidBeginEditing:(UITextView *)textView
{
FTViewController *fontSelector = [[FTViewController alloc] init];
[self presentViewController:fontSelector animated:YES completion:nil];
}
I am using a Cocoapods project called FTFontSelector to pick the font. In the FTViewController that gets
presented, I have the following code that runs when the view controller loads. This code adds a UIToolbar
with two buttons, one of which I would like to be used to dismiss the view controller, but all of the
attempts I have made at making this happen have not worked.
- (void)loadView;
{
CGRect frame = [[UIScreen mainScreen] applicationFrame];
self.textView = [[UITextView alloc] initWithFrame:frame];
self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.textView.textAlignment = NSTextAlignmentLeft;
self.textView.font = [UIFont systemFontOfSize:FONT_SIZE];
self.textView.text = #"Hello World!";
self.changeFontButton = [[UIBarButtonItem alloc] initWithTitle:#"Font"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(changeFont:)];
self.dismissFontButton = [[UIBarButtonItem alloc] initWithTitle:#"Dismiss"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(dismissFont:)];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(frame), 44)];
toolbar.tintColor = [UIColor lightGrayColor];
toolbar.translucent = YES;
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
toolbar.items = #[self.changeFontButton, self.dismissFontButton];
self.textView.inputAccessoryView = toolbar;
self.view = self.textView;
}
This is the method I call to dismiss the view controller that I need help with. I have commented out
what I have tried.
- (void)dismissFont:(id)sender;
{
[self.textView resignFirstResponder];
// This crashes!
//[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
}
I suspect part of my problem is that there is no navigation controller in my presented view controller,
but when I tried to add one, the text went behind the view (I could see a few pixels of the top of the text),
and there was no back button, so something I tried to do there was wrong.
I am still pretty new to IOS programmng, so there is a lot I still don't understand. I have the rest of
my app working pretty well now, but this last piece is giving me a headache. I am hoping someone here can
show me how to dismiss this view controller.
[[self presentingViewController] dismissViewControllerAnimated:NO completion:nil];
sends a message to the parent view controller of your view controller. This is clearly not what you want. At best it would dismiss your view controller.
[self dismissViewControllerAnimated:YES completion:NULL];
is what you should do.
From -dismissViewControllerAnimated:completion:
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, it automatically forwards the message to the presenting view controller.
In this case your view controller (self) is the presenting view controller.
i meet a very strange thing today: that my custom ViewController occasionally miss in responder chain
first i have a custom UIView, with a UIButton as its subview, then i set the target-action as usual:
[closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
of course, i implement the closeButtonPressed method in my custom UIViewController
in most time, it just worked fine. but occasionally, my ViewController miss the tap event, and finally i found that , the tap event pass to the AppDelegate, and the closeButtonPressed method in AppDelegate is invoked!
i spent a whole day in this problem, and still don't know why. can you give me a clue? thanks a lot. following is the code, hope it can help:
the code to init and present my ViewController and View:
YLSRegisterStepOneViewController *step1Controller = [[YLSRegisterStepOneViewController alloc] initWithNibName:nil bundle:nil];
step1Controller.view = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
step1Controller.modalPresentationStyle = UIModalPresentationFormSheet;
step1Controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:step1Controller animated:YES completion:nil];
the code of the UIView:
UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
closeButton.frame = CGRectMake(10, 10, 50, 50);
[closeButton setTitle:NSLocalizedString(#"button_close", #"") forState:UIControlStateNormal];
[closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:closeButton];
the code of the UIViewController:
-(void) closeButtonPressed
{
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];// to dismiss self
}
additional: aside the UIButton, there is a UITextField. when this problem happens, if i click the UITextField, then click the UIButton, UIViewController works fine
You set controller property of YLSRegisterStepOneView like this:
YLSRegisterStepOneViewController *step1Controller = [[YLSRegisterStepOneViewController alloc] initWithNibName:nil bundle:nil];
YLSRegisterStepOneView *step1View = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
step1Controller.view = step1View;
step1View.controller = step1Controller;
You add the button in YLSRegisterStepOneView's initWithFrame: method, don't you?
So [closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside]; self.controller here is still nil.
step1View.controller = step1Controller; is called after [closeButton addTarget:self.controller action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
updated:
You say the responder chain confuses you, I think the problem is that you assign view controller's view property like this step1Controller.view = step1View; which is not recommended. If you want to use your custom view as viewcontroller's view, do this:
Override loadView method in viewcontroller.
You can override this method in order to create your views manually. If you choose to do so, assign the root view of your view hierarchy to the view property. The views you create should be unique instances and should not be shared with any other view controller object. Your custom implementation of this method should not call super.
- (void)loadView
{
YLSRegisterStepOneView *step1View = [[YLSRegisterStepOneView alloc] initWithFrame:CGRectMake(0, 0, 540, 720) OperType:operType];
self.view = step1View ;
}
I don't see where you are setting the controller property of the custom view which you are passing here:
[closeButton addTarget:*self.controller* action:#selector(closeButtonPressed) forControlEvents:UIControlEventTouchUpInside];
I think if you create/set the controller property in your view it would solve the problem (unless you are already doing it but code is not here).
I have made a barbuttonitem programmatically on a toolbar overlay. All of this appears when my camera is accessed. The button functions fine and the selector is fully capable of calling it.
Here's the overlay in .m , take a look at the doneButton selector.
- (UIView*)CommomOverlay {
//Both of the 428 values stretch the overlay bottom to top for overlay function. It
doesn't cover it.
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,420)];
UIImageView *FrameImg = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,420)];
[FrameImg setImage:[UIImage imageNamed:#"newGraphicOverlay.png"]];
FrameImg.userInteractionEnabled = YES;
UIToolbar *myToolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 428, 320, 50)];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self
action:#selector(doneButtonPressed)];
[myToolBar setItems:[NSArray arrayWithObjects: cancelButton, flexiSpace2, flexiSpace,
doneButton, nil] animated:YES];
[view addSubview:FrameImg];
[view addSubview:myToolBar];
return view;
}
Here's method I'm using for my void function.
//NewViewController is the nib I want to bring up when done is clicked.
-(void)doneButtonPressed {
NewViewController *UIView = [[NewViewController alloc] initWithNibName:nil bundle:nil];
UIView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:UIView animated:NO];
[UIView release];
NSLog(#"Acknowledged!");
}
The button is being called, but nothing happens. As you can see I added an NSLog function to see whether it was being called or not. "Acknowledged" shows up in the log when the button is clicked, so it's not a problem with the selector. The app doesn't crash when i use the button either, which should occur had I done some heavily faulty coding (in fact I don't even get any warnings about it), as far as Xcode is considered, everything is fine which, needless to say isn't.
I also have my .h files of NewViewController in place correctly in the view controller in which this code is being implemented.
UIView is the name of a class. Don't use it as the name of a variable. At best it is hugely confusing and is a probable reason for your problems. Rename UIView to something like myView everywhere in doneButtonPressed.
Apple's "Mobile Human Interface Guidelines" says about Popovers:
When possible, allow people to close one popover and open a new one
with one tap. This behavior is especially desirable when several
different bar buttons each open a popover, because it prevents people
from having to make extra taps.
The only solution I can think right now is to track the position of the touch when dismissing the popover and check whether that was the position of another button.
Is there any easier way to do this?
PS: I searched in stackoverflow and googled quite a while before posting. Sorry, if this was asked here before.
UPDATE
I guess I didn't explain myself well. Let's say I have three buttons. All of them open a popover. My user taps button #1 and a popover opens. While the popover is open, the user taps button #2. The popover gets dismissed (because the user tapped outside of the popover - default behavior of non-modal popovers) and a new popover opens up because the user had clicked on button #2. All of that without having to tap twice: once to dismiss the popover and twice for opening the new one.
2nd UPDATE
I built a simple dummy to reproduce what I'm trying to do. When the user taps on a button and a popover is open, the method that opens the popovers doesn't get called. Therefore the user has to click twice to open the second popover. Any ideas?
#import "RootViewController.h"
#import "AViewController.h"
#interface RootViewController()
#property (nonatomic, retain) UIPopoverController *currentPopover;
#end
#implementation RootViewController
#synthesize currentPopover;
- (void)loadView
{
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
UIView *view = [[UIView alloc] initWithFrame:applicationFrame];
CGRect buttonFrame = CGRectMake(50, 100, 200, 40);
for (int i = 0; i < 3; i++)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:[NSString stringWithFormat:#"Button %i", i + 1] forState:UIControlStateNormal];
[button addTarget:self action:#selector(openPopover:) forControlEvents:UIControlEventTouchDown];
[button setFrame:buttonFrame];
[view addSubview:button];
buttonFrame.origin.y += 50;
}
self.view = view;
[view release];
}
- (IBAction)openPopover:(id)sender
{
AViewController *avc = [[AViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:avc];
[avc release];
UIPopoverController *tempPopover = [[UIPopoverController alloc] initWithContentViewController:navigationController];
[tempPopover setDelegate:self];
[tempPopover setPopoverContentSize:CGSizeMake(320, 500)];
[tempPopover presentPopoverFromRect:[sender frame] inView:[self view] permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
self.currentPopover = tempPopover;
[tempPopover release];
[navigationController release];
}
- (void)dealloc
{
[currentPopover release];
[super dealloc];
}
#end
If you use bar button items in a toolbar, the open popover is not automatically closed when you tap another bar button item. In these situations you should close the visible popover and open the other one in one step.
- (IBAction)sortAction {
[searchBarView resignFirstResponder];
[self.popoverController dismissPopoverAnimated:YES]; //clear popover
self.popoverController = popoverSetting;
[self.popoverController presentPopoverFromBarButtonItem:sortBarButtonItem
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; //show popover
}
hope will help you
Lets say you have 3 buttons and each opens a popup. You could use a state variable that tracks whether a popup is currently open, and inside each "open popup" method, close the existing one (if it is open) before opening the new popup.