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.
Related
I am trying to implement the functionality to open a new wkwebview in my viewcontroller when the user taps a link on a website that is configured to open in a new tab (URLs that have target=_blank). After some testing I've noticed that a new tab opens very inconsistently and the user just stays on the parent webview (new tab opens only 1 in 3 times). I'm using the following Objective-C implementation to achieve this:
RCT_EXPORT_METHOD(wkWebView:(NSURL *)nsurl) {
UIViewController *rootViewController = [[
[ UIApplication sharedApplication] keyWindow] rootViewController];
//WkWebview initialization
WKPreferences *wkPreferences = [[WKPreferences alloc] init];
wkPreferences.javaScriptCanOpenWindowsAutomatically = true;
WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
theConfiguration.preferences = wkPreferences;
dispatch_async(dispatch_get_main_queue(), ^{
self.controller = [[UIViewController alloc] init];
self.webView = [[WKWebView alloc] initWithFrame:rootViewController.view.frame configuration:theConfiguration];
self.webView.navigationDelegate = self;
self.webView.UIDelegate = self;
NSURLRequest *nsrequest=[NSURLRequest requestWithURL:nsurl];
[self.webView loadRequest:nsrequest];
self.controller.view = self.webView;
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.controller];
[self.navigationController setNavigationBarHidden:NO animated:YES];
[rootViewController presentViewController:self.navigationController animated:YES completion: nil];
});
}
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
self.popupWebView = [[WKWebView alloc] initWithFrame:self.webView.frame configuration:configuration];
self.popupWebView.UIDelegate = self;
self.popupWebView.navigationDelegate = self;
[self.webView addSubview:self.popupWebView];
return self.popupWebView;
}
Interface file:
#interface WkWebViewModule : NSObject <RCTBridgeModule, WKUIDelegate, WKNavigationDelegate>
#property (nonatomic) UIViewController *controller;
#property (nonatomic) UINavigationController *navigationController;
#property (nonatomic) WKWebView *webView;
#property (nonatomic) UINavigationItem *navItem;
#property (nonatomic) UINavigationBar *navbar;
#property (nonatomic) WKWebView *popupWebView;
#property (nonatomic) WKPreferences *wkPreferences;
#end
i just created tab bar controller with side menu i got output with black screen but i dont know how to assign two view controllers in app delegate please tell me how to make it work.i need that specific code to make it work.
//AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate,UITabBarControllerDelegate>
{
UINavigationController *navigationController;
}
#property (strong, nonatomic) UIWindow *window;
#property (strong,nonatomic)UITabBarController *tabBarController;
//AppDelegate.m
#interface AppDelegate ()<SWRevealViewControllerDelegate>
#end
#implementation AppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window = window;
self.tabBarController =[[UITabBarController alloc]init];
//Initialize View controller and speciality
UIViewController *viewcontroller1=[[HomeView alloc]init];
UIViewController *viewcontroller2=[[Speciality alloc]init];
UIViewController *viewcontroller3=[[Activity alloc]init];
UIViewController *viewcontroller4 =[[Notification alloc]init];
UIViewController *viewcontroller5 =[[Profile alloc]init];
self.tabBarController.viewControllers=[NSArray arrayWithObjects:viewcontroller1,viewcontroller2,viewcontroller3,viewcontroller4,viewcontroller5, nil];
self.tabBarController.tabBar.barTintColor = [UIColor colorWithRed:0.376 green:0.729 blue:0.318 alpha:1.000];
self.window.backgroundColor = [UIColor whiteColor];
HomeView *frontViewController = [[HomeView alloc] init];
RearViewController *rearViewController = [[RearViewController alloc] init];
UINavigationController *frontNavigationController = [[UINavigationController alloc] initWithRootViewController:frontViewController];
UINavigationController *rearNavigationController = [[UINavigationController alloc] initWithRootViewController:rearViewController];
SWRevealViewController *mainRevealController = [[SWRevealViewController alloc]
initWithRearViewController:rearNavigationController frontViewController:frontNavigationController];
mainRevealController.delegate = self;
self.viewController = mainRevealController;
self.window.backgroundColor= [UIColor whiteColor];
self.window.rootViewController =self.tabBarController;
self.window.rootViewController=self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Arun, I'm going to hook you up big time, if you change your library to JASidpanels, this is going to be easier for you and I already just made the solution. Download JASidePanels, use this library instead, it does the same thing as the one you have, but it's better, download here:
https://github.com/gotosleep/JASidePanels
and if you don't want to worry about doing this yourself, here's the GISTs of the App delegate files:
https://gist.github.com/anonymous/e85536b17296287ec34f
https://gist.github.com/anonymous/93b620135418ddc8f1ed
Start the demo project, and then all you need to do is change the AppDelegate.h and AppDelegate.m files and you have exactly what you want, and more:
Here's the new AppDelegate.m:
#import "JAAppDelegate.h"
#import "JASidePanelController.h"
#import "JACenterViewController.h"
#import "JALeftViewController.h"
#import "JARightViewController.h"
#implementation JAAppDelegate
#synthesize window = _window;
#synthesize viewController = _viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[JASidePanelController alloc] init];
self.viewController.shouldDelegateAutorotateToVisiblePanel = NO;
self.viewController.leftPanel = [[JALeftViewController alloc] init];
UIViewController *viewcontroller1=[[UIViewController alloc]init];
UIViewController *viewcontroller2=[[UIViewController alloc]init];
UIViewController *viewcontroller3=[[UIViewController alloc]init];
UIViewController *viewcontroller4 =[[UIViewController alloc]init];
UIViewController *viewcontroller5 =[[UIViewController alloc]init];
viewcontroller1.view.backgroundColor = [UIColor redColor];
viewcontroller2.view.backgroundColor = [UIColor blueColor];
viewcontroller3.view.backgroundColor = [UIColor yellowColor];
viewcontroller4.view.backgroundColor = [UIColor greenColor];
viewcontroller5.view.backgroundColor = [UIColor purpleColor];
UINavigationController *navcontroller1=[[UINavigationController alloc] initWithRootViewController:viewcontroller1];
UINavigationController *navcontroller2=[[UINavigationController alloc] initWithRootViewController:viewcontroller2];
UINavigationController *navcontroller3=[[UINavigationController alloc] initWithRootViewController:viewcontroller3];
UINavigationController *navcontroller4 =[[UINavigationController alloc] initWithRootViewController:viewcontroller4];
UINavigationController *navcontroller5 =[[UINavigationController alloc] initWithRootViewController:viewcontroller5];
viewcontroller1.title = #"one";
viewcontroller2.title = #"two";
viewcontroller3.title = #"three";
viewcontroller4.title = #"four";
viewcontroller5.title = #"five";
navcontroller1.tabBarItem.image = [UIImage imageNamed:#"cam"];
navcontroller2.tabBarItem.image = [UIImage imageNamed:#"cam"];
navcontroller3.tabBarItem.image = [UIImage imageNamed:#"cam"];
navcontroller4.tabBarItem.image = [UIImage imageNamed:#"cam"];
navcontroller5.tabBarItem.image = [UIImage imageNamed:#"cam"];
self.this = [[UITabBarController alloc] init];
self.this.viewControllers=[NSArray arrayWithObjects:navcontroller1,navcontroller2,navcontroller3,navcontroller4,navcontroller5, nil];
//self.this.tabBar.barTintColor = [UIColor orangeColor];
self.this.tabBar.backgroundColor = [UIColor orangeColor];
self.viewController.centerPanel = _this;
self.viewController.rightPanel = [[JARightViewController alloc] init];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
#end
Here's the new AppDelegate.h:
#import <UIKit/UIKit.h>
#class JASidePanelController;
#interface JAAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) JASidePanelController *viewController;
#property (strong, nonatomic) UITabBarController *this;
#end
This works, here's proof:
this all works, you can customize the sides a very easily, and this doesn't break nearly as much as the other sidepanel controllers. Ask questions if you have them!
ALSO, make sure you add your own custom images to the tabs. This works without a hitch and you will now have yourself a very very robust navigation system that works prostyle. In fact, this JASidePanels is probably one of THE most popular amongst production apps because it doesn't cut corners and doesn't break the guy who made it is a very very good at what he does. Also, this took me about 10 minutes to make and this is just the start, you can do a lot more with this little side panel library than the others. This library literally requires 4 files, that's it, no mess, no fuss, no stupidity.
I don't have privilege to comment on your code.
So I am posting it in your answer.
Why did you set the window's root view controller twice in your code, it will always be one.
Either this,
self.window.rootViewController =self.tabBarController;
Or this,
self.window.rootViewController=self.viewController;
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];
I just added a new UIWebView and it doesn't seem to be showing up. I'm pretty new here, so this could be a very simple error.
I created the view using the storyboard and dragged it into my GuideViewController.h
This is my GuideViewController.h
#import <UIKit/UIKit.h>
#interface GuideViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIWebView *newsWebView;
#end
This is my GuideViewController.m
#import "GuideViewController.h"
#interface GuideViewController ()
#end
#implementation GuideViewController
#synthesize newsWebView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *newsURL = [NSURL URLWithString:#"http://www.yahoo.com"];
NSURLRequest *newsRequest = [NSURLRequest requestWithURL:newsURL];
[newsWebView loadRequest:newsRequest];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is what I'm using to add the view to my app delegate. I already have a sidebar menu added.
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
VidViewController *vidViewController = [[VidViewController alloc] init];
GuideViewController *newsWebView = [[GuideViewController alloc] init];
UINavigationController *navController1 = [[UINavigationController alloc] initWithRootViewController:vidViewController];
[self.window setRootViewController:navController1];
SelectVideo1 *selectVideo1 = [[SelectVideo1 alloc] initWith:#"Test"];
//[self.navController pushViewController:selectVideo1 animated:YES];
SelectVideo1 *selectVideo2 = [[SelectVideo1 alloc] initWith:#"Latest News"];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIStoryboard *tabStoryBoard = [UIStoryboard storyboardWithName:#"TabStoryboard" bundle:nil];
UIStoryboard *navStoryBoard = [UIStoryboard storyboardWithName:#"NavStoryboard" bundle:nil];
UINavigationController *navController = [navStoryBoard instantiateViewControllerWithIdentifier:#"Nav Controller"];
UITabBarController *tabController = [tabStoryBoard instantiateViewControllerWithIdentifier:#"Tab Controller"];
ViewController *redVC, *greenVC;
redVC = [[ViewController alloc] init];
greenVC = [[ViewController alloc] init];
RootController *menuController = [[RootController alloc]
initWithViewControllers:#[navController, selectVideo1, selectVideo2, tabController, newsWebView]
andMenuTitles:#[#"Test", #"Videos", #"Latest News", #"Walkthroughs", #"Official News"]];
self.window.rootViewController = menuController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
#end
The view shows up in the menu bar, but when I click it, nothing happens. I believe the problem lies in my appdelegate and how I call the view?
If you're using a nib file to define your GuideViewController, use
GuideViewController *newsWebView = [[GuideViewController alloc] initWithNibName:#"Insert_Nib_Name_Here" bundle:nil];
If you define your GuideViewController in a storyboard, use
UIStoryboard *navStoryBoard = [UIStoryboard storyboardWithName:#"NavStoryboard" bundle:nil];
GuideViewController *newsWebView = [navStoryBoard instantiateViewControllerWithIdentifier:#"Insert_Guide_Controller_Name_Here"];
If that doesn't work, make sure your IBOutlet UIWebView is connected (control+drag from the UIWebView object in your nib file)
You can also just add the UIWebView programmatically.
In GuideViewController.h, you probably want to conform to the UIWebViewDelegate protocol. Implement the methods to control the UIWebView's functionality
#interface GuideViewController : UIViewController <UIWebViewDelegate>
In GuideViewController.m...
- (GuideViewController*)init
{
self = [super init];
if (self) {
//Adjust the frame accordingly if you don't want it to take up the whole view
self.newsWebView = [[UIWebView alloc] initWithFrame:self.view.frame];
self.newsWebView.delegate = self;
[self.view addSubview:self.newsWebView];
}
return self;
}
I'm trying to set my nib properties programmatically. Specifically, I have a view controller which I initialized with a nib, and now I'm trying to programmatically [mapView setMapType:MKMapTypeHybrid] but it never sets it.
My mapView is an IBOutlet MKMapView, and I dragged a Map View into my nib and conected mapView to Map View.
If I set the Type in the Attributes Inspector of the Map View, it works fine. Is there a way to do this programmatically?
I gave up trying to use nibs months ago (shortly after I started with XCode), but it would be really nice to figure this out.
Thanks
MapTabViewController.h
#import <MapKit/MapKit.h>
#interface MapTabViewController : UIViewController <MKMapViewDelegate>
#property (nonatomic, strong) IBOutlet MKMapView *mapView;
MapTabViewController.m
-(id) initWithTabBarAndNibName: (NSString *) nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = MAPTAB_TITLE;
self.tabBarItem.image = [UIImage imageNamed:MAPTAB_ICON];
self.mapView = [[MKMapView alloc] init];
[self.mapView setMapType:MKMapTypeHybrid];
}
return self;
}
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.dataModel = [[DataModel alloc] init];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
tabBarController = [[UITabBarController alloc] init];
vc_tacTab = [[TacTabViewController alloc] initWithTabBarAndNibName:#"TacTabViewController" bundle: nil];
vc_tacTab.dataModel = self.dataModel;
vc_mapTab = [[MapTabViewController alloc] initWithTabBarAndNibName:#"MapTabViewController" bundle:nil];
vc_mapTab.dataModel = self.dataModel;
NSArray *localControllersArray = [[NSArray alloc] initWithObjects:vc_tacTab, vc_mapTab, nil];
tabBarController.viewControllers = localControllersArray;
[self.window addSubview:tabBarController.view];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
self.mapView = [[MKMapView alloc] init];
Here you are destroying the value in your outlet, and replacing it with a new mapview, which will never be displayed.
When loading from the nib, the outlets will be populated with the objects you have linked them to in the nib. Remove this line and you should be fine.
EDIT - Just realised where this code is being executed. The outlet won't be populated yet - you need to set the property in viewDidLoad, not in the overridden initializer - in fact, all of that code would be better placed in viewDidLoad.