in watchOS I used presentControllerWithName to show a View Controller and to pass the context in this way
presentControllerWithName("NameOfTheViewController", context:"PassedContext")
Which is the equivalent in tvOS?
Best Regards
As noted in other answers, the way to programmatically show another view controller in tvOS (or iOS) is performSegueWithIdentifier:sender:. (Or presentViewController:animated:completion: if you're not getting your VCs from a storyboard flow.)
But you might not need to do it programmatically. In watchOS it's sometimes easiest to do it that way, but in iOS & tvOS, it's common to make controls directly perform storyboard transitions entirely from Interface Builder. Just control-drag (right-click-drag) from the button to another view controller. (More step-by-step instructions in Xcode Help.)
Unlike watchOS, the view controller transitions in iOS & tvOS don't include a way to pass context information. Not as part of the API, at least — you have to include a bit of glue code yourself to do that. How to do that is a pretty common question.
If you're using storyboard segues (generally, you should), the prepareForSegue:sender: method is typically where you do this — you get a reference to the new view controller that's about to be shown, and use some function or property you've defined on that view controller to pass it some context. It often looks something like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == mySegueIdentifier {
guard let destination = segue.destinationViewController as? MyViewControllerClass
else { abort("unexpected storyboard segue") }
destination.someProperty = someValue
}
}
You can find good examples of this when you create a new Xcode project with the Master-Detail App template.
tvOS is more similar to iOS than it is to watchOS, although they all have some similarities. In tvOS (like in iOS) you can use both performSegueWithIdentifier:sender: or presentViewController:animated:completion: depending on your situation.
For more on this, you can check out the UIViewController class reference.
Related
I'd like to be able to layout my view controller in code but see the layout displayed in interface builder.
I know I can create a UIView subclass, make that IBDesignable, and assign it to the view controller's view, but this would require that I make all other subviews properties of this UIView subclass instead of properties of the view controller.
The real desire is to be able to layout my view controllers in code but quickly see any changes without rebuilding the project. If this is possible with playgrounds instead, an answer describing how to do that would also be appreciated.
Thanks for any suggestions.
I found a workaround to test view controller layout using IBDesignable.
1.Layout your view controller in code just as you'd do normally
2.Create an IBDesignable UIView subclass and add the view controller's view as a subview.
3.Create a xib and set the class of its view to the subclass you created in step 2
To elaborate on step 2, your IBDesignable's initWithFrame: method may look like
{
self = [super initWithFrame:frame];
MyViewController *viewController = [MyViewController alloc] init];
viewController.view.frame = self.bounds;
[self addSubview:viewController.view];
return self;
}
So beyond this initWithFrame method, all of your layout code can be handled by your view controller. You may want to pass data to your view controller in your subview's prepareForInterfaceBuilder method.
In order to layout you own classes in Xcode you need first to import then in your swift playground: here more information.
After you do that, it's came the "tricky" part. In order to make your how class debuggable and visibile in playground, your class must conform to the protocol: CustomPlaygroundQuickLooacable:
Here there is a quick example from the WWDC:
By implementing this protocol, you're basically telling playground how to represent you hown class. I haven't fond any better solution yet.
I want to programmatically move from a viewController to another using Apple's new Swift language. I've googled and read through the docs, and I see how to use a single ViewController. Does anyone have an example or documentation on how to switch between View Controllers?
There are many ways to do this detailed in the class documentation for UIViewController.
Example 1
Here is an example of using the -presentViewConroller: method (assuming this code is written in a UIViewController subclass):
var secondViewController = UIViewController() //create your second view controller.
self.presentViewController(secondViewController, true, NULL)
Example 2
This is how you would present the second UIViewController via storyboards (again assuming this code is written in a UIViewController subclass):
self.preformSegueWithIdentifier("segueIdentfier", self);
By adding IMvxModalTouchView to MyView, let the view become modal. But, I cannot change it at runtime. i.e. MyView must be modal every time. Is it possible to make it more flexible, let say, Show(MvxShowViewModelRequest view, bool isModal); ?
This area of MvvmCross is called "preesentation"
Other Mvvm frameworks may refer to it as "INavigationService"
Within MvvmCross, the presenter on each platform is 100% overrideable. Some examples and source code links are provided on http://slodge.blogspot.co.uk/2013/06/presenter-roundup.html
If you want to implement some custom navigation hint, then:
all ShowViewModel calls have an presentationHint parameter - https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNavigatingObject.cs#L40
the presenters receive these hints in the PresentationValues property of the MvxViewModelRequest in the Show call
I am trying to use the Google Maps SDK for iOS in a subview of the main view which I created in the storyboard and linked to the view controller via an IBOutlet (I called it extraView, subclassed from UIView). When I follow the steps in the SDK getting started guide, the SDK works just fine, but it uses the uppermost view in the hierarchy (the main view), which I don't want. I want my map to be in a smaller portion of the screen and use the rest of the screen for something else. When I attempt to assign the mapView_ object (see the getting started guide) to self.extraView instead of self.view, the whole screen is black and I get an error in the console output:
"Application windows are expected to have a root view controller at the end of application launch"
Has anyone else figured this out? I can't find anything in the documentation and the sample code Google provides does not use a storyboard.
Here's how...
add a UIView into the view controller where you're working
set it's class to be GMSMapView in the identity inspector.
Then control-drag it to your code as you would for any other outlet.
You can lazily instantiate it in its setter...
- (void) setMapView:(GMSMapView *)mapView {
if (!mapView) {
mapView = [[GMSMapView alloc] initWithFrame:mapView.bounds];
}
_mapView = mapView;
}
To display a map Google's sample code becomes...
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:1.285
longitude:103.848
zoom:12];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
I solved my problem just removing the loadview code that i took from the example.
Just adding a view as sberley said should works.
just on thing more, on the identity inspector, that attribute that you have to change is class, at least it is on xcode 4.5
I got a very interesting problem here. My iPhone app has an UITabbarController as rootViewController in the AppDelegate.
If the app is opened the first time, it must be configured basically. For this purpose I create an UINavigationController and tell the tabbarController to present it modally:
firstRun = [[firstRunViewController alloc] init];
navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
When the configuration is done, I'd like to get rid of the firstRunViewController. I'm using this technique very often, using -dismissModalViewControllerAnimated:.
But in this constellation this doesn't work. It doesn't matter from what controller I'm calling the dismiss.
I tried it via the tabbarController, the rootViewController, the currently active viewController, of cause self and several other controllers.
EVERY TIME I call -dismissModalViewControllerAnimated: I get this exception:
'UIViewControllerHierarchyInconsistency', reason: 'presentedViewController for controller is itself on dismiss for: <UINavigationController:…
Can anybody help? Thanks in advance, with kind regards, Julian
EDIT
In my AppDelegate I'm using a UITabbarController as rootViewController for the main window:
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
Then I'm creating an UINavigationController and tell the UITabbarController to present the modalViewController:
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
When I now call -dismissModalViewControllerAnimated: on the firstViewController I'm getting the error from above.
In my opinion you are abusing UITabbarController. This class, even though a subclass of UIViewController, does not really use much of the UIViewController infrastructure.
What you want is a slight extension of what you have now. Create a new UIViewController subclass in your appDelegate, and add it as the single object to an array, and set the tabBar's viewControllers to this array. Set your subclass' hidesBottomBarWhenPushed to YES so it hides the tab bar when it becomes visible.
Now your app will launch and your UIViewController subclass will become the frontmost view. You can make this view the one you wanted to present modally, or you can present that view from your subclass using some kind of animation. Oh, and if you use the launch view as the background image for your subclass, you can really make this a smooth transition - I do this now.
When your modal view is done, then you can instantiate whatever views you want to then display, and set the UITabBarController to use those views with tabBarController.viewControllers (or the animated version). Poof, you UIViewController will get replaces (and under ARC just disappear).
I don't have a chance to test my hypothesis, but I suspect that this issue could depend on the fact that you are presenting the modal view too early, whereby too early means before the main window has had the chance to set up the tab bar controller. So, I would suggest this changes:
create a method to instantiate your navigation controller:
- (void)initializeAndPresentNavigationController {
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:firstRun];
[[self tabBarController] presentModalViewController:navCtrl animated:NO];
}
instead of presenting the navigation controller directly from appDidFinishLaunching, call the above method asynchronously:
[self performSelector:#selector(initializeAndPresentNavigationController) withObject:nil afterDelay:0.0];
Here the trick of calling the method as I do in 2 is that the call to initializeAndPresentNavigationController will be simply pushed on the main loop, and executed after your app has had the possibility to build its initial UI.
Hope it works for you.
I finally found the answer myself!
I just couldn't see the wood for the trees! I'm quite happy right now! :)
I did really silly things: In the last viewController of the setup viewControllers I had to change the tabars viewControllers corresponding to whether the user is administrator or not. So I did:
appDelegate.tabBarController.viewControllers = [NSArray arrayWithObjects:appDelegate.readState,
appDelegate.navCtrl,
appDelegate.settings, nil];
You can see that I was adding the AppDelegate's "navCtrl" to the tabbar's viewControllers. So I was trying to dismiss a viewController I just added to the parentViewControllers (UITabbarController) sub-controllers.
Dismissing something I want to present just in the same moment is NOT advisable! :))