Monotouch open document - UIDocumentInterationController - iphone

I want to open a document on my iphone app written in monotouch
- i.e. launch a PDF file in the default PDF viewer.
I think I should be using UIDocumentInterationController?
Anyone have any Ideas on this..
I have put together the following on a viewcontroller ( with a toolbar)
but it doesnt work :-( It does nothing!!
string s = string.Format("{0}",strFilePath);
NSUrl ns = NSUrl.FromFilename (s);
UIDocumentInteractionController PreviewController =
UIDocumentInteractionController.FromUrl(ns);
PreviewController.Delegate = new UIDocumentInteractionControllerDelegateClass();
PreviewController.PresentOpenInMenu(btnOpen,true);
public class UIDocumentInteractionControllerDelegateClass : UIDocumentInteractionControllerDelegate
{
public UIViewController FileViewController = new UIViewController();
public UIDocumentInteractionControllerDelegateClass ()
{
}
public override UIViewController ViewControllerForPreview (UIDocumentInteractionController controller)
{
return FileViewController;
}
public override UIView ViewForPreview (UIDocumentInteractionController controller)
{
return FileViewController.View;
}
}

First thing I would try, is ensuring when you present the options menu, that it is taking place on the main thread:
InvokeOnMainThread(delegate{
PreviewController.PresentOpenInMenu(btnOpen,true);
});
If that alone doesn't work, another thing I noticed is that you're creating a new view controller in the delegate class. It doesn't appear to be added to the stack anywhere in your code, so maybe thats why it's not showing. Code I've used is as follows:
PreviewController.Delegate = new UIDocumentInteractionControllerDelegateClass(this);
...
...
public class UIDocumentInteractionControllerDelegateClass : UIDocumentInteractionControllerDelegate
{
UIViewController viewC;
public UIDocumentInteractionControllerDelegateClass(UIViewController controller)
{
viewC = controller;
}
public override UIViewController ViewControllerForPreview (UIDocumentInteractionController controller)
{
return viewC;
}
public override UIView ViewForPreview (UIDocumentInteractionController controller)
{
return viewC.View;
}
public override RectangleF RectangleForPreview (UIDocumentInteractionController controller)
{
return viewC.View.Frame;
}
}
This will then use the current viewcontroller to present the preview in. The only other change I can think of using is rather than presenting from a UIBarButtonItem try:
PreviewController.PresentOpenInMenu(new RectangleF(320,320,0,500), this.View, true);
I hope this helps!

Related

ionic 2 ViewController for popTo

I want to use popTo ( http://ionicframework.com/docs/v2/api/components/nav/NavController/#popTo ) in my ionic 2 application. Which requires a ViewController ( http://ionicframework.com/docs/v2/2.0.0-beta.7/api/components/nav/ViewController/ )
I am not able to figure out how to create a page as a ViewController that is usable in popTo with the documents present over the internet.
Has someone used popTo ? any heads up !!
NavController.getByIndex(int index) returns a ViewController, so you can use: this.navCtrl.popTo(getByIndex(index)).
Don't forget to inject the NavControlelr properly
import { NavController } from 'ionic-angular';
class MyComponent {
constructor(public navCtrl: NavController) {
}
}
See here for Reference:
http://ionicframework.com/docs/v2/api/navigation/NavController/#getByIndex
this.navCtrl.popTo() also works if you provide a ViewController which is how I prefer to popTo(). It's dangerous to rely on the index because you may add a page to the flow which will change the index. This way you just give it the name of the page to pop back to.
let popToViewController = Utilities.getViewController(this.returnPageName, this.navCtrl);
this.navCtrl.popTo(popToViewController);
I had to create a utility method to obtain the ViewController from the NavController:
public static getViewController(pageName: string, navController: NavController): ViewController {
for (let viewController of navController.getViews()) {
if (viewController.name == pageName) {
return viewController
}
}
return null;
}

UIStatusBarStyle PreferredStatusBarStyle does not work on iOS 7

In my iPhone application built with Xcode 5 for iOS 7 I set UIViewControllerBasedStatusBarAppearance=YES in info.plist, and in my ViewController I have this code:
-(UIStatusBarStyle) preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
But the status bar is still black against the black background.
I know its possible to change this app-wide by setting UIViewControllerBasedStatusBarAppearance=NO in info.plist, but I actually need to alter this on a viewController by viewController basis at runtime.
I discovered that if your ViewController is inside a navigationController then the navigationController’s navigationBar.barStyle determines the statusBarStyle.
Setting your navigationBar’s barStyle to UIBarStyleBlackTranslucent will give white status bar text (ie. UIStatusBarStyleLightContent), and UIBarStyleDefault will give black status bar text (ie. UIStatusBarStyleDefault).
Note that this applies even if you totally change the navigationBar’s color via its barTintColor.
OK, here's the trick. You do have to add the key "View controller-based status bar" and set the value to No.
This is counter to what it appears the meaning of this key is, but even if you set the value to No, you can still change the appearance of the status bar, and whether it shows or not in any view controller. So it acts like "Yes" but set it to "No"!
Now I can get the status bar white or dark.
For preferredStatusBarStyle() to work within UINavigationController and UITabBarController I add the following code, which will get the preferred status bar style from the currently visible view controller.
extension UITabBarController {
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
public override func childViewControllerForStatusBarStyle() -> UIViewController? {
return visibleViewController
}
}
For Swift 3 those are not methods but properties:
extension UITabBarController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childViewControllerForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
The Swift 4.2 properties have been renamed:
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
Usage
class ViewController: UIViewController {
// This will be called every time the ViewController appears
// Works great for pushing & popping
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
I may be coming to this a bit late, but incase anyone else is looking for a working and verified app wide solution.
#mxcl is correct in describing why this is happening. In order to correct it, we simply create an extension (or category in obj-c) that overrides the preferredSatusBarStyle() method of UINavigationController. Here is an example in Swift:
extension UINavigationController {
public override func preferredStatusBarStyle() -> UIStatusBarStyle {
if let rootViewController = self.viewControllers.first {
return rootViewController.preferredStatusBarStyle()
}
return super.preferredStatusBarStyle()
}
}
This code simply extracts the first view controller (the root view controller) and unwraps it (in obj-c just check that it is not nil). If the unwrap is successful (not nil) then we grab the rootViewControllers preferredStatusBarStyle. Otherwise we just return the default.
Hope this helps anyone who might need it.
To provide more detail into the accepted answer, put the following line in your app delegate's didFinishLaunchingWithOptions: method:
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
Then, in your Info.plist, add View controller-based status bar appearance and set it to NO.
I believe that's how it should be done, NOT from the navigation controller, if you want the same status bar color for the entire app. You might have screens that are not necessarily embedded in a UINavigationController, or a different UINavigationController subclass somewhere else, and other things.
EDIT: You can also do it without typing any code: https://stackoverflow.com/a/18732865/855680
In viewDidLoad just write this
[self setNeedsStatusBarAppearanceUpdate];
just do that and it will work
can u please try this
Set UIViewControllerBasedStatusBarAppearance to NO.
Call [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
One more thing i have seen in your question that
you have wrote the method like this
-(void)UIStatusBarStyle PreferredStatusBarStyle ()
{
return UIStatusBarStyle.LightContent;
}
but it should be like this
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
iOS 13 Solution(s)
The highest-voted answer uses "legacy" code 👎
Setting the barStyle property is now (iOS 13+) considered a "legacy customization." According to Apple,
In iOS 13 and later, customize your navigation bar using the standardAppearance, compactAppearance, and scrollEdgeAppearance properties. You may continue to use these legacy accessors to customize your navigation bar's appearance directly, but you must update the appearance for different bar configurations yourself.
Regarding your attempt - You were on the right track!
UINavigationController is a subclass of UIViewController (who knew 🙃)!
Therefore, when presenting view controllers embedded in navigation controllers, you're not really presenting the embedded view controllers; you're presenting the navigation controllers! UINavigationController, as a subclass of UIViewController, inherits preferredStatusBarStyle and childForStatusBarStyle, which you can set as desired.
Any of the following methods should work:
Override preferredStatusBarStyle within UINavigationController
preferredStatusBarStyle (doc) - The preferred status bar style for the view controller
Subclass or extend UINavigationController
class MyNavigationController: UINavigationController {
override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
OR
extension UINavigationController {
open override var preferredStatusBarStyle: UIStatusBarStyle {
.lightContent
}
}
Override childForStatusBarStyle within UINavigationController
childForStatusBarStyle (doc) - Called when the system needs the view controller to use for determining status bar style
According to Apple's documentation,
"If your container view controller derives its status bar style from one of its child view controllers, [override this property] and return that child view controller. If you return nil or do not override this method, the status bar style for self is used. If the return value from this method changes, call the setNeedsStatusBarAppearanceUpdate() method."
In other words, if you don't implement solution 3 here, the system will fall back to solution 2 above.
Subclass or extend UINavigationController
class MyNavigationController: UINavigationController {
override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
OR
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
topViewController
}
}
You can return any view controller you'd like above. I recommend one of the following:
topViewController (of UINavigationController) (doc) - The view controller at the top of the navigation stack
visibleViewController (of UINavigationController) (doc) - The view controller associated with the currently visible view in the navigation interface (hint: this can include "a view controller that was presented modally on top of the navigation controller itself")
Note: If you decide to subclass UINavigationController, remember to apply that class to your nav controllers through the identity inspector in IB.
P.S. My code uses Swift 5.1 syntax 😎
Here is how I solved it. Usually the navigationController or tabBarController are the ones deciding the appearance of the status bar (hidden, color, etc).
So I ended up subclassing the navigation controller and overriding preferredStatusBarStyle. if the current visible ViewContorller implements StatusBarStyleHandler I ask for the value to be used as the style, if it doesn't I just return a default value.
The way you trigger an update of the status bar appearance is by calling setNeedsStatusBarAppearanceUpdate which triggers preferredStatusBarStyle again and updates UI according to what the method returns
public protocol StatusBarStyleHandler {
var preferredStatusBarStyle: UIStatusBarStyle { get }
}
public class CustomNavigationCotnroller: UINavigationController {
public override var preferredStatusBarStyle: UIStatusBarStyle {
if let statusBarHandler = visibleViewController as? StatusBarStyleHandler {
return statusBarHandler.preferredStatusBarStyle
}
return .default
}
}
Then usage
public class SomeController: UIViewController, StatusBarStyleHandler {
private var statusBarToggle = true
// just a sample for toggling the status bar style each time method is called
private func toggleStatusBarColor() {
statusBarToggle = !statusBarToggle
setNeedsStatusBarAppearanceUpdate()
}
public override var preferredStatusBarStyle: UIStatusBarStyle {
return statusBarToggle ? .lightContent : .default
}
}
Even with all the answers here i still didn't find the exact solution for me, but started with the answer from Daniel. What I ended up with was:
override var preferredStatusBarStyle: UIStatusBarStyle {
return visibleViewController?.preferredStatusBarStyle ?? .lightContent
}
in navigation controllers (similar for tab, just selectedViewController). And then it will respect the:
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
In each view controller unless you set it otherwise. I dont need to call setNeedsStatusBarAppearanceUpdate() anywhere, it just updates when you arrive at each view controller.
1) One setting for whole project:
If available, remove UIViewControllerBasedStatusBarAppearance key-value pair from your info.plist, or set NO without removing it. If it's not available in your info.plist, do nothing. Default is NO for this property.
Add below code to your AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
2) Different settings for different View Controllers:
Add UIViewControllerBasedStatusBarAppearance key-value pair to your info.plist and set it to YES.
If your View Controller is not embed in to Navigation Controller. Let's say MyViewController. just add code below to your MyViewController.m file. If your View Controller is embed in to Navigation Controller, create a new Cocoa Touch Class and make it subclass of UINavigationController. Let's say MyNC. Select Navigation Controller View on your Storyboard, at right pane; Utilities -> Identity Inspector -> Custom Class -> Class, type "MyNC". After linking Storyboard View with your "MyNC" Cocoa Touch Class, add code below to your MyNC.m:
- (BOOL)prefersStatusBarHidden {
return NO;
}
-(UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
If in case you wanted to hide the statusBar during splashScreen but wanted to change the style to light content (StatusBarInitiallyHidden on Plist has to be NO to hide statusBar on splash), you can add this to appDelegate's didFinishLaunchingWithOptions method to change to lightContent.
[[UIApplication sharedApplication]setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];
swift example
in AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent;
return true
}
in info.plist set View controller-based status bar appearance: NO
If you're using NavigationController, you can subclass NavigationController so that it consults its child view controller
// MyCustomNavigationController
- (NSUInteger)supportedInterfaceOrientations {
UIViewController *viewControllerToAsk = [self findChildVC];
return [viewControllerToAsk supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate {
UIViewController *viewControllerToAsk = [self findChildVC];
return [viewControllerToAsk shouldAutorotate];
}
- (UIStatusBarStyle)preferredStatusBarStyle {
UIViewController *viewControllerToAsk = [self findChildVC];
return [viewControllerToAsk preferredStatusBarStyle];
}
- (UIViewController *)findChildVC {
return self.viewControllers.firstObject;
}
Swift 4.2
extension UITabBarController {
open override var childForStatusBarStyle: UIViewController? {
return selectedViewController
}
}
extension UINavigationController {
open override var childForStatusBarStyle: UIViewController? {
return visibleViewController
}
}
You can set the status bar style. It will resembles the status bar like IOS 6 and below.
Paste this methods in your view controller
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleBlackOpaque;
}
and call this method from view did load like this
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f)
{
[self setNeedsStatusBarAppearanceUpdate];
}
swift example
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent;
return true
}
in info.plist set View controller-based status bar appearance: NO
I just want to add a note for a specific case I faced. I had another UIWindow in my app to display a chat face to be floating all over my app all the time. Doing this caused none of the solution above to work, and I am not really sure why! All what I have noticed is that my ViewController in the new UIWindow was the reason for that! And if I wanted to change the status bar style I have to do it in that view controller of the new UIWindow.
This note might help others who have a similar structure! So basically you can apply the solutions mentioned above in the ViewController of the new UIWindow.
Again this a specific case.
Thanks
Wanna some tricky? No needs to override status bar style in every view controller
First: Follow #Sahil Kapoor, add 'View controller-based status bar = YES' to plist
Second: Make a subclass of window's root view controller and return StatusBarTrackingController.
final class StatusBarTracker: UIViewController {
override var preferredStatusBarStyle: UIStatusBarStyle {
CustomThemeProvider.currentTheme.asStatusBarStyle
}
}
final class TabBarController: UITabBarController {
private let statusBarTracker = StatusBarTracker()
override var childForStatusBarStyle: UIViewController? {
statusBarTracker
}
}
extension TabBarController: CustomThemeUpdatable {
func applyCustomTheme(_ theme: CustomTheme) {
setNeedsStatusBarAppearanceUpdate()
}
}
// SceneDelegate
window?.rootViewController = TabBarController()
For swift 3, in your UIViewController:
override var preferredStatusBarStyle : UIStatusBarStyle { return UIStatusBarStyle.lightContent }

Monotouch Replacing the RootViewController

Using MonoTouch I add a LogonViewController to the Window and show it on FinishedLaunching:
window = new UIWindow(UIScreen.MainScreen.Bounds);
window.RootViewController = new LogonViewController();
window.MakeKeyAndVisible();
In the LogonViewController, how do I add the main VC, called MainViewContoller and remove the LogonViewController? (This is the action that will happen once the user is logged in.)
Even if it's possible to replace the window.RootViewController, that's not how it's usually done. Most of the time, you define your RootViewController and handle your navigation, including login, from there. That's at least how I do it.
//AppDelegate.cs
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window = new UIWindow (UIScreen.MainScreen.Bounds);
window.RootViewController = new MainViewController ();
window.MakeKeyAndVisible ();
return true;
}
//MainViewController.cs
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
if (not_logged_in)
PresentViewController (new LoginViewController (), true, ()=>{});
}
For what its worth this is how I've done it before.
public static void swapRootView(UIViewController newView, UIViewAnimationOptions opt)
{
UIView.Transition(mainWindow, 0.5, opt, delegate{
mainWindow.RootViewController = newView;
},null);
}
Then after login is ok, call that method with this option.
swapRootView(yourNewViewController, UIViewAnimationOptions.TransitionFlipFromRight);

