How to interrupt viewWillAppear hierarchy - ios

I have a rootViewController, in it's viewDidLoad method, I initialized another two ViewController2* object and their views as subview of rootViewController.view, then I set first ViewController2* controller.view.hidden = YES.
Then, on v1 has a button handler, when touch it, it present a UINavigationController, after that touch 'dismiss' button call dismissViewControllerAnimated on v1.
The question is: when dismiss complete, the two of ViewController2* fire viewWillAppear. How to make it only fire the viewWillAppear on the visible one, but not on the hidden one?
the rootViewController's implementation:
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.v1 = [[ViewController2 alloc] init];
self.v1.title = #"v1";
[self.view addSubview:self.v1.view];
self.v1.view.hidden = YES;
self.v2 = [[ViewController2 alloc] init];
self.v2.title = #"v2";
[self.view addSubview:self.v2.view];
UIButton * btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setTitle:#"POP" forState:UIControlStateNormal];
[btn sizeToFit];
[btn addTarget:self action:#selector(touchHandler:) forControlEvents:UIControlEventTouchDown];
[self.view addSubview:btn];
}
- (void)touchHandler:(id)sender {
UINavigationController * nc= [[UINavigationController alloc] initWithRootViewController:[[UIViewController alloc] initWithNibName:nil bundle:nil]];
((UIViewController *)[nc.viewControllers objectAtIndex:0]).navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"dismiss" style:UIBarButtonItemStyleBordered target:self action:#selector(dismissHandler:)];
[self presentViewController:nc animated:YES completion:nil];
}
- (void) dismissHandler:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
ViewController2:
#implementation ViewController2
- (void)viewWillAppear:(BOOL)animated
{
NSLog(#"%#",self.title);
}
#end

viewWillAppear will fire on your UIViewController's, even if the view controllers view is set hidden=YES.
You can surely test if (self.view.hidden == YES) in your viewWillAppear delegate method if you want to prevent some expensive operation from occurring, but beware that if you later make that view un-hidden, that viewWillAppear won't fire then.

Simple, the reason why those methods are called is because the viewController's view is part of the main window's view hierarchy. This means that it has a superview that has a superview that has a superview and so on until that superview is the main window.
Instead of hiding and unhiding the viewController views, you should instead add and remove them from their superview. Also, to make sure that viewWillAppear and viewDidAppear are called correctly at the correct times, take a look at ViewController Containment:
http://www.cocoanetics.com/2012/04/containing-viewcontrollers/

Related

Uinavigation Controller issues

Hi i created UInavigation controller in iOS programatically but the problem is when i move to next view controller i am directing to same screen.I created another view with name InfoView but when i push to InfoView it shows the same screen with buttons that i created in ViewController.
#import "AppDelegate.h"
#import "ViewController.h"
#interface AppDelegate ()
{
UINavigationController *navigation;
}
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
navigation = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
self.window.rootViewController = navigation;
[self.window makeKeyAndVisible];
return YES;
}
#import "ViewController.h"
#import "InfoView.h"
#interface ViewController ()
{
UIButton *RealVideo,*listen,*Readmat,*Look,*DiveIn;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor=[UIColor whiteColor];
[self designDeclare];
}
-(void)designDeclare{
RealVideo=[UIButton buttonWithType:UIButtonTypeCustom];
RealVideo.frame=CGRectMake(10,self.view.frame.size.height*0.2, CGRectGetWidth(self.view.frame)-20, CGRectGetHeight(self.view.frame)/7);
[RealVideo addTarget:self action:#selector(real:) forControlEvents:UIControlEventTouchUpInside];
[RealVideo setTitle:#"Real Video" forState:UIControlStateNormal];
RealVideo.backgroundColor=[UIColor colorWithRed:0.744f green:0.000f blue:0.000f alpha:1.00f];
[self.view addSubview:RealVideo];
listen=[UIButton buttonWithType:UIButtonTypeCustom];
listen.frame=CGRectMake(CGRectGetMinX(RealVideo.frame),CGRectGetMaxY(RealVideo.frame)+20, CGRectGetWidth(RealVideo.frame), CGRectGetHeight(RealVideo.frame));
// [listen addTarget:self action:#selector(Listen:) forControlEvents:UIControlEventTouchUpInside];
[listen setTitle:#"Listen" forState:UIControlStateNormal];
listen.backgroundColor=[UIColor purpleColor];
[self.view addSubview:listen];
Readmat=[UIButton buttonWithType:UIButtonTypeCustom];
Readmat.frame=CGRectMake(CGRectGetMinX(RealVideo.frame),CGRectGetMaxY(listen.frame)+20, CGRectGetWidth(RealVideo.frame), CGRectGetHeight(RealVideo.frame));
// [Readmat addTarget:self action:#selector(Listen:) forControlEvents:UIControlEventTouchUpInside];
[Readmat setTitle:#"Reading Material" forState:UIControlStateNormal];
Readmat.backgroundColor=[UIColor colorWithRed:0.000f green:0.412f blue:0.851f alpha:1.00f];
[self.view addSubview:Readmat];
Look=[UIButton buttonWithType:UIButtonTypeCustom];
Look.frame=CGRectMake(CGRectGetMinX(RealVideo.frame),CGRectGetMaxY(Readmat.frame)+20, CGRectGetWidth(RealVideo.frame), CGRectGetHeight(RealVideo.frame));
[Look addTarget:self action:#selector(Look) forControlEvents:UIControlEventTouchUpInside];
[Look setTitle:#"Look" forState:UIControlStateNormal];
Look.backgroundColor=[UIColor colorWithRed:0.400f green:1.000f blue:0.400f alpha:1.00f];
[self.view addSubview:Look];
DiveIn=[UIButton buttonWithType:UIButtonTypeCustom];
DiveIn.frame=CGRectMake(self.view.frame.size.width*0.7,CGRectGetMaxY(Look.frame)+20, CGRectGetWidth(RealVideo.frame)/4,CGRectGetHeight(RealVideo.frame)/1.5);
[DiveIn setTitle:#"Dive In" forState:UIControlStateNormal];
DiveIn.backgroundColor=[UIColor colorWithRed:0.941f green:0.471f blue:0.353f alpha:1.00f];
[self.view addSubview:DiveIn];
}
-(void)real:(id)sender{
}
-(void)Look{
InfoView *infoVC=[[InfoView alloc]init];
[self.navigationController pushViewController:infoVC animated:YES];
}
]1
A navigation controller works like a stack so you can push and pop viewcontroller exactly like a stack behaves in the real world. Think of a navigation controller as a stack of viewcontrollers, so you cant actually add a UIView, but what you would like to do instead is to add the uiview as a subview in your view controller and push that view controller onto the navigation controller stack with a simple:
[navigationcontroller pushViewController:aViewcontroller];
Please read through Apple Documentation for more insight.
You can't push a View. You need to push a View Controller.
If you want to show the View on top of the same View Controller, then you need to add the InfoView as the subView, preferably with animation.
But if you wanted to push the InfoView then you should create a UIViewController in your Storyboard and then add the InfoView as that View Controller's subview.
Let's say you create a new View Controller called InfoViewcontroller which is going to hold the InfoView. Now go to the InfoViewcontroller's -viewDidLoad method and add the following line
InfoView *infoVC=[[InfoView alloc]initWithFrame:self.view.frame];
[self.view addSubview:infoVC];
However, as you don't want to touch your storyboard, you may want to add it as a subView with animation. So, you can change your Look method with something like-
-(void)Look{
InfoView *infoVC=[[InfoView alloc]initWithFrame:self.view.frame];
[UIView transitionWithView:self.view
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[self.view addSubview:infoVC];
}
completion:NULL];
}
When the InfoView.m looks like-
#import "InfoView.h"
#implementation InfoView
-(id)initWithFrame:(CGRect)frame{
self=[super initWithFrame:frame];
if(self){
self.backgroundColor=[UIColor whiteColor];
}
return self;
}
#end
Note: you need an -initWithFrame method as your InfoView needs to know it's frame size.

how to change ContentOffSet of UIScrollView Xcode

I create one UIScrollView with programmatically code and I have one button in my view (not exist in UIScrollView).
when I click on this button go to next page with modal transition. I create Cancel button in next page that when I click on it back to main page (this page have UIScrollView).
I want when click on Cancel button and return to main page call one method that is in main page and in this method change ContentOfSet my ScrollView... but not working!!!!
this is my code:
mainView.m
- (void)viewDidLoad{
UIScrollView *scrollbar = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0,width, height)];
scrollbar.directionalLockEnabled = YES;
scrollbar.backgroundColor = [UIColor whiteColor];
scrollbar.maximumZoomScale = 1.0;
scrollbar.minimumZoomScale = 1.0;
scrollbar.clipsToBounds = YES;
scrollbar.showsHorizontalScrollIndicator = YES;
scrollbar.pagingEnabled = YES;
[scrollbar setContentSize:CGSizeMake(scrollbar.frame.size.width * 4,scrollbar.frame.size.height)];
scrollbar.contentOffset = CGPointMake(0, 0);
scrollbar.delegate = self;
[self.view addSubview:scrollbar];
[super viewDidLoad];
}
-(void)ChangeMainScrollContentOffset{
scrollbar.contentOffset = CGPointMake(scrollbar.frame.size.width * (3), 0);
}
this button is in root View :
- (IBAction)AddView:(id)sender{
AddStationController *add = [[AddStationController alloc]initWithNibName:#"AddStationController" bundle:nil];
[add setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self.view.window.rootViewController presentViewController:add animated:YES completion:nil];
}
this button is Cancel button for return in my mainView:
- (IBAction)BackView:(id)sender{
mainView *main = [[mainView alloc]init];
[main ChangeMainScrollContentOffset];
[self dismissViewControllerAnimated:YES completion:nil];
}
please guide me about that!!!
I so confused why not working ContentOffSet!!!
I think your problem is that you didn't add ChangeMainScrollContentOffset
method to your ViewController.h file.
Just add it in ViewController.h file and than call it.
You second viewController should have reference to previous view controller.
When you do this:
mainView *main = [[mainView alloc]init];
[main ChangeMainScrollContentOffset];
You create another instance of mainView which not on screen and change contentOffset on ANOTHER scrollView :)
You should add property delegate to your AddStationController
AddStationController.h
#property (nonatomic, weak) mainView* delegate;
mainView:
- (IBAction)AddView:(id)sender{
AddStationController *add = [[AddStationController alloc]initWithNibName:#"AddStationController" bundle:nil];
>> add.delegate = self; <<
[add setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self.view.window.rootViewController presentViewController:add animated:YES completion:nil];
}
Cancel button action
- (IBAction)BackView:(id)sender{
>> [self.delegate ChangeMainScrollContentOffset]; <<
[self dismissViewControllerAnimated:YES completion:nil];
}

self.navigationItem.hidesBackButton = YES and go back with swipe gesture on iOS7

I write the codes below in my UIViewController that uses UINavigationController.
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.hidesBackButton = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>) self;
}
I build and run my app,
self.navigationItem.hidesBackButton = YES;
above that works correctly, but
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>) self;
that one DO NOT works.
So, I re-write the code below.
- (void)viewDidLoad {
UIBarButtonItem *backBarButton = [[UIBarButtonItem alloc] initWithCustomView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 44.0f, 44.0f)]];
backBarButton.tintColor = [UIColor clearColor];
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
self.navigationItem.leftBarButtonItem = backBarButton;
}
It works correctly.
However, I want to use the first example.
The first one clearly express what I want to do.
Does someone have any idea?
In viewDidLoad, the view controller is not yet contained in a navigation controller, so the navigationController property is nil, which is why that line has no effect.
That said, assigning the delegate of UINavigationController's interactivePopGestureRecognizer is not good practice (I'm pretty sure it expects to be assigned to the navigation controller). Try disabling the gesture recognizer in viewWillAppear: instead:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}

