ios tab bar button to modal view - ios

I'm using idev-recipes/RaisedCenterTabBar and I want a modal view called from the center button, not a camera.
Code is here:
https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar
Any ideas on how to get this working?

There is a better approach to follow in order to accomplish that. And much easier.
What I understand by implementing using this methodology: https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar is that strange things are happening when you are trying to hide the tab bar. So the best solution I found for me (the same thing as you do) is here: http://www.lantean.co/display-a-modal-uiviewcontroller-when-a-uitabbaritem-is-pressed/
There is no need to do anything else. Just ignore the view controller that the UITabBarItem is associated with and present your modal view! That's all!

I would create your own subclass of UITabBarController and then add in this method:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item {
}
You will be able to tell what item was selected and then instantiate a modal VC inside there.

Probably you could just use the UITabBarDelegate, with the - (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item method. The method gets sent to the delegate, when somebody presses a button in the tab bar. In there you could check if it was the right button, and then instantiate the modal view controller.

Either with subclassing or by using the delegate, you can simply check if the item selected is your middle button and if it is, have the tab bar select the item that was previously selected and then present your model view controller. Since you'll be doing this within the same RunLoop source that the original selection happened, the tab selection will effectively be undone without ever switching to the middle VC.

According to the code sample provided by you =>
https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar
The central raised tab button is a UIButton, so just set the action of that button like this in BaseViewController.m class
[button addTarget:self action:#selector(showmodalview) forControlEvents:UIControlEventTouchUpInside];
and then in showmodalview method write this code=>
-(void)showmodalview
{
UIViewController *view1=[[UIViewController alloc] init]; // you can use any view controller instance you want ,this is just the example.
[self presentModalViewController:view1 animated:YES];
}

Related

On button pressed go to different view controller

I have this button and I want when clicked to go to a different view controller. How do I do this?
- (void)buttonPressed:(UIButton *)button {
NSLog(#"Button Pressed");
}
NOTE: I am using theos.
If you are using a Storyboard to set up your views, you can ctrl-click and drag from the UIButton to the new view. This will set up a Segue for you which you can customise further.
In main.storyboard go right click the button, select a segue, drag to the view controller you want it to take you to.
You can present a UIViewController programatically in several ways.
Are you working for iOS8? use showViewController:sender: or showDetailViewController:sender: and presentViewController (if you want it modally)
Are you working for iOS7? use pushViewController, but be aware this method is deprecated
If you want to know more about how to use this methods you should read about UIViewController and UINavigationController at the documentation, hera are the methods I named explained in both Objective-C and Swift

Return values to presenting view controller when navigation back button pressed

I'm having trouble piecing this all together. I have a view controller that opens up another (pushes it on to the navigation stack). On that presented view controller, the user enters a value in a text view. When the user pushes the back button in the navigation, I want to be able to pass the value that they entered in the text view back to the presenting controller.
I've looked for a way to use unwind segue with the back button but haven't found anything. When I create my back button (programmatically) I use initWithTitle:style:target:action but I'm not sure how in implementing the action method that I'll be able to access the value set in the presented controller. Might have to use a delegate to link the two, but not sure of the exact integration point for this scenario.
I feel like I'm so close here and a little help would get me there. Thanks!
The two most common models to use for this interaction are for the child view controller to have either a delegate or a completion block. Either would be set in the prepareForSegue method. My personal preference is the completion block method just because it keeps code contained, but ymmv.
There are also multiple models for detecting when your child view controller is dismissed and you need to invoke the delegate and/or completion:
Use a custom back button. Not a fan of this as it can be an issue to create a back button that really looks and acts like the Apple original, especially if supporting iOS 6 and iOS 7.
Hook viewDidDisappear and see if you're still in the navigation controller's viewControllers array. This is better as the back button works right, but it still feels kind of hokey.
Use the UINavigationBarDelegate method navigationBar:shouldPopItem: This is attractive, especially if you have other validation that needs to happen like checking for saved/unsaved values. To implement this you'll have to subclass UINavigationController and forward the method to your child view controller.
EDIT: Details on Option 2:
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if(![self.navigationController.viewControllers containsObject:self])
{
// We're not still in the navigation stack so we must've been
// popped. If we were pushed, viewDidDisappear would be called
// but viewControllers containsObject:self would be true
}
}
EDIT: Clarified Option 3: in your navigation controller subclass
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
UIViewController* top = self.topViewController;
if([top respondsToSelector:#selector(navigationBar:shouldPopItem:)])
return [(id)top navigationBar:navigationBar shouldPopItem:item];
return [super navigationBar:navigationBar shouldPopItem:item];
}
Then you can implement navigationBar:shouldPopItem: in the classes that need the functionality.
the back button does not actually comes up with any event associated with itself so that you can pass the values between the previous and to be Popped ViewController.
You would have to implement Delegate pattern to pass values. In this case as you cant catch when backButton is pressed, you need to use custom leftBarButtonItem or use a image with < in itself.

Regarding the UITabBarController, is there a way to force a view to be fully released when a new tab is selected

I'm creating a tab bar application for the iPhone and I want whatever view is currently active to be fully unloaded/released if a new tab is selected. When any tab is reselected I want it to have to reload everything. The reason I seek this feature is because all views interact with a single database, and can modify the database. When the views are built they are built off the current database, which means that they can be out of date without a forced reload of the view.
To see what I'm referring to load the "Phone" app on your iPhone and you can type in a number on the keypad, switch tabs, switch back to the keypad and the number you typed remains there. Which is a desirable trait for the Phone app, but not so much for what I'm designing.
Is there a way to achieve this? Or, should I use another method to update my views when tabs are switched?
I think Neil Galiaskarov comment that you should not think about releasing the view. His idea to put your current reloading logics in -(void)viewWillAppear is sound:
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppeared:animated];
// Any code you are currently triggering in your init / viewDidLoad
// to reload your database and display the result
}
This is triggered every time you return via the tab-bar and should give you the result you are after. There are few caveats however, depending on what you do next, that might not deliver the required functionality:
The screen will be updated when it is reached by popping the stack (which is probably OK from what you are describing).
If you start to navigate backwards in the stack with the swipe-gesture but abort the navigation the screen will also be updated. (As this triggers viewWillAppear and viewDidAppear).
If the latter is a problem one way to handle it through a BOOL _shouldTriggerReload;:
Wrap the viewWillAppear logic inside an if:
if (_shouldTriggerReload){
_shouldTriggerReload = NO; // Preparing for the next round
// Any code you are currently triggering in your init / viewDidLoad
// to reload your database and display the result
}
Then in your viewDidDisappear:
- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
_shouldTriggerReload = YES;
}
And it will also have to be set inside your viewDidLoad for that first entry:
- (void)viewDidLoad{
_shouldTriggerReload = YES;
}
tabBarController has a viewControllers property.
You modify the viewControllers property to achieve such effect.
What i would do is,
For the view controller(say VC) which you want to reload its view, when user selects that tab.
add UITabBarControllerDelegate delegate to VC. and implement below method.
– tabBarController:shouldSelectViewController:
when the user selects this in bottom tab bar, tabBarController calls this method whether should it show this viewController or not.
Here, change the tabBarController.viewControllers property and return YES.
Lets say your tab bar has only two viewControllers attached to it, and user now selects tab 2 and you have to create new viewController and show it.
So,
UITabBarController *tabBarController;
NSMutableArray *array=[NSMutableArray arrayWithArray:tabBarController.viewControllers];
UIViewController *viewController2; //init your viewController type 2
[array replaceObjectAtIndex:1 withObject:viewController2];
tabBarController.viewControllers =[NSArray arrayWithArray:array];
Use delegate method
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
Add your piece of code which you can trigger each time whenever you select tabBarItem.

