Tab bar with multiple tabs using only one view controller - ios

I was not able to find an answer to my problem on SO, please link me if an answer already exists somewhere! My problem seems pretty common- i have a tableview embedded in a nav controller and i want a tab bar with 3 items, where the 3 items change the tableview to populate different data, the first tab representing the default data in the tableview when the view is loaded.
But it seems unnecessary to make two extra UITableViewController classes for the other two tabs, when i can simply just change the data populating the table, with a simple [tableView reloadData]. How do you go about doing this, and also how to implement this in storyboard?

Sounds to me what you really want is a single UITableViewController with a Segmented Control to change the view.Tab Bars are for navigation.
Segmented Control
Use UIControlEventValueChanged to detect the change, load the new data and reload the view.
You didn't indicate what you mean by 'different data'. If you mean something like perform some action which updates data via a CoreData fetch/predicate/sort, etc. then using the Segmented Control is probably the way to go. If your data is dramatically different (different entities, different data management, etc. ) then you should probably go with separate UITableViewControllers as you should not try to over generalize your UITableViewController but rather pair your data to your UITableViewController. After all, that's what it is for.

You can make multiple relationship segue to one controller with ctrl+drag like this.
storyboard> 5 times ctrl+drag to one Navigation Controller
And you should make CustomTabBarController.swift to modify tabs.
Don't forget to change class name of TabBarController that is drawn in storyboard.
class CustomTabBarController: UITabBarController {
let MENUS = ["tab1", "tab2", "tab3", "tab4", "tab5"]
override func viewDidLoad() {
super.viewDidLoad()
let items = tabBar.items!
for (var idx=0; idx<items.count; idx++) {
items[idx].title = MENUS[idx]
items[idx].tag = idx
}
}
...
}
You can use tag or selected index of tabs on the ViewController.swift
let tag = self.tabBarController?.tabBar.selectedItem!.tag
let selectedIndex = self.tabController?.selectedIndex

What you can do is reuse the same Class and have a check in you viewDidLoad method to determine how to populate your tableView, for example:
- (void)viewDidLoad{
//itemType is a property you set
//when instantiating the controller
int index = self.itemType;
switch (index) {
case 0:
[self populateTab1];
break;
case 1:
[self populateTab2];
break;
case 2:
[self populateTab3];
break;
default:
break;
}
}