Make modal push segue programmatically — Objective-c

I have a button, which when is pressed, adds a new subview with other buttons on it. I have done like this.
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget: #selector(newView)];
- (void)newView
{
UIView *newView = [[UIView alloc]initWithFrame:CGRectmake(0,0,100,100)];
[self.view addSubview:newView];
}
Now when the button is pressed the new view is just added. I want to animate the new view like I can do in the IB, with push segue modal style. How can I do that programmatically?
You can do that with performSegueWithIdentifier, here is the code
- (void)newView
{
//execute segue programmatically
[self performSegueWithIdentifier: #"MySegue" sender: self];
}
Try something like this.
- (void)newView
{
[self.view addSubview:newView]
newView.frame = // somewhere offscreen, in the direction you want it to appear from
[UIView animateWithDuration:10.0
animations:^{
newView.frame = // its final location
}];
}
You can present a new viewcontroller like this:
- (void)newView
{
//Embed your new View into a plain UIViewController
UIView *newView = [[UIView alloc]initWithFrame:CGRectmake(0,0,100,100)];
UIViewController *yourNewViewController= [[UIViewController alloc] init];
controller.view = newView;
//Present it animated
[self presentViewController:yourNewViewController animated:YES completion:nil];
}
Hope it helps! :)

creating a UIToolbar programmatically

