Is it possible to wrap the rootViewController within another ViewController? - ios

Right now I'm attempting to integrate this library with an existing app. However, the app already has a rootViewController. Is it possible to simply redirect the frontView this library requires to the current rootViewController that the app has? All I need to implement is the ability to swipe between the rearViewController and the frontViewController like in the first example the library gives.

Yes, but then you need to set the SWRevealController as the new rootViewController.
Here's some sample code to illustrate from application: didFinishLaunchingWithOptions: in your app delegate:
MYAppViewController *mainVC = [[MYAppViewController alloc] init];
// Before using SWRevealViewController I had this line:
// self.window.rootViewController = mainVC
// Used for the rear view of the SWRevealViewController
MYMenuViewController *menuVC = [[MYMenuViewController alloc] init];
SWRevealViewController *revealVC = [[SWRevealViewController alloc] initWithRearViewController:menuVC frontViewController:mainVC];
// Now set the SWRevealViewController as the root view controller
self.window.rootViewController = revealVC;

Just make your rootViewController class inherit from SWRevealViewController, then you wont need to wrap anything.
read the Documentation it explains what to do. You don't need to wrap anything.

Related

How to use LGSideMenuController

I want to use LGSideMenuController in my project.
I have a trouble from step :
// Initialization
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController;
My Question : Where to add it? I have added it in viewcontroller.h, is it correct?
and second step is:
- (void)setLeftViewEnabledWithWidth:(CGFloat)width
presentationStyle:(LGSideMenuPresentationStyle)presentationStyle
alwaysVisibleOptions:(LGSideMenuAlwaysVisibleOptions)alwaysVisibleOptions;
- (void)setRightViewEnabledWithWidth:(CGFloat)width
presentationStyle:(LGSideMenuPresentationStyle)presentationStyle
alwaysVisibleOptions:(LGSideMenuAlwaysVisibleOptions)alwaysVisibleOptions;
My Question : I have added it in my viewcontroller.h . Is it correct?
and third step is:
ViewController *viewController = [ViewController new];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
LGSideMenuController *sideMenuController = [[LGSideMenuController alloc] initWithRootViewController:navigationController];
[sideMenuController setLeftViewEnabledWithWidth:250.f
presentationStyle:LGSideMenuPresentationStyleScaleFromBig
alwaysVisibleOptions:0];
TableViewController *leftViewController = [TableViewController new];
[sideMenuController.leftView addSubview:leftViewController.tableView];
My Question - I have added it in my viewcontroller.m, but it shows following alert:
not found method setlef... ; setright... and instancetype ;
Please help me to integrate it in my projects.
Actually the people who have created that third party lib have made this abundantly clear.
Answer to your questions; Nopes, You don't have to add any of the methods to your ViewController.h file or anywhere else. Methods are already there in LGSideMenuController.h. Just import it to the place where you intend to use it.
Assuming that you have downloaded the third party lib and added it to your project, this is what you have to do:
First of all add following line to your ViewController.h or AppDelegate.h file (If you are resetting the root VC programmatically). Write it where you have rest of your import statements (That means the top of the file).
#import "LGSideMenuController.h"
Now you can access, create and modify instances of LGSideMenuController in your ViewController.
Then you have to initialize your Side Menu.
The method for that is:
- (instancetype) initWithRootViewController:(UIViewController *)rootViewController;
You can create this like in your didFinishLaunching method in your AppDelegate.m :
ViewController *viewController = [ViewController new]; //Your root VC
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; //Create a new navigation controller and assign your VC to that navigation controller
LGSideMenuController *sideMenuController = [[LGSideMenuController alloc] initWithRootViewController:navigationController]; //Create instance of your side menu and pass your navigation controller as parameter here.
Now that you have created an instance, it's time to assign it a left view or right view as you prefer. Right now, let's do left view:
[sideMenuController setLeftViewEnabledWithWidth:250.f presentationStyle:LGSideMenuPresentationStyleScaleFromBig
alwaysVisibleOptions:0];
TableViewController *leftViewController = [TableViewController new];
[sideMenuController.leftView addSubview:leftViewController.tableView];
Now just present your sideMenuController, hook the events to right buttons and that's it. If you don't know how to do that either, look up on other Questions on stackoverflow.
However, IDK your requirements but I'd suggest using SWRevealViewController for side menu. It is simple, elegant and really easy to use with plenty of help.

Using didSelectRowAtIndexPath with UISplitViewController and Google Maps