MonoTouch UITableViewController and TableFooterView

I'm trying to develop a small iPhone application using MonoDevelop (v2.8) and MonoTouch (v4.2.2).
My home screen is represented by a UITableViewController which use a UITableView for presentation. I want to fill the UITableView.TableFooterView (which is a UIView object) with some other controls (two labels and two buttons).
To do this I have created a "subview" called SearchView, which is represented by a UIViewController and use a simple UIView for presentation. I assign this view as footer view of the tableview.
public partial class HomeScreen : UITableViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
SearchViewController searchViewController = new SearchViewController();
this.TableView.TableFooterView = searchViewController.View;
}
}
Is this right?
It is right to assume that usaually you create a view (UIView) and consume it by a UIViewController ?
- (void)loadView {
[super loadView];
sBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,0,320,30)];
sBar.delegate = self;
[self.view addSubview:sBar];
you can add subviews like this ,sbar is the search bar,u can also add any controllers like button ,labels ,textview,textfield in it.
In your UITableViewDataSource you can override public virtual UIView GetViewForFooter(UITableView tableView, int sectionIndex)
public override UIView GetViewForFooter(UITableView tableView, int sectionIndex)
{
// Write a method to get the proper Section via the sectionIndex
var section = GetSection(sectionIndex);
if (section != null)
{
if (section.FooterView == null && !string.IsNullOrEmpty(section.FooterText))
{
// Create your FooterView here
section.FooterView = CreateFooterView(tableView, section.FooterText);
}
return section.FooterView;
}
return null;
}
As of iOS 5 you will also need to override
public virtual float GetHeightForFooter(UITableView tableView, int sectionIndex)
and return the height of the FooterView