I wish to add a UIToolbar programmatically to a view when a user clicks on a button (in my case when they zoom in on a photo).
It seems to work fine when I create the toolbar in the click method and add to the subview but if I create the toolbar in the viewDidLoad method, assign it to an instance variable,and add that instance variable later to the subview on click, nothing appears. The debugger shows that the instance variable is a UIToolbar and is not null. I didn't want to create and destroy the same toolbar on every click so I thought it was better just to keep it as an instance variable that I add and remove from the view as needed. Is this the right approach?
Why is it visible in the one case and not the other.
Setup
#synthesize toolBar;
- (UIToolbar*)createToolbar
{
UIToolbar* toolbar = [[UIToolbar alloc] init];
toolbar.frame = CGRectMake(0, self.view.frame.size.height - 44, self.view.frame.size.width, 44);
UIBarButtonItem *shareButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(sharePhoto:)];
NSArray *buttonItems = [NSArray arrayWithObjects:shareButton,nil];
[toolbar setItems:buttonItems];
return toolbar;
}
This works
- (void) clickMyButton {
toolBar = [self createToolbar];
[self.view addSubview:toolBar];
}
This doesn't show anything
- (void)viewDidLoad
{
[super viewDidLoad];
toolBar = [self createToolbar];
}
- (void) clickMyButton {
[self.view addSubview:toolBar];
}
Why doesn't it work in the latter case
The problem is that when viewDidLoad gets called, it is not guaranteed that the frames for your view and subviews are set. Try calling [self createToolbar] from viewWillAppear or viewDidAppear instead.

Resources