I am using a UITableViewController inside of a UINavigationController for my Master and I'm using a UIViewController implementing the GMSMapViewDelegate inside of a UINavigationController for my detail side to display a google map. Currently the table view and the Google map are displaying in the UISplitViewController fine.
I am a beginner who recently finished reading Programming in Objective C and Big Nerd Ranch's guide for IOS 7. I can't figure out how to use the didSelectRowAtIndexPath method to change the camera position with the map. I know how to change the camera position, I've wrote NSLog calls to test whether my app was responding when tapping a particular row, but I can't figure out how to connect the two controllers. I thought about trying to make the controller holding the mapview a delegate for the UITableView, but I am confused as to how to connect the two. What options do I have to carry something like that out.
This is what my appdelegate file looks like.
...
mapviewController *mvc = [[mapViewController alloc]init];
locationTableController *ltc = [[locationTableController alloc]init];
UISplitViewController *svc = [[UISplitViewController alloc]init];
UINavigationController *sideNav = [[UINavigationController alloc]initWithRootViewController:ltc];
UINavigationController *mapNav = [[UINavigationController alloc]initWithRootViewController:mvc];
svc.delegate = mapNav;
svc.viewControllers = #[sideNav,mapNav];
....
I would keep your locationTableController as delegate and datasource for the table. You can use self.splitViewController to access the splitViewController, your mapNav is then at viewControllers[1] and your mapviewcontroller is rootViewController of mapNav. If you implement a changeCameraPosition method in your mapviewcontroller, you can call this from within didSelectRowAtIndexPath. So in didSelectRowAtIndexPath:
UISplitViewController *svc = self.splitViewController;
UINavigationController *mapNav = svc.viewControllers[1];
mapViewController *mvc = (mapViewController *)mapNav.rootViewController;
[mvc changeCameraPosition];
You may need to import the relevant .h files if not already done. Personally I would add some properties to the splitViewController to speed up accessing the other view controllers.

Login View with SWRevealViewController