Custom TabBarController functionality

I'm attempting to create a custom tab bar controller with the following options:
Feed
Map
New
Camera
Search
The feed, map, camera, and search will each pull up their individual VC's, while new is supposed to be more of a functionality button. When the new tab item is pressed, the map view should be displayed, and the map should begin recording the user's location. I'm trying to use a UITabBarController to manage these views, but I cannot seem to figure out how to implement the functionality that I would like with the "New" tab. It seems as if I would need to implement a separate view controller for the "New" record and stop functionality but that doesn't seem right.
The functionality of record/stop should be similar to snapchat's big red button that takes a picture when you press it.
While I agree with Scott's comment that this is a bad UX, if you technically wanted to do it, you could subclass UITabBarController and in viewDidLoad you could add a UIButton subview to the the tab bar controller's tabBar:
[self.tabBar addSubview:yourCustomButton];
Thus, this button could have it's own action and selector to do whatever you want with.
Take a look at idevrecipes for an example.
I think you have to implement the container view controller yourself. I think you can't do that with UITabBarController.
I was going to dig up the idevrecipes example that shawnwall pointed out, but there's another possibly answer, assuming you want the New button to match the standard UITabBarButton appearance. I agree it may not be the best UI, but it's workable.
For starters, you would create a dummy view controller for the New item. I'm not saying you should duplicate the Maps controller or anything, I'm just saying create an empty view controller and stash to it (or it's location) in a property. Assuming you're creating your tab bar in application:didFinishLaunchingWithOptions:, it'd look something like this.
self.newViewController = [[UIViewController alloc] init];
self.newViewController.title = NSLocalizedString(#"New", nil);
self.newViewController.image = [UIImage imageNamed:"new.png"];
Drop that view controller at the appropriate location in the tab bar controller's viewControllers property.
Save a reference to the Maps controller the same way you saved one for the dummy New controller.
If you haven't already done do, set the delegate of your tabBarController to your app delegate. You may need to declare that your app delegate conforms to UITabBarControllerDelegate.
UITabBarDelegate gives you a few hooks for tracking changes to the tab bar. tabBarController:shouldSelectViewController: looks to be the appropriate place for us to hook in for your desired behavior.
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
if ([viewController isEqual:self.newViewController]) {
self.tabBarController.selectedViewController = self.mapViewController;
// Whatever logic you need to start the recording
return NO;
}
return YES;
}
The look of the user interaction's a little odd - the user tabs the middle item (New), but the item to the left (Map) gets selected. If you want the "tab bar triggers behavior" action, I'd go the idevrecipes route and make the button visually distinct. If you're married to the tab bar item look, though, I believe this is how you'd accomplish it.

Affecting a UINavigationBar's Back Button Method (iOS)

I have a table view that pushes to a detail view controller. From the detail view controller, when I press the 'back' button, I'd like an integer value to change. How do I edit the navigation bar back button's action programatically. The back button is automatically placed in my app because I'm using a table view so I didn't actually create the button, so I don't know how to affect it's method.
To be clear, I still want the back button to go back to the original view, but simultaneously change an integer's value. Thanks!
Thanks PengOne to point me to this direction.
Add the UINavigationBarDelegate in the header file and use this in the .m file:
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item
{
//insert your back button handling logic here
// let the pop happen
return YES;
}
I've figured out an easy fix to this. I simply unchecked 'Shows Navigation Bar' in the Interface Builder for the UINavigationController that the Table View was contained in. Then I used a UINavigationBar to replicate the look (but be able to add and delete buttons as I pleased).
After that I just created IBAction's that I connected to the buttons and could control an integer value from there.
(P.S. The only problem with this is that there is no 'Back' button left pointing arrow shape in the XCode interface builder as many of you know. There are solutions around this that are pretty easily found if you search).
If you're using a UINavigationController, then UINavigationBarDelegate is the delegate class and it implements -navigationBar:shouldPopItem. You can put the action you want to trigger in that method, e.g. incrementing or decrementing a counter.
You could try implementing viewDidDisappear, which should be called as the detail view controller's view goes out of view.

Resources