SWRevealViewController project in iOS - ios

Note: Problem solved.
Here comes the story. I am using RevealViewController in my project. I am also hiding the navigationBars:
[self.navigationController setNavigationBarHidden];
My project can be seen in the picture below and the "menuButton" is implemented in the tabBarViewController.
Since the navigationBar is hidden due to my interface looks, all tabViews (HomeViewController) will not show the menuButton and the navigationBar as supposed to. I am not using panGestureRecognizer to trigger the menu aswell.
This means I have a problem to trigger the menu via a normal button in HomeViewController. The menuButton-event is placed in tabBarViewController.m:
_menuButton.target = self.revealViewController;
_menuButton.action = #selector(revealToggle:);
So I tried to call a method from HomeViewController to fire the button in tabBarViewController like this:
HomeViewController.m
- (IBAction) onMenuClicked: (id)sender{
tabBar = [[tabBarViewController alloc] init];
[tabBar setupMenu]:
}
tabBarViewController.m
-(void) setupMenu{
[_realMenuButton sendActionForControlEvents:UIControlEventTouchUpInside];
[_realMenuButton addTarget:self.revealViewController action:#selector(revealToggle:) UIControlEventTouchUpInside];
}
In this example I tried to make the realMenuButton and normal UIButton. Ive also tried as a UIBarButtonItem just to trigger the #selector(revealToggle:) But nothing happens in the app when I try to trigger the button from HomeViewController.
Not sure how I shall make this work. Any other Ideas or tricks? Please be specific if so! Regards

Yes, it will still work.
SWRevealViewController is just a subclass of a UIViewController, so you can use it at any point in the app:
By calling presentViewController:animated at some point.
By using it in a navigation stack etc.
Note that you can add gestures from SWRevealViewController to its content view controllers, which will alter the behaviour of used in a navigation view controller, but that's to be expected, and you still have full control over its behaviour.
Edit
The UI structure of your app is still not clear to me - it looks like you're trying to call revealToggle on an instance of SWRevealViewController when the VC in view is infact HomeViewController? How would this work, when SWVC is not even in view?
My best guess is that your UI structure should be as follows:
TabBarController --->(root)UINavigationController --->(root)SWRevealViewController.
Then, on your SWRevealViewController, set HomeViewController as the front view controller, and the TableViewController as the right or left view controller.

Do you mean like this?
it is possible. you can set the menu button in your tabBarController.m, like this :
UIBarButtonItem *menu = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:#"menu.png"] style:UIBarButtonItemStylePlain target:revealController action:#selector(revealToggle:)];
self.navigationItem.leftBarButtonItem = menu;
self.delegate = self;
For me, my initial view controller is the login screen (obviously I don't need reveal any VC here...). then when user tap the login button,
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:yourRootVC];
LeftMenuViewController *leftMenuVC = [[LeftMenuViewController alloc]init];
SWRevealViewController *revealController = [[SWRevealViewController alloc]initWithRearViewController:leftMenuVC frontViewController:nav];
revealController.delegate = self;
[self presentViewController:revealController animated:YES completion:nil];

I've tried it and it should work as normal. Even it isn't initial view controller

Related

iOS SWReveal sidebar with links to Detail Segue

My iOS application is based on John-Lluch's SWRevealViewController to get sidebar navigation. I have ran into a navigation problem that I don't know how to solve.
I want one of the menu items to lead to a page that doesn't contain a sidebar but a back button instead. (The other menu items leads to pages where the sidebar can be opened).
To get a back button on a view I need to use a Show Detail Segue, but I also need a navigation controller "somewhere" for the back button to show up. (I don't mean that I need a navigation controller AFTER the segue - I have that already - but I need it somewhere before).
Have someone used SWRevealViewController in this way or know how to achieve this? "Where" should I place a navigation controller?
Thanks!
The only working solution I came up with was to use a Category on UIView, that could do my Detail Segues.
#interface UIViewController (SidebarView)
(void)setupSidebarWithGestureRecognizer:(BOOL)useGestureRecognizer;
(void)openSettingsPage;
(void)openAboutPage;
#end
and the .m-file's code for openAboutPage:
/* This method is called by the sidebar. If the sidebar opens the settings page from itself, the back button
* doesn't know where it should point. This method opens the about menu when the sidebar tells it to, and the back button
* is pointing to the home page. */
- (void)openAboutPage {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *about = [storyboard instantiateViewControllerWithIdentifier:#"About"];
[self.revealViewController rightRevealToggleAnimated:YES];
[self.navigationController pushViewController:about animated:NO];
self.navigationController.navigationItem.title = #"About";
}
and the setupSideBarWithGestureRecognizer... method
- (void)setupSidebarWithGestureRecognizer:(BOOL)useGestureRecognizer {
SWRevealViewController *revealViewController = self.revealViewController;
if (revealViewController) {
UIBarButtonItem *sidebarButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"reveal"] landscapeImagePhone:[UIImage imageNamed:#"reveal"] style:UIBarButtonItemStylePlain target:self.revealViewController action:#selector(rightRevealToggle:)];
self.navigationItem.rightBarButtonItem = sidebarButton;
if(useGestureRecognizer) {
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
}
}
Then for each page I want to show a sidebar, I just call [self setupSidebar:YES]; in the viewWillAppear method of that view controller.

SWRevealViewController insertObject:atIndex object cannot be nil

i'm a new developper with storyboard.i try to make a app with a slide-out menu.
To do this, i use the library : SWRevealViewController and the tutorial : http://www.appcoda.com/ios-programming-sidebar-navigation-menu/ .
i follow the tutorial, but i load the application, i'have this error :
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '*** -[__NSArrayM
insertObject:atIndex:]: object cannot be nil'
my app crash on this line :
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
how can i set self.revealViewController ?
here my storyboard UPDATED:
to understand my app, startviewController is used to download and store data, after downloading, the mainViewcontroller is showed.
i want my slide out menu on my mainviewcontroller, but i cant not do.
here the code i add to my mainviewController viewdidload :
- (void)viewDidLoad
{
[super viewDidLoad];
self.contentView.autoresizesSubviews = YES;
_sharedUser = [User sharedUser];
///slide out menu
// Change button color
//SWRevealViewController *revealViewController = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"RevealViewController"];
_sidebarButton.tintColor = [UIColor redColor];
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
//end slide out
self.contentView.backgroundColor = [UIColor cyanColor];
if (_sharedUser.tokenString) {
}
else{
[self showHomeWithoutLogginView];
}
}
I'm looking at the tutorial you are following. According to your screenshot, there are some stuff missing in your storyboard.
The RevealViewController should be connected with two controllers: a front viewController (for displaying content) and a rear viewController (for showing the navigation menu):
Credits for the image: http://www.appcoda.com/ios-programming-sidebar-navigation-menu/
Those connections (segues) should be marked as "reveal view controller" and each of them have to be named accordingly: "sw_front" and "sw_rear".
Then you have to add the menu items in the navigation menu (rear view controller) and connect each cell to the corresponding viewController, give the segues a name and mark them as a SWRevealViewController class. You may want to connect the front view controller to the viewController you want to be shown first.
I strongly suggest you make the tutorial as it is. I think I used it in the past and it worked pretty well. If you have any doubt about it don't hesitate to ask.
Best of lucks!
SOLVED
thanks to leandro !
here the code who is need in my staviewcontroller who solved my problem:
SWRevealViewController *sideBar = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"SWRevealViewController"];
[self.navigationController pushViewController:sideBar animated:YES];
Are you using the latest version of the SWRevealViewController? The AppCoda tutorial is outdated, and SWReveal has great sample on Git.
Check your segue identifier and class on your storyboard. Have you set sw_front and sw_rear? Also, in the latest version, your segue for setting the Menu / Front View should be: SWRevealViewControllerSegueSetController and not the old SWRevealViewControllerSegue.
EDIT:
Also note that calling [self.revealController panGestureRecognizer]; is enough to enable the gesture; no need for an additional gesture.
EDIT:
Try initializing like this:
MenuViewController *menuVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MenuViewController"];
UINavigationController *frontNavigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"MainNavigationController"];
SWRevealViewController *revealViewController = [[SWRevealViewController alloc] initWithRearViewController:menuVC frontViewController:frontNavigationController];
EDIT:
Can you try adding an action to your Menu Button like this:
[menuButton addTarget:self.revealViewController action:#selector(revealToggle:)
forControlEvents:UIControlEventTouchUpInside];

Is it possible to insert a subview while being on the same tab bar index?

To give some context, I have logic that programmatically decides what view controller to insert into the navigation controller. For example:
If(true){
MyViewController * MyObject = [[MyViewController alloc]init];
myNavigationController = [[UINavigationController alloc]initWithViewController:MyObject];
else {
MyOtherViewController * MyOtherObject = [[MyViewController alloc]init];
myNavigationController = [[UINavigationController alloc]initWithViewController:MyOtherObject];
}
self.tabBarController.viewControllers=[NSArray arrayWithObjects:myNavigationController,nil];
Hopefully that illustrates my point of how I insert views inside of navigation controller. Now onto my problem:
I have an action listener with a button inside of "MyViewController" that essentially replaces the navigation/tab bar index when the user clicks the button. Is it possible to update a navigation/tab bar index with just a button?
MyViewController.m
- (IBAction)MyActionListener:(id)sender {
MyOtherViewController *MyOtherObject = [[MyOtherViewController alloc] initWithNibName:#"MyOtherViewController" bundle:nil];
[self.view insertSubview:MyOtherViewController.view atIndex:2];
}
When I do this, I get a crash EXEC_BAD_ACCESS I'm just wondering if my implementation/approach is wrong. I noticed this question: Update UITabBar Views?
However, doesn't seem to fit the results I am looking for. Hopefully I am clear. Thanks!
Yes it is possible to switch your views on button click with navigation.
You currently in VC1 , you have other two vc VC2 & VC3 and on button click you choose VC2 or VC3 but you did not change the VC1 place.

How to add UIBarButtonItem to NavigationBar while using UIPageViewController

Please forgive me, there are already a ton of questions on how to add a UIBarButtonItem to a NavigationBar programmatically but I just can't seem to get any of the solutions to work in my situation.
Here is the layout of a simple test app I have been working with to learn the UIPageViewController.
I have the page view controller working nicely with three unique viewControllers. I would now like to set unique rightBarButtonItems for each of the view controllers. I can easily set a common barButtonItem in the DetailViewController by simply doing this.
UIBarButtonItem *newButton = [[UIBarButtonItem alloc] initWithTitle:#"Whatever"
style:UIBarButtonItemStylePlain
target:self
action:#selector(doSomething)];
self.navigationItem.rightBarButtonItem = newButton;
Given that I need a unique button for each of the three pages in the pageViewController I am not able to set the button in the detailViewController. I have tried the code above in viewDidAppear of the three controllers but the buttons will not appear. I have also tried creating the button in the same way and then setting it like this with no luck.
DetailViewController *vc = [[DetailViewController alloc] init];
vc.navigationItem.rightBarButtonItem = newButton;
I know I'm close here, I'm just not sure how to specify I need to add a button to the NavigationBar of the NavigationController that is running the detailViewController that my contentViewControllers are embedded in. Any help would be great ESPECIALLY SNIPPETS.
As a side note I have tried a few other methods that have come up problematic.
Setting the button in viewDidLoad rather than viewDidAppear
This will not work because the viewDidLoad method is not called everytime you swipe from one page to the next. The viewDidAppear method is however so I am trying to set the button there. It is possible viewWillAppear is called everytime but I haven't checked.
Setting the button in the UIPageViewController delegate methods
This is problematic if the user flips through the pages to quickly the button will fail to change or fail to appear.
SOLUTION
It turns out I was close… Rather than creating the button in the UIPageViewController methods I simply needed to create a navigationItem property in each of my three view controllers. When the controllers are instantiated in the delegate methods I simply set the navigationItem property equal to that of the detailViewController. That way in my viewDidApper methods I could create the button. Then at viewWillDisappear I set the button to nil. You can also just create the button at viewdidLoad of the DetailViewController and change the text and action in viewDidAppear of the individual viewControllers. Here is a sample.
In the delegate methods
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
I call a helper method based on the index of the viewController. The helper method instantiates the view controllers when it is called. Once instantiated I set some properties including the navigationItem property.
-(FirstController *)controllerAtIndex:(NSUInteger)index
{
FirstController *fvc = [self.storyboard instantiateViewControllerWithIdentifier:#"FirstPageController"];
fvc.imageFile = self.pageImages[index];
fvc.titleText = self.pageTitles[index];
fvc.pageIndex = index;
fvc.navItem = self.navigationItem;
return fvc;
}
Then in the viewDidAppear of the viewController I just do this
-(void)viewDidAppear:(BOOL)animated
{
UIBarButtonItem *newButton = [[UIBarButtonItem alloc]
initWithTitle:#"Whatever" style:UIBarButtonItemStylePlain target:self action:#selector(doSomething)];
navItem.rightBarButtonItem = newButton;
}
If you need the button to change each time you change the page you look at, it must be done in one of the delegate methods that you have tried. I suggest however, that instead of creating a new button and setting it to the navigation item, you simply change the title.
You can create the button in interface builder and link it to a property in your DetailViewController and then call setTitle:forState with UIControlStateNormal on the button every time you go to a new page.
If you need the button to do something different for each page, I would recommend checking the current page in the buttons action method rather than declaring a new one each time.
You can find the correct navigation item to set buttons/titles on by finding the page controller in one of its paged view controllers, then getting its nav item. e.g.
UIViewController *pageController = [[self.navigationController childViewControllers] lastObject];
pageController.navigationItem.title = #"My page's title";
It's really annoying that self.navigationItem doesn't work!
One of my colleagues experienced the same problem with page view controller.
As far as I understand, you wont' be able to add UIBarButtonItem to navigation bar of member view controllers in UIPageViewController. Reason being 'navigationController' is set to nil for UIPageViewController. To confirm, print value of [UIPageViewController navigationController].
However you can do one thing to overcome this issue. Please download example PhotoScroller.
And do following changes in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// kick things off by making the first page
PhotoViewController *pageZero = [PhotoViewController photoViewControllerForPageIndex:0];
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:pageZero];
if (pageZero != nil)
{
// assign the first page to the pageViewController (our rootViewController)
UIPageViewController *pageViewController = (UIPageViewController *)self.window.rootViewController;
pageViewController.dataSource = self;
[pageViewController setViewControllers:#[nav]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
}
return YES;
}
And following changes in the PhotoViewController.m
- (void)loadView
{
.....
.....
self.title =#"Frogs";
UIBarButtonItem *newButton = [[UIBarButtonItem alloc] initWithTitle:#"Something" style:UIBarButtonItemStylePlain target:self action:#selector(doSomething)];
[newButton setTintColor:[UIColor redColor]];
self.navigationItem.rightBarButtonItem = newButton;
}
To avoid crash, you have to handle UIPageViewControllerDataSource delegate methods correctly in AppDelegate.m
Though, I wouldn't advice you to do above as it breaks the whole concept of UIPageViewController.
I hope this would be helpful.

presented ModalView gets displayed within the custom view, from which its called

The above picture shows the schema of my app .. I created a custom view to show the content in UIViewController3 in 1 and 2.
I want to jump directly to VC4 when custom view is touched in VC1 and 2 ..
the custom view was a UIView, the I changed it to UIControl in Interface Builder, to receive touch event ..
I used the following code in custom view class touchevent method
- (IBAction)customViewTouched:(id)sender {
VC4 *nextController = [[VC4 alloc] initWithNibName:#"VC4" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:nextController];
[self presentViewController:navigationController animated:YES completion:nil];
navigationController.navigationBar.tintColor = [UIColor blackColor];
navigationController.navigationBar.topItem.title = #"My Title";
navigationController.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc]
initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:self action:#selector(cancel)];
navigationController.navigationItem.hidesBackButton = FALSE;
// navigationController.navigationBar.backItem.title = #"back";
}
when custom view was touched in VC2(its getting called correctly) - VC4 pops , but only within the custom view..
Also I cant get a back button on the navigation bar. ( as suggested in other stackoverflow answers I also tried setting the custom view's title in ViewDidLoad)
3.I create a dummy UIButton in VC1 of customView's size and place the customView in it .. so that I can handle touch event on VC1 itself .. will this create any performance issues ?
[myCustomViewButton addTarget:self action:#selector(myEventHandler) forControlEvents: UIControlEventTouchUpInside];
when I use the above code, its not throwing any error, but the method myEventHandler never gets called .. in addTarget instead of 'self' when I use 'UIViewController' class name, its throwing an error..
I dont know how to proceed on this .. Any help is appreciated :)
I assume the unmentioned VC3 manages your custom view:
change [self presentVC] to [self.parentVC presentVC]
the VC3 you are presenting VC4 from is embedded as a child in VC1 and VC2

Resources