Currently, I have a project where I want to integrate a Login View with a SideBarRevealController.
Here is the link with the SideBarRevealController : https://github.com/John-Lluch/SWRevealViewController
I am currently having an issue presenting my login view which is a standard UIViewController.
There are 3 example projects in the link, but I am going to stick with the first one, for IOS. I am having an issue understanding which viewcontroller (SWRevealViewController or my loginview controller) should be the rootviewcontroller?
I figure SWRevealViewController should be the rootviewcontroller but I am not completely sure.
I guess my understanding of how to design the flow of my application with a login view and a mainview is off.....
But if possible, how would I allow a login view to be presented before the SWREVEALVIEWCONTROLLER class, which contains several viewcontrollers?
If there are any questions or concerns please refer to the link and run the example project. I figure this would be an issue for EVERYONE who wants a login view with a sidebar navigator feature.
THANK YOU STACKOVERFLOW!!!
For adding a login screen before the SWRevealViewController you will have to make the changes in the AppDelegate.m file.
LoginView *lv = [[LoginView alloc]init];
SideMenuViewController *smvc = [[SideMenuViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:lv];
UINavigationController *menuVC = [[UINavigationController alloc]initWithRootViewController:smvc];
SWRevealViewController *revealController = [[SWRevealViewController alloc]initWithRearViewController:menuVC frontViewController:nav];
revealController.delegate = self;
self.menu = revealController;
self.window.rootViewController = self.menu;
By this you will get a loginview as your rootview and from there you can navigate to next screen from where you will use sidemenu actions.
I am also using the SWRevealViewController for side menu. I also has the similar requirement, where to show a login screen for existing user and new user registration scree. The way I solved this problem is using multiple storyboard. A very clean and easy solution.
I have a login storyboard and main storyboard file.
In your project setting, disable loading from storyboard, by removing the storyboard key.
Now in your application didFinishLaunchingWithOptions, check if user is already logged in, then load Main storyboard, else load login storyboard.
Now all left is dismissing and showing other story, as when required.
#Hiren
SideMenuViewController *smvc = [[SideMenuViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:lv];
UINavigationController *menuVC = [[UINavigationController alloc]initWithRootViewController:smvc];
SWRevealViewController *revealController = [[SWRevealViewController alloc]initWithRearViewController:menuVC frontViewController:nav];
revealController.delegate = self;
self.menu = revealController;
self.window.rootViewController = self.menu;
so what you are saying is that 1v = whatever the name of your login controller is?
To solve this problem I used following steps.
Create a ViewController in Storyboard with type "SWRevealViewController" and make it as "initial view controller".
First view that is connected to SWRevealViewController with segue "sw_front" do not add toggle button to show drawer. Implement login process on this first view.
After Login the view you want to show side drawer add toggle button.
For logout add following line of code. self.revealViewController().performSegue(withIdentifier: "sw_front", sender: self)
As it is quite hard to explain i have draw a flow how I implemented it.

What is best practice when NOT using storyboards or nibs?

I've heard Facebook and Google do not use UIStoryboards or nibs because they are difficult to merge – they format all their views programmatically. Are there any resources out there that can provide some guidance as to how best to position assets, handle localization, organize files, etc., when creating all your views without nibs?
The first step would be to create an UINavigationController or a UITabBarController within the AppDelegate's didFinishLaunching method, where you should set the rootViewController for the current UIWindow ([window setRootViewController:]).
Then you just have to create your content viewcontrollers and views. Let's say you want to create a menu, then you should create a MneuViewController which inherits from UIViewController and a MenuView which inherits from UIView. Within the MenuView code you create your view components like labels, textfields or whatever you need. In the MenuViewController you create an instance of the MenuView class and call [self setView:] with that object. Finally you have to add the ViewControllers to your rootViewController.
The AppDelegate should look similar to something like this:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
MenuViewController *mvc = [[MenuViewController alloc] init];
UINavigationController *rootViewController = [[UINavigationController alloc] initWithRootViewController: mvc];
[self.window setRootViewController: rootViewController];
[self.window makeKeyAndVisible];
}
Localization has to be done using the macro NSLocalizedString() for which you should find a lot of samples.
Files should be handled using NSFileManager.
For eveything else you should ask more specific questions.

How to use a UISplitViewController as a Modal View Controller?

I am trying to display a UISplitViewController presenting it as a Modal View Controller in my iPad app. I manage to have it display, but for some reason there is a gap to the left of the modal view the size of a Status Bar which is also preserved when the orientation is changed.
Does anybody know why this is happening? Or if this is even possible? Maybe I'm just digging myself a huge hole.
Like for many of you, I needed a 'modal way' to use the UISplitViewController. This seems to be an old issue, but all I found in StackOverflow was at best an explanation why the problem happens when you attempt to do so (like the accepted answer above), or 'hack-arounds'.
However, sometimes it is also not very convenient to change much of your code-base and make a UISplitViewController the initial object just to get it's functionality up and running.
In turns out, there's a way to make everybody happy (including Apple guidelines). The solution that I found best, was to use the UISplitViewController normally, but when needed to be shown/dismissed, use the following approach:
-(void)presentWithMasterViewController: (UIViewController *) thisMasterViewController
andDetailViewController: (UIViewController *) thisDetailViewController
completion:(void(^)(void))completion
{
masterViewController = thisMasterViewController;
detailViewController = thisDetailViewController;
[self setViewControllers:[NSArray arrayWithObjects:masterViewController, detailViewController, nil]];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
self.window.rootViewController = self;
[self.window makeKeyAndVisible];
if(completion)
completion();
}
-(void)dismissViewControllerWithCompletion:(void (^)(void))completion
{
self.window = nil;
masterViewController = nil;
detailViewController = nil;
if(completion)
completion();
}
Where "window", is a property of your UISplitViewController subclass. And the system will take care of the rest!
For convenience/reference, I uploaded this as a UISplitViewController subclass to gitHub:
ModalSplitViewController
--EXAMPLE ON HOW TO USE --
mySplitViewController = [[ModalSplitViewController alloc] init];
mySplitViewController.delegate = self;
[mySplitViewController presentWithMasterViewController:masterViewController andDetailViewController:detailViewController completion:nil];
// when done:
[mySplitViewController dismissViewControllerWithCompletion:nil];
mySplitViewController = nil;
Side-note: I guess most of the confusion originates from the fact that
the UISplitView usage example from Apple documentation uses the window
created in the appDelegate, and for the fact that most people are not
so familiar with the window concept - because we normally don't need
to (they are created once in StoryBoards or boilerplate code).
Additionally, if you are doing state restoration, one should not
forget that programmatically-created UIViewControllers won't
automatically be restored by the system.
The stock UISplitViewController was designed for use as the root view controller only. Presenting one modally goes against the Apple Human Interface Guidelines and has a high probability of getting rejected by the App Review Team. In addition, you may receive the error:
Application tried to present Split View Controllers modally
Technically, this is what I did:
1/ Subclass a UIViewController ie. #interface aVC: UIViewController
2/ In the viewDidLoad, set up a splitViewController, ie. aSplitVC
3/ Then self.view = aSplitVC.view
After all, present aVC as modalViewController
I agree with Evan that this is slightly off-color for Apple, but I was able to complete a working version of this with the following solution:
UISplitViewController *splitVC = [[UISplitViewController alloc] init];
splitVC.delegate = VC2;
splitVC.viewControllers = [NSArray arrayWithObjects:navcon1, navcon2, nil];
UINavigationController *splitNavCon = [[UINavigationController alloc] init];
splitNavCon.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[splitNavCon.view addSubview:splitVC.view];
VC2.splitParentViewController = splitNavCon;
[self presentViewController:splitNavCon animated:YES completion:nil];
This allowed me to have a working back button in the new UISplitViewController that was presented modally on the screen.
You'll notice that I actually pass the VC2 (the delegate of the UISplitViewController) its parent UINavigationController. This was the best way that I found I could dismiss the UISplitViewController from within the VC2:
[splitParentViewController dismissViewControllerAnimated:YES completion:nil];
I believe one can do the other way around: instead of custom controller presenting split controller, one can set up the split controller as the root window controller in storyboard, and on top of its view you can add your custom controller (ie, login screen) and remove it from the screen (removeFromSuperview for example) when it is needed.
That answer is not actually correct, because it not valid any longer since iOS8 and if you need to support even iOS7 you can do that like you put actually modally UIViewController which has a container as SplitView.
let mdSplitView = self.storyboard?.instantiateViewControllerWithIdentifier("myDataSplitView") as! MyData_SplitVC
self.addChildViewController(mdSplitView)
mdSplitView.view.bounds = self.view.bounds
self.view.addSubview(mdSplitView.view)
mdSplitView.didMoveToParentViewController(self)

Resources