Switching to a TabBar tab view programmatically?

Let's say I have a UIButton in one tab view in my iPhone app, and I want to have it open a different tab in the tab bar of the TabBarController. How would I write the code to do this?
I'm assuming I unload the existing view and load a specific tab view, but I'm not sure how to write the code exactly.
Try this code in Swift or Objective-C
Swift
self.tabBarController.selectedIndex = 1
Objective-C
[self.tabBarController setSelectedIndex:1];
Note that the tabs are indexed starting from 0. So the following code snippet works
tabBarController = [[UITabBarController alloc] init];
.
.
.
tabBarController.selectedViewController = [tabBarController.viewControllers objectAtIndex:4];
goes to the fifth tab in the bar.
My opinion is that selectedIndex or using objectAtIndex is not necessarily the best way to switch the tab. If you reorder your tabs, a hard coded index selection might mess with your former app behavior.
If you have the object reference of the view controller you want to switch to, you can do:
tabBarController.selectedViewController = myViewController
Of course you must make sure, that myViewController really is in the list of tabBarController.viewControllers.
You can simply just set the selectedIndex property on the UITabBarController to the appropriate index and the view will be changed just like the user tapped the tab button.
I tried what Disco S2 suggested, it was close but this is what ended up working for me. This was called after completing an action inside another tab.
for (UINavigationController *controller in self.tabBarController.viewControllers)
{
if ([controller isKindOfClass:[MyViewController class]])
{
[self.tabBarController setSelectedViewController:controller];
break;
}
}
Like Stuart Clark's solution but for Swift 3:
func setTab<T>(_ myClass: T.Type) {
var i: Int = 0
if let controllers = self.tabBarController?.viewControllers {
for controller in controllers {
if let nav = controller as? UINavigationController, nav.topViewController is T {
break
}
i = i+1
}
}
self.tabBarController?.selectedIndex = i
}
Use it like this:
setTab(MyViewController.self)
Please note that my tabController links to viewControllers behind navigationControllers. Without navigationControllers it would look like this:
if let controller is T {
For cases where you may be moving the tabs, here is some code.
for ( UINavigationController *controller in self.tabBarController.viewControllers ) {
if ( [[controller.childViewControllers objectAtIndex:0] isKindOfClass:[MyViewController class]]) {
[self.tabBarController setSelectedViewController:controller];
break;
}
}
My issue is a little different, I need to switch from one childViewController in 1st tabBar to home viewController of 2nd tabBar. I simply use the solution provided in the upstairs:
tabBarController.selectedIndex = 2
However when it switched to the home page of 2nd tabBar, the content is invisible. And when I debug, viewDidAppear, viewWillAppear, viewDidLoad, none of them is called.
My solutions is to add the following code in the UITabBarController:
override var shouldAutomaticallyForwardAppearanceMethods: Bool
{
return true
}
I wanted to be able to specify which tab was shown by class rather than index as I thought it made for a robust solution that was less dependant on how you wire up IB. I didn't find either Disco's or Joped's solutions to work so i created this method:
-(void)setTab:(Class)class{
int i = 0;
for (UINavigationController *controller in self.tabBarContontroller.viewControllers){
if ([controller isKindOfClass:class]){
break;
}
i++;
}
self.tabBarContontroller.selectedIndex = i;
}
you call it like this:
[self setTab:[YourClass class]];
Hope this is helpful to someone
import UIKit
class TabbarViewController: UITabBarController,UITabBarControllerDelegate {
//MARK:- View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//Tabbar delegate method
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let yourView = self.viewControllers![self.selectedIndex] as! UINavigationController
yourView.popToRootViewController(animated:false)
}
}
Use in AppDelegate.m file:
(void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
{
NSLog(#"Selected index: %d", tabBarController.selectedIndex);
if (viewController == tabBarController.moreNavigationController)
{
tabBarController.moreNavigationController.delegate = self;
}
NSUInteger selectedIndex = tabBarController.selectedIndex;
switch (selectedIndex) {
case 0:
NSLog(#"click me %u",self.tabBarController.selectedIndex);
break;
case 1:
NSLog(#"click me again!! %u",self.tabBarController.selectedIndex);
break;
default:
break;
}
}
Like Stuart Clark's solution but for Swift 3 and using restoration identifier to find correct tab:
private func setTabById(id: String) {
var i: Int = 0
if let controllers = self.tabBarController?.viewControllers {
for controller in controllers {
if let nav = controller as? UINavigationController, nav.topViewController?.restorationIdentifier == id {
break
}
i = i+1
}
}
self.tabBarController?.selectedIndex = i
}
Use it like this ("Humans" and "Robots" must also be set in storyboard for specific viewController and it's Restoration ID, or use Storyboard ID and check "use storyboard ID" as restoration ID):
struct Tabs {
static let Humans = "Humans"
static let Robots = "Robots"
}
setTabById(id: Tabs.Robots)
Please note that my tabController links to viewControllers behind navigationControllers. Without navigationControllers it would look like this:
if controller.restorationIdentifier == id {