second Tab is always greyed out in UITabbarController - ios

I'm trying to embed two NavBar Controllers into a UITabbarController, using the code below in the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[window makeKeyAndVisible];
// Configure and show the window.
FirstViewController *firstController = [[FirstViewController alloc] initWithNibName:nil bundle:NULL];
self.firstNav = [[UINavigationController alloc] initWithRootViewController:firstController];
SecondTableViewController *anotherOne = [[SecondTableViewController alloc] initWithNibName:nil bundle:NULL];
self.anotherNav = [[UINavigationController alloc] initWithRootViewController:anotherOne];
NSArray *twoViewControllers = [[NSArray alloc]initWithObjects:self.anotherNav,self.firstNav, nil];
self.tabBarController = [[UITabBarController alloc]init];
[self.tabBarController setViewControllers:twoViewControllers];
[window addSubview:self.tabBarController.view];
[window setRootViewController:tabBarController];
return YES;
}
The two tabs are displayed fine, with their names, but I can select the first one only, the second one is always greyed out and does not respond to touch events. I reversed the navController assignment into the Tabbar (i.e. in the array twoViewControllers), and each view is displayed fine (in the first tab).
The app delegate does not implement UITabbarDelegate and uiTabBarControllerDelegate. I don't use story boards.
Any obvious reason why the second tab is always greyed out ?
Sample Code:
It's just Apple's Locations tutorial (with ARC)
here
Then change :
(void)applicationDidFinishLaunching:(UIApplication *)application {}
for
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Configure and show the window.
RootViewController *cont1 = [[RootViewController alloc] initWithNibName:nil bundle:NULL];
RootViewController *cont2 = [[RootViewController alloc] initWithNibName:nil bundle:NULL];
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// Handle the error.
}
cont1.managedObjectContext = context;
cont2.managedObjectContext = context;
UINavigationController *aNav1 = [[UINavigationController alloc] initWithRootViewController:cont1];
UINavigationController *aNav2 = [[UINavigationController alloc] initWithRootViewController:cont2];
NSArray *twoViewControllers = [[NSArray alloc]initWithObjects:aNav1,aNav2, nil];
self.tabBarController = [[UITabBarController alloc]init];
[self.tabBarController setViewControllers:twoViewControllers];
//[window addSubview:[tabBarController view]];
[window setRootViewController:tabBarController];
[window makeKeyAndVisible];
}
and replace #interface LocationAppDelegate ...#end by
#interface LocationsAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
NSPersistentStoreCoordinator *persistentStoreCoordinator;
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
}
#property (nonatomic, strong) IBOutlet UIWindow *window;
#property (nonatomic, strong) UITabBarController *tabBarController;
- (IBAction)saveAction:sender;
#property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (weak, nonatomic, readonly) NSString *applicationDocumentsDirectory;
#end
and Compile and run.

Try to get rid of [window addSubview:self.tabBarController.view];

Related

Custom transition between UIViewControllers does not work