In storyboard, add UITabbar into your table view controller. Do not use UITabbarViewController which works as a container of view controllers. On the other hand UITabbar is just a control unit.
Set the delegate of the tab bar to your table view controller, and add the following protocol method:
- (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
You can load the correct data in this method. You can get the index of the selected item (button) by
NSUInteger index = [tabBar.items indexOfObject:item];

Related

Swift: The best way to show and hide different views based off of my UISegmentedControl?

I want to show one view when the segmented control highlights the first option. When the user highlights the other option, I want the first view to disappear (or hide) and the other view to become visible. Then, if the user presses the first option again, the second view hides and the first becomes visible.
What is the best way to do this?
I do not want to switch ViewControllers, but simply Views who are both using the same ViewController.
A way to do that would be to give a tag to each view (as in your segment's indices) and call a method when the its value is changed that would hide all view's accept the one with the right tag number.
You could hook the UISegmentedControl from the view controller to the code using an #IBAction and use the following method:
#IBAction func switchView(sender: UISegmentedControl) {
// Change your view controller's view property
// to reference whatever custom views you have.
if(sender.selectedSegmentIndex == 0) {
self.view = viewOne
} else {
self.view = viewTwo
}
}
viewOne and viewTwo being UIViews

Add view behind tableview in UITableViewController

I'm trying to add this custom control below my tableview in a TableViewController:
https://github.com/zogieosagie/RMEIdeasPullToSortControl
In the example the creator gives, the control is implemented using a ViewController and an added tableview, but I want to use it in a TableViewController. I have created and initialized it as shown in the example but I cannot get it to show up behind the table. Any ideas?
Here is a screenshot of the control above my tableview: https://www.dropbox.com/s/ojfpacxelcy9cqm/Photo%20May%2028%2C%208%2057%2035%20PM.png
Here is my code in the viewDidLoad method:
[self.tableView setBackgroundColor:[UIColor clearColor]];
self.rmeideasPullDownControl = [[RMEIdeasPullDownControl alloc] initWithDataSource:self delegate:self clientScrollView:self.tableView];
self.sortTitlesArray = [[NSArray alloc] initWithObjects:#"Listed from A - Z", #"Listed from Z - A", #"Brand value: HIGHEST - LOWEST", #"Brand value: LOWEST - HIGHEST", #"Founded: OLDEST - NEWEST", #"Founded: NEWEST - OLDEST", nil];
CGRect originalFrame = self.rmeideasPullDownControl.frame;
self.rmeideasPullDownControl.frame = CGRectMake(0.0, 45.0, originalFrame.size.width, originalFrame.size.height);
//It is recommended that the control is placed behind the client scrollView. Remember to make its background transparent.
//[self.view insertSubview:self.rmeideasPullDownControl belowSubview:self.tableView];
[self.tableView addSubview:self.rmeideasPullDownControl];
[self.tableView sendSubviewToBack:self.rmeideasPullDownControl];
Table view controllers do not lend themselves to managing anything other than a table view. In a table view controller the content view of the view controller is the table view.
You should not try to add other views as subviews of a table view.
Those 2 things combined mean that you can't do what you are trying to do.
Instead, you should create a regular UIViewController. In your storyboard, add a container view to the view controller's content view. Create a UITableViewController as a separate scene, and then control-drag from the container view onto the table view controller. That will set up an embed segue, so your table view controller becomes a child view of the regular view controller. Now you can do whatever you want to the main view controller's content view, including adding other views behind the table view.
Do you mean that you are using a Table View Controller on the storyboard? Or do you mean that your backing code is a subclass of UITableViewController?
I haven't used this project before but I'm guessing you are using a Table View Controller on the storyboard, in which case there is no backing view for the RMEIdeasPulldownControl to attach to (the top-level view is a UITableViewController). If you look in the example it needs to be attached to a scrollview (like a table view) but it needs to be inserted into a view (like a UIView)
If you meant the second one then I'm not sure, UITableViewControllers are subclassed from UIViewControllers and are really very similar, so I can't imagine any trouble arising from that.
It isn't possible directly, but you can create UIViewControllerClass with relevant storyboard UIViewController
add a MyUIView in hierarchy then UITableView next to MyUIView
attach datasource and delegates for UITableView and use MyUIView as per your requirement.

how do I display different views in a view controller using a tab bar

I have a view controller that has a map view and a second view under the a tab bar. How do I go about updating the second view when I press buttons on the tab bar?
I tried:
LocationNotesViewController lnvc = new LocationNotesViewController();
lnvc.View.Frame = MainPageTabBarView.Frame;
MainPageTabBarView = lnvc.View;
Nothing happens...the view doesn't update.
I want to update the second view with different things when a user clicks on the tabbar...
If you put a UIView underlying whatever data you want displayed in it, you can use the IBAction of the tabBar to programtically cahnge out the contents of the UIView.
Or you could have the IBActions of the tabbar create new UIViews on the fly, containing whatever you want inside.
Code to do this would be like explained here: http://www.programmerscountry.com/creating-uiviewcontrols-programatically/.
Not exactly the same, but you will understand how it works from that answer.
To switch UIViewControllers use this piece of code:
UIViewController *viewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"4"];
[self presentViewController:a animated:YES completion:nil];
I think this is a work around - but I was able to make this happen by doing:
LocationNotesViewController lnvc = new LocationNotesViewController();
lnvc.View.Frame = new RectangleF(MainPageTabBarView.Frame.X, MainPageTabBarView.Frame.Y - MainPageTabBarView.Frame.Y, MainPageTabBarView.Frame.Width, MainPageTabBarView.Frame.Height);
MainPageTabBarView.AddSubview(lnvc.View);

How to Show popupViews

I have UiView,In my Uiview I have one Button And one textField.
When I click the button i need to show the popUp for date values.
when i click the textfield,other popUp with Names.If user select any name from there,that name will show in textfield.If User click on Button,Dates will be arranged by Ascending or Descending order.
Probelm is,My Uiview contain one Main table also.
Now how to differentiate that main table and popUp views.
Thanks.
Create your other popups as separate classes, and add them to your view when needed.
Example:
Create a class called "Names" which inherits from UIView or UIViewController
Create a class called "Dates" which inherits from UIView or UIViewController
To present any of those classes as a popup, you have 2 options:
In case you used UIView, then you can present them with [self addsubview:nview] & [UIView animationwithduration] to make the popup animation.
In case you used UIViewController, just use [self presentViewController:nview].
Each view will have tags, use them.
tableView.tag = 1;
textBoxView.tag = 2;
alertView.tag = 3;
Now that you have the tags you can differentiate the views with respect to the tags.

Incorrect Popover size - when displaying UITableViews under Navigation Controller in Popover

I am writing an iPad app which features UITableViews displayed under a Navigation Controller within a UIPopoverController.
The popover is displayed when I pick a button in the Main View Controller of my app. The popover opens displaying a first TableViewController, which has two rows (UITableViewCells) - "Search" in the first row and "Advanced Settings" in the second row. On initial display, the popover is sized just enough to display the two rows.
I have coded this first TableViewController's didSelectRowAtIndexPath such that when I pick "Search", it pushes a second TableViewController onto the NavigationViewController. This next View Controller allows the user to perform a search, and search results then get populated in its tableview.) This (search results) table view controller is sized long enough to accommodate all the rows returned by the search. The search popover therefore becomes longer when displaying the search tableview controller.
When I cancel the search (or hit the back button in the navigation bar) the popover returns to displaying the first table view controller (the one with just two rows). However this first table view controller now has the longer size. In other words, the popover, instead of resizing itself back to a two row table, remains the size of the second (search results) table view controller (so it now has the two rows "Search" and "Advanced Settings" plus a number of empty rows)
My question is: how can I get each tableview controller in the hierarchy in this implementation (i.e. where table view controllers are displayed in a popover under a navigation controller) to be sized individually and to return to its original size when the user navigates back and forward. There is probably a simple solution to this, but it escapes me! Appreciate if someone can point me to a solution.
As the above solution does not work anymore, here's a more current (Swift) alternative.
You can pass along the popovercontroller to your destinationViewControllers.
Then call preferredContentSizeDidChangeForChildContentContainer in viewWillAppear() and the popover will resize automatically.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if let ppc = popoverController {
ppc.preferredContentSizeDidChangeForChildContentContainer(self)
}
}
If it doesn't work make sure you properly implement the preferredContentSize. For example calculating the size of the your tableViewController with a single section as such:
override var preferredContentSize: CGSize {
get {
let sectionFrame = self.tableView.rectForSection(0)
let titleOnTop = self.navigationController!.navigationBar.frame.height
let height = sectionFrame.height + titleOnTop
return CGSize(width: super.preferredContentSize.width, height: height)
}
set { super.preferredContentSize = newValue }
}
I implemented the answer from the following StackOverflow post by user #krasnyk :
Popover with embedded navigation controller doesn't respect size on back nav
It worked great for me with one change ...
Basically added the same function detailed in the above post with one modification (I hardcoded the size for each VC in my view heirarchy in the PopupController)
I referenced this function to set the correct popover size in the ViewDidLoad and ViewDidAppear functions for each VC in the chain of VCs displayed in my PopoverController.
- (void) correctPopoverContentSize {
//
// removed the following line from the original code in above post as it did not
// work for me
// CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
CGSize currentSetSizeForPopover = CGSizeMake(320.0f, 180.0f);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}

Resources