In Storyboard I have a TabBarController set as the initial view controller which connects ("view controller" relationship) to a Navigation Controller, which in turn connects to a View controller (iphone5VC).
How is it possible to programmatically change the view controller iphone5VC to iphone4VC? I have to decide which of iphone5VC or iphone4VC I will display depending on the phone size (iphone4, 5)
Thanks a lot to both of you. I finally decided to have only one Storyboard and use specific viewcontrollers on an adhoc basis when the 3.5 screen really needs to have a slightly different layout.
What I did is:
Added <UITabBarControllerDelegate> in the viewcontroller .h file from which the user presses on the TabBar to select the view.
Added in the viewdidLoad of the .m file:
UITabBarController *tbc = self.tabBarController;
[tbc setDelegate:self];
and then added in the same file:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
UIStoryboard *myStoryBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
CGSize result = [[UIScreen mainScreen] bounds].size;
if (tabBarController.selectedIndex == 1) // button # 2 pressed
{
if (result.height == IPHONE4_HEIGHT)
{
navController = (UINavigationController *) [myStoryBoard instantiateViewControllerWithIdentifier:#"ViewControlleriphone4"];
[self presentViewController:navController animated:NO completion:nil];
}
else
{
navController = (UINavigationController *) [myStoryBoard instantiateViewControllerWithIdentifier:#"ViewControlleriphone5"];
[self presentViewController:navController animated:NO completion:nil];
}
}
}
If I'm reading your question correctly, you want to include a "check" in your app where the result will set the size of your view controllers, and I'm assuming the layout of the views contained within, based upon which phone the user has. If I have this correct, check out this thread. Also, I would strongly recommend using Auto Layout, which will automatically place the views inside your view controller, regardless of screen size and layout (portrait/landscape).
If I'm not understanding your question, maybe paste a screenshot or some code. Hope this helps, good luck!
So if i am understanding you correctly, you really want to load a separate storyboard (and associated viewController)depending on the device type.
if so, what you need to do is have your main storyboard only contain the initial TabBarController, Navigation Controller, and a subclass of UIViewController we'll call dynamicViewController. The dynamicViewController will load the appropriate storyboard based on the device type. Obviously the various storyboards will need to exist (in the code below, the storyboards are named iphoneV4.storyboard and iphoneV5.storyboards)
So your dynamicViewController, simply needs the following -(void)viewDidLoad method;
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController __unused * targetViewController = nil;
CGRect screenBounds = [[UIScreen mainScreen] bounds];
UIStoryboard *targetStoryboard = (screenBounds.size.height == 568) ? [UIStoryboard storyboardWithName:#"iphoneV5" bundle:nil] : [UIStoryboard storyboardWithName:#"iphoneV4" bundle:nil];
targetViewController = [targetStoryboard instantiateInitialViewController];
if (self.parentViewController && ![self.parentViewController isKindOfClass:UITabBarController.class] && ![self.parentViewController isKindOfClass:UINavigationController.class]) {
// replace self with the target view controller
[self.parentViewController addChildViewController:targetViewController];
[self.view.superview insertSubview:targetViewController.view aboveSubview:self.view];
[self.view removeFromSuperview];
[self removeFromParentViewController];
} else { // tab bars, nav controllers, and modal dialogs
[self addChildViewController:targetViewController];
CGRect f = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
targetViewController.view.frame = f;
[self.view addSubview:targetViewController.view];
}
}
Related
I have many storyboards in my project to have modules with specific functionalities. In one of my storyboard, I have a navigation controller, which push the initial view controller of another storyboard. When I push it, the navigation bar is removed and there is no way to get this specific bar back. When I put another navigation controller in my new storyboard, the navigation bar is resetted with an ugly transition (it comes from the right and replace the older one).
This is how I push my new storyboard's view controller :
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:aStoryboardName bundle:nil];
UIViewController *SideBarInitialViewController = [storyboard instantiateInitialViewController];
UIStoryboardSegue *segue = [[GDFromRightCustomSegue alloc] initWithIdentifier:aSegueIdentifier source:aSource destination:SideBarInitialViewController];
[segue perform];
I perform a custom segue as well to get rid of the basic animation (the view coming from below) :
UIView *sourceView = [self.sourceViewController view];
UIView *destinationView = [self.destinationViewController view];
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
CGFloat screenWidth = [[UIScreen mainScreen] bounds].size.width;
destinationView.frame = CGRectMake(screenWidth, 0.0, screenWidth, screenHeight);
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
[window insertSubview:destinationView aboveSubview:sourceView];
[UIView animateWithDuration:0.4 animations:^{
destinationView.frame = CGRectOffset(destinationView.frame, -screenWidth, 0.0);
sourceView.frame = CGRectOffset(sourceView.frame, -screenWidth, 0.0);
} completion:^(BOOL finished){
[self.sourceViewController presentViewController:self.destinationViewController animated:false completion:nil];
}];
Is there a way to push the new storyboard without animate the navigation bar, or even better, to have the older navigation controller in my new storyboard ?
In your source storyboard drag a new UIViewController and then drag a ** Modal segue** to this new UIViewController from your source ViewController. Click on this segue and then in the attributes Inspector add a Identifier of segue (let say "newSegue") Identifier must be unique. Also set segue type to "Custom " and write "newSegue" in Segue Class
Now add a catagory on UIStoryBoardSegue with name newSegue and in the .m file write these two methods.
- (id) initWithIdentifier:(NSString *)identifier
source:(UIViewController *)source
destination:(UIViewController *)destination
{
return [super initWithIdentifier:identifier
source:source
destination:[[UIStoryboard storyboardWithName:#"YourDestinationStoryBoardName" bundle:nil] instantiateInitialViewController ]];
}
- (void)perform
{
UIViewController *source = (UIViewController *)self.sourceViewController;
[source presentViewController:self.destinationViewController
animated:YES
completion:Nil];
}
Now in your source ViewController when you want to presenth new View Controller write this line
[self performSegueWithIdentifier:#"newSegue" sender:nil];
Must Remember to replace "YourDestinationStoryBoardName" with your actual destination StoryBoard name in the above function.
Try this Hope this will work fine.
I'm playing around with view life cycles & am having trouble changing a view from the load of a different view.
In my ViewController.h i have:
-(void)viewDidAppear:(BOOL)animated{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
}
However this only causes the view to be between ViewController, and ViewController2 appearing with animation (in a loop).
I used the code in viewDidLoad however neither of the view's loaded (from reading you cannot change view until the viewWillAppear)
Update: When using the code in viewWillAppear, whose view is not in the window hierarchy error is thrown.
How does one change the view from view setup stage?
Update
Using the above code, inside & out of GCD, in viewDidLoad, viewWillAppear & viewDidAppear either results in an infinite loop of animated showing of the ViewController2, or crash on 2nd attempt of segue (result from the loop).
EDITED:
I'm not sure exactly what you're trying to do, but assuming you are wanting the first viewcontroller to appear and then the second viewcontroller to immediately animate on top of the first one, you should be able to accomplish using several options:
First you could just wrap your calls in a dispatch_async call:
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard
instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
});
Or you could use a show modally segue:
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"myModalSegue" sender:self];
});
}
Or you could use a navigation controller and use a standard show segue (formally push). This one doesn't require the dispatch_async:
- (void)viewDidLoad {
[super viewDidLoad];
[self performSegueWithIdentifier:#"myshowsegue" sender:self];
}
I've posted working examples of all three on: github
It is better to exchange views in loadView method.
- (void)loadView {
CGRect rect = [[UIScreen mainScreen] applicationFrame];
MyView *view = [[MyView alloc] initWithFrame:rect];
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
self.view = view;
}
I am trying to figure out for a while now, how should I use the annotation button to switch
to another mapView. The app I am working on uses MapBox - maps. I checked the exemples
provided by them, but programmatically switching between two maps is there always achieved
through tab bar (which is not the case I want to use).
I am working with storyboards and I understood it quit well, how the segue should be made
in the Interface builder, but I think I am not managing with the programmatically integrated
buttons on map views. I initiated 'id's in both header files and I proclaimed them in the
Identity Inspector as well.
This is the part of the code, where I implement the RMMMapView with the annotation in the
main View Controller - ViewController and it works perfectly:
- (void)viewDidLoad{
[super viewDidLoad];
RMMapBoxSource *onlineSource = [[RMMapBoxSource alloc] initWithMapID:(([[UIScreen mainScreen] scale] > 1.0) ? kRetinaMapID : kNormalMapID)];
_mapView = [[RMMapView alloc] initWithFrame:self.view.bounds andTilesource:onlineSource];
_mapView.tileSource = [[RMMapBoxSource alloc] initWithMapID:(([[UIScreen mainScreen] scale] > 1.0) ? kRetinaMapID : kNormalMapID)];
_mapView.centerCoordinate = CLLocationCoordinate2DMake(0,0);
_mapView.adjustTilesForRetinaDisplay = YES;
_mapView.zoom = 4;
_mapView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:_mapView];
_mapView.showsUserLocation = YES;
[_mapView setConstraintsSouthWest:[_mapView.tileSource latitudeLongitudeBoundingBox].southWest
northEast:[_mapView.tileSource latitudeLongitudeBoundingBox].northEast];
RMPointAnnotation *annotation = [[RMPointAnnotation alloc] initWithMapView:_mapView
coordinate:_mapView.centerCoordinate andTitle:#"Hello, world!"];
[_mapView addAnnotation:annotation];
}
and this is the part, where I try to call the LowContentMap viewController, from the ViewController - main ViewController:
- (void) prepareForSegue:(UIStoryboardSegue *) segue sender:(id) sender {
if ([segue.identifier isEqualToString:#"Hello, world!"]) {
//LowContentMap *lowContentMap = segue.destinationViewController;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
LowContentMap *lowContentMap = [storyboard instantiateViewControllerWithIdentifier:#"lowContentMap"];
lowContentMap.lcm = _vc;
}}
This is the part of the code, that should be filled in:
- (void)mapView:(RMMapView *)mapView annotationView:(RMPointAnnotation *)annotation calloutAccessoryControlTapped:(UIControl *)control{
[self performSegueWithIdentifier:#"ShowSomeViewController" sender:annotation];
}
It would be really great, if somebody would try to resolve the problem.
I followed the discusion between Noa and Kronos at:
Setting up a detail view controller using a segue
but I still think, the part with the 'id' is something I am doing wrong. Thanks in advance.
1. I think your problem is that you don't know how to display another viewController
You should give the "View Controller Programming Guide" a good read, especially the part "Presenting View Controllers from Other View Controllers"
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
I also recommend to check out some of the awesome WWDC videos that show how to use ViewControllers.
2. How to create and display a viewController
There are many ways to do it. E.g. using the storyboard to create and display the viewController, define a protocol in the child controller, override "performSegueWithIdentifier" to set the delegate and implement the protocol to dismiss the vc.
However, in your case, it seems to make sense to do it all programmatically. Thus, you need to:
a) find the right place to add your action
b) alloc and init your view controller:
MyController *myController = [[MyController alloc] init];
// setup as required, there should be at least a delegate (being able to dismiss the view)
myController.delegate = self;
If you have designed your viewController in a storyboard, you might want to use this alloc/init routine instead:
MyController *myController = [[UIStoryboard storyboardWithName:#"Main.storyboard" bundle:nil] instantiateViewControllerWithIdentifier:#"MyController"];
myController.delegate = self;
c) display your new view controller;
this depends on if you have a navigationController:
[self.navigationController pushViewController:myController animated:YES];
...or if you want to present it modally:
[self presentViewController:myController animated:YES completion:NULL];
d) dismiss when done;
when your other controller is done with whatever it does, it should inform its delegate (implement your own protocol!) that it's done and should be dismissed. The delegate is the original viewController that created (alloc'd/inited) the "myController":
// this method should be defined in a protocol and implemented in the vc that created (and owns) the child view controller
// typically, this is the parent view controller
- (void)done {
[self dismissViewControllerAnimated:YES completion:NULL];
}
if you used a navigationController it's not -dismissViewControllerAnimated:, but
[self.navigationController popViewControllerAnimated:YES];
hope this helps to clarify things
I am using ViewDeck to power the sliding UI in my iPad app but i'm hitting a few problems.
I want to size the leftViewController to a specific size regardless of the rotation. The code I have to setup ViewDeck is as follows oh and i'm using storyboards.
- (id)initWithCoder:(NSCoder *)aDecoder
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UINavigationController *navigationController = [storyboard instantiateViewControllerWithIdentifier:#"leftViewController"];
JWTimerGroupsViewController *timerGroupsViewController = navigationController.viewControllers[0];
IISideController *constrainedSizeLeftViewController = [[IISideController alloc] initWithViewController:navigationController];
JWMainTableViewController *middleViewController = (JWMainTableViewController *)[storyboard instantiateViewControllerWithIdentifier:#"middleViewController"];
[timerGroupsViewController setDelegate:middleViewController];
self = [super initWithCenterViewController:middleViewController leftViewController:constrainedSizeLeftViewController];
self.centerhiddenInteractivity = IIViewDeckCenterHiddenNotUserInteractiveWithTapToClose;
/* This below IS NOT the size of the left view controller? Just seems odd that it isn't */
[super setLeftSize:200];
[super setSizeMode:IIViewDeckViewSizeMode];
if (self) {
// Add any extra init code here
}
return self;
}
The setLeftSize appears to set the topViewControllers width? Which then makes the left view controller size inconsistent when rotating.
Also I'm seeing some really terrible blocky shadows when the topVC is opened and then the device is rotated.
Is it possible to fix the size of the left ViewController and the amount the top VC opens in ViewDeck?
EDIT
I have just found a reference to this method:
IISideController *constrainedSizeLeftViewController = [[IISideController alloc] initWithViewController:navigationController constrained:200];
Which DOES constrain the left viewcontroller to a specific value. But now there is still no way to have the top VC open to that width?!
You could try the approach suggested here: https://stackoverflow.com/a/16484446/928209
Basically it is:
instantiate your IIViewDeckController in code (not from the
storyboard)
set the center view of the view deck controller to the
rootViewController from your storyboard and side views to whatever
you need.
set the rootViewController of your app to the view deck
controller.
Here is my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard* storyboard = self.window.rootViewController.storyboard;
UINavigationController* leftSideVC = (UINavigationController*)[storyboard instantiateViewControllerWithIdentifier:#"tableNavController"];
UINavigationController* centerNavVC = (UINavigationController*) self.window.rootViewController;
IIViewDeckController* viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:centerNavVC leftViewController:leftSideVC rightViewController:nil];
self.window.rootViewController = viewDeckController;
viewDeckController.resizesCenterView = YES;
viewDeckController.sizeMode = IIViewDeckViewSizeMode;
[self.window makeKeyAndVisible];
return YES;
}
When I tried this approach coding in my IIViewDeckController after loading my storyboard, I found that a lot of my problems with view sizing went away. Before, for example, in order to make the side view a fixed width I had to set the leftSize property to (screenWidth - width) instead of the actual "width" I wanted. Once I made the IIViewDeckController the rootViewController of the app not via the storyboard but instead in code in my AppDelegate, I could set the fixed size to "width" and it worked properly.
I am working on an iPhone app but found that I require another view / window to get the user to input and save data / information there.
How do I add another view? Do I add it in interface builder and then link it in the main app delegate or will it have its own .h and .m files.
I selected a window view app to start with, do I need to start over with a flip side view app or can this just be added in anyway if I have the correct code there.
manny thanks
Carl
The Window app is perfect for you. In your AppDelegate file, you should have a section like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
// Configure and show the window
[window addSubview:[yourViewController view]];
[window makeKeyAndVisible];
}
This is the part of the code that declares, allocates and adds your custom view to the window. You have a couple choices for how to add the second view. You can either add it in place of this one, or add it after this one using a Navigation Controller. To add the navigation controller, change the above method to look like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//instantiate the venue view controller object
YourViewController *yourViewController = [[YourViewController alloc] initWithNibName:#"YourView" bundle:[NSBundle mainBundle]];
UINavigationController *yourViewControllerWrapper = [[UINavigationController alloc] initWithRootViewController: yourViewController];
// Configure and show the window
[window addSubview:[yourViewControllerWrapper view]];
[window makeKeyAndVisible];
}
There, we create your custom view, then wrap it in a navigation controller. The navigation controller is what gets added to the window. Next the code to switch to the second view would look like this, assuming you switch views on a button press:
-(IBAction)switchViewController{
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController];
}
Of course, you should replace the line
MySecondViewController *secondViewController = [[MySecondViewController alloc] init];
with the proper way of instantiating your second view controller. This could be from a nib file like above, or programmatically.
As far as creating the view files, you should create a nib in Interface builder for the layout of everything, then create a .h and .m file for the ViewController code itself.
you can also display new frame instead of new view. It is easier sometimes, as you don;t have to pass parameters - you are in one class:
CGRect frame = okresView.frame;
frame.origin.x = frame.size.width;
if ( [okresView superview] == nil )
{
[self.view addSubview:okresView];
}
okresView.frame = frame;
[okresDataTableView reloadData]; // przeĊadowanie tabeli na subwidoku
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.5];
frame.origin.x = 0;
okresView.frame = frame;
[UIView commitAnimations];
if you want new subview, you can use a few methods - just download few applications from XCode help and check how they do this. Nice example are in 'Elements' and 'UICatalog' application where you have flipped view and other examples.
// Create and push another view controller.
UIViewController *myViewController = [[UIViewController alloc] init];
myViewController.title = #"My First View";
myViewController.view.backgroundColor = [UIColor redColor];
//to push the UIView.
[self.navigationController pushViewController:myViewController animated:YES];