I have object that manage custom transition:
#interface NavigationManager : NSObject <UIViewControllerAnimatedTransitioning>
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext;
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext;
#property (nonatomic, assign) NSTimeInterval presentationDuration;
#property (nonatomic, assign) NSTimeInterval dismissalDuration;
#property (nonatomic, assign) BOOL isPresenting;
#end
#interface NavigationManager()
#property (nonatomic, strong) id<UIViewControllerContextTransitioning> transitionContext;
#end
#implementation NavigationManager
#synthesize presentationDuration, dismissalDuration, isPresenting;
-(id)init{
self = [super init];
if(self){
self.presentationDuration = 1.0;
self.dismissalDuration = 0.5;
}
return self;
}
-(NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext{
return self.isPresenting ? self.presentationDuration : self.dismissalDuration;
}
-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
self.transitionContext = transitionContext;
if(self.isPresenting){
[self executePresentation:transitionContext];
}
else{
[self executeDismiss:transitionContext];
}
}
...
#end
And in class that should process implement transitions:
#interface ViewController : UIViewController <UIViewControllerTransitioningDelegate>
#property (nonatomic, strong) NavigationManager navigationManager;
..
#end
#implementation
...
//Here I`m doing navigation to new UIViewController
- (void)navigateToNewScreen
{
DetailedNewsController *secVC = [[DetailedNewsController alloc] init];
secVC.fullDescription = fullDescription;
secVC.headerImage = a.imageView.image;
self.transitioningDelegate = self;
[self.navigationController pushViewController:secVC animated:YES];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
self.animationController.isPresenting = YES;
return self.animationController;
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
self.animationController.isPresenting = NO;
return self.animationManager;
}
#end
Default animation of transitioning is performed. Also navigation controller bar is not displayed after navigation.
UPDATE:
I thing problem in way how I`m creating UINavigationController in AppDelegate:
firstVC = [[ViewController alloc] init];
navController = [[UINavigationController alloc] initWithRootViewController:firstVC];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor blackColor];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
I'll make an answer with the new information you have provided. The reason I make it an answer is that I just don't want to give you some copy paste code, but to try to give a brief explanation behind it. If I understand correctly, you now want to present a ViewController with a custom transition.
So you got the custom transition working by changing your code to this:
secVC.transitioningDelegate = self;
secVC.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController:secVC animated:YES completion:nil];
Since we got that up and running, what's currently missing is the NavigationBar of the ViewController you want to show. Since you're presenting a ViewController, it won't be contained within the existing NavigationController stack in which the the ViewController you're presenting is within.
Therefore, you need to wrap your VC you want to present within a UINavigationController.
[self presentViewController:[[UINavigationController alloc] initWithRootViewController:secVC] animated:YES completion:nil];

SWRevealViewController not toggle

I'm trying to implement SWRevealViewController in a project without using storyboard. I think it's possible to do but i unfortunately failed. The button in the navigation bar does not perform the "revealToggle" action that is defined on him. So NavigationTableViewController is never shown. I don't understand why... I searched several hours a solution to this problem. Anyone help would be much appreciated.
#import "ContentViewController.h"
#import "NavigationTableViewController.h"
#interface ContentViewController()<SWRevealViewControllerDelegate>
#end
#implementation ContentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
//[self.navigationItem setHidesBackButton:YES animated:YES];
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = window;
ContentViewController *frontViewController = self;
NavigationTableViewController *rearViewController = [[NavigationTableViewController alloc] init];
UINavigationController *frontNavigationController = [[UINavigationController alloc] initWithRootViewController:frontViewController];
SWRevealViewController *revealController = [[SWRevealViewController alloc] initWithRearViewController:rearViewController frontViewController:frontNavigationController];
revealController.delegate = self;
[revealController panGestureRecognizer];
[revealController tapGestureRecognizer];
self.viewController = revealController;
self.window.rootViewController = self.viewController;
UIBarButtonItem *revealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"reveal-icon.png"]
style:UIBarButtonItemStyleBordered target:revealController action:#selector(revealToggle:)];
self.navigationItem.leftBarButtonItem = revealButtonItem;
}
I finally managed to solve my problem. According to John Lluch examples, i modified my code.
Here is the solution without using storyboards :
AppDelegate.h
#import <UIKit/UIKit.h>
#import "SplashScreenController.h"
#import "SWRevealViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UINavigationController *navigationController;
#property (strong, nonatomic) SplashScreenController *viewController;
#property (strong, nonatomic) SWRevealViewController *revealController;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "ContentViewController.h"
#import "NavigationTableViewController.h"
#interface AppDelegate()<SWRevealViewControllerDelegate>
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
SplashScreenController *frontViewController = [[SplashScreenController alloc] initWithNibName:#"SplashScreenController" bundle:nil];
NavigationTableViewController *rearViewController = [[NavigationTableViewController alloc] init];
UINavigationController *frontNavigationController = [[UINavigationController alloc] initWithRootViewController:frontViewController];
SWRevealViewController *revealController = [[SWRevealViewController alloc] initWithRearViewController:rearViewController frontViewController:frontNavigationController];
revealController.delegate = self;
self.window.rootViewController = revealController;
[self.window makeKeyAndVisible];
return YES;
}
ContentViewController.h
#import <UIKit/UIKit.h>
#interface ContentViewController : UIViewController
#end
ContentViewController.m
#import "ContentViewController.h"
#import "SWRevealViewController.h"
#import "NavigationTableViewController.h"
#import <sqlite3.h>
#interface ContentViewController()<SWRevealViewControllerDelegate>
#end
#implementation ContentViewController
- (void)viewDidLoad {
[super viewDidLoad];
SWRevealViewController *revealController = [self revealViewController];
[revealController panGestureRecognizer];
[revealController tapGestureRecognizer];
UIBarButtonItem *revealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"reveal-icon.png"] style:UIBarButtonItemStyleBordered target:revealController action:#selector(revealToggle:)];
self.navigationItem.leftBarButtonItem = revealButtonItem;
}

Different URI for each instance of UIViewController

I have a UITabController with five tabs. Each tab simply holds an instance of a custom UIViewController, and each instance holds a UIWebView.
I want the UIWebView in each tab to open a different URI, but I don't think it should be necessary to create a new class for each tab.
I can make it work if I do [self.webView loadRequest:] in -(void)viewDidLoad but it seems ridiculous to create five different classes with five different versions of viewDidLoad when all I really want to change is the URI.
Here's what I've tried:
appDelegate.h
#import <UIKit/UIKit.h>
#interface elfAppDelegate : UIResponder <UIApplicationDelegate, UITabBarControllerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UITabBarController *tabBarController;
#end
appDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
customVC *start = [[customVC alloc] init];
customVC *eshop = [[customVC alloc] init];
customVC *table = [[customVC alloc] init];
customVC *video = [[customVC alloc] init];
customVC *other = [[customVC alloc] init];
// Doesn't do anything... I wish it would!
[start.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"]]];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = #[start, eshop, table, video, other];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
customVC.h
#import <UIKit/UIKit.h>
#interface customVC : UIViewController <UIWebViewDelegate> {
UIWebView* mWebView;
}
#property (nonatomic, retain) UIWebView* webView;
- (void)updateAddress:(NSURLRequest*)request;
- (void)loadAddress:(id)sender event:(UIEvent*)event;
#end
customVC.m
#interface elfVC ()
#end
#implementation elfVC
#synthesize webView = mWebView;
- (void)viewDidLoad {
[super viewDidLoad];
self.webView = [[UIWebView alloc] init];
[self.webView setFrame:CGRectMake(0, 0, 320, 480)];
self.webView.delegate = self;
self.webView.scalesPageToFit = YES;
[self.view addSubview:self.webView];
}
Create a property of type NSURL* in your customVC.
Change your customVC's -(id)init method to -(id)initWithURL:(NSURL*)url as follows:
-(id)initWithURL:(NSURL*)url{
self = [super init];
if(self){
self.<URLPropertyName> = url;
}
return self;
}
Then call
[start.webView loadRequest:[NSURLRequest requestWithURL:self.<URLPropertyName>]];
in viewDidLoad
Then when you initialize your different instances of customVC, just use
customVC *vc = [customVC alloc]initWithURL:[NSURL URLWithString:#"http://..."]];
I suspect you are initialising your webview after calling it's loadRequest: method. To avoid this, it's a better practice to initialise nonatomic properties by overriding their setters:
- (UIWebView*)webview {
if (mWebView == nil) {
// do the initialization here
}
return mWebView;
}
This way your webview will be initialised when you first access it (while calling loadRequest:) and not after it, in your custom view controller's viewDidLoad method.

Combining Navigation Controller with Tab Bar Controller

As I mentioned in the title, I want to add Navigation Controller to my application which already has a Tab Controller. So trying to do the staff something like on this page. Anyway, something is wrong. UINavigationController is looking a blank page, even if has a view and some libraries.
Let me begin from the stracht:
In my AppDelegate, I'm setting tab bar controllers like this:
#interface MYAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UITabBarController *tabBarController;
#end
And here is .m file:
#implementation MYAppDelegate
#synthesize window = _window;
#synthesize tabBarController = _tabBarController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
application.applicationSupportsShakeToEdit = YES;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UINavigationController *viewController1 = [[[MYMainViewController alloc] init] initWithNibName: #"MYMainViewController" bundle:nil];
UIViewController *viewController2 = [[[MYPageViewController alloc] init] initWithNibName:#"MYPageViewController" bundle:nil];
UIViewController *viewController3 = [[[MYSearchViewController alloc] init] initWithNibName:#"MYSearchViewController" bundle:nil];
UIViewController *viewController4 = [[[MYPersonViewController alloc] init] initWithNibName:#"MYPersonViewController" bundle:nil];
// Initialize tabBarController and add ViewControllers
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects: viewController1, viewController2,
viewController3, viewController4, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
Then, here is MYMainViewController implementaion which is a UINavigationController:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", [self navigationController]); // Logging null
}
My .xib file has a UINavigationController and and there is a view in it. Althought it, when I worked the app, there is blank page and untitled navigation bar. What am I doing wrong?
If I could see the content of my view, I want to navigate between two view controllers by using back button.
Any help or approach would be great for me.
Try to remove navigation controller from xib, so it only have view controller, then initialize navigation controller programatically:
UIViewController *tmpViewController1 = [[[YourViewController alloc] init] initWithNibName:#"YourViewController" bundle:nil];
UINavigationController *viewController1 = [[UINavigationController alloc] initWithRootViewController:tmpViewController1];

Pushing View Controller with Two Nav Controllers

I've got an app where I am pushing a modal view controller. It is working fine, but I am concerned I haven't coded it in the most correct fashion. I have instanstiated two navigation controllers, which seems a bit dodgy to me.
Basically I've created a tab bar controller with 3 tabs, then made one of those tabs / view controllers the root. Later I am (using some home-grown markup on core text) popping a view controller when the user touches a particular word in a paragraph. The pushed view controller has a back button which works fine and the app seems to be OK.
Like I said it all works, but it seems I am coding in circles here. Is this correct?
AppDelegate.h
#import <Foundation/Foundation.h>
#interface AppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate>
{
UIWindow *window;
UITabBarController *tabBarController;
}
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) UITabBarController *tabBarController;
#end
From AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
ViewController2 *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
ViewController3 *viewController3 = [[ViewController3 alloc] initWithNibName:#"ViewController3" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:viewController];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:nav, viewController2, viewController3, nil];
self.tabBarController.delegate = self;
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
ViewController3.h
#import <UIKit/UIKit.h>
#import "JSCoreTextView.h"
#import "PopupViewController.h"
#class JSTwitterCoreTextView;
#interface ReadingViewController : UIViewController <JSCoreTextViewDelegate>
{
JSTwitterCoreTextView *_textView;
UIScrollView *_scrollView;
}
#end
From ViewController3.m
Here I am instantiating another navigation controller. Is this a good idea?
- (void)textView:(JSCoreTextView *)textView linkTapped:(AHMarkedHyperlink *)link
{
PopupViewController *popupVC = [[PopupViewController alloc] initWithNibName:#"PopupViewController" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:popupVC];
[nav setModalPresentationStyle:UIModalPresentationFullScreen];
[nav setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentModalViewController:nav animated:YES];
}
From PopupViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(done:)]];
}
- (void)done:(id)sender
{
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
It appears the answer is "yes". I was under the impression there is a single Navigation Controller for the app, but it's more like one per tab, depending on if there are going to be further pushes from that tab.

Resources