Introduction
In this blog, I will explain how to handle multiple view controllers on a single page in Xamarin iOS. If you're interested in learning this, just read the entire post. Since there is no default functionality for showing multiple view controllers in iOS, some of the application designs are complicated too. In such circumstances hiding & showing views in single ViewController is not the smart way. So, we need to separate the views. In this sample, I have created multiple ViewController's to present on a single page. Here, I will show you how to present multiple view controllers in a single page.
iOS output
Prerequisites
- Visual Studio 2019
- XCode 10.0 or above
- Physical device or simulator
- This project is created in Visual Studio 2019 for Mac
Let's start.
Step 1
Create Xamarin iOS Single View Application by navigating to Visual Studio File Menu >> New Project >> In the dialog window >> select left plane App under iOS and center plane select Single View Application and click Next.
Step 2
In the next window, give your application a name, target version & device type (tab or mobile), organize & bundle identifier and click OK.
Step 3
After the project creation, you will get a folder structure like below.
Now, open storyboard in your interface builder using the right click of Main.Storyboard >> in the context menu select Open with >> forwarded by XCode Interface Builder.
Step 4
It's time to design our interface. Default one view controller will be there. We should place Navigation Controller in-front of Initial View Controller. Drag and drop the UICollectionView and View. Here, collection view for creating a tabbed page and view for set another controller view to this view, because there is no default control for the tabbed page and set this collection view height and constraints as per your requirements. Create an outlet for CollectionView and View as collectionView and baseView.
Next, select collection view and open properties plane and set the size is None.
Add First View Controller
Next, drag and drop the new view controller and set the background color as red and add a label view in the center of the page. Create a new ViewController class named as FirstViewController to assign this ViewController.
Add Second View Controller
Similarly, create another view controller and set the background color as yellow and place one label in the center of the page, as well as creating another view controller class named SecondViewController to assign to this View Controller.
fFnally, your storyboard looks like below,
Step 5
Now, add new Collection View Cell for tab design using right-click the solution >> add >> new File >> new dialog window will appear, in the left plane select iOS,>> center plane, select Collection View Cell and give the name as TabCollectionViewCell and then click Add.
Design Collection View Cell
Next, open this Collection View Cell in an Interface builder. Add the following views in the collection view cell.
- Label - Tab title
- View - Active tab indicator
The label is in the center of the cell and view height is 5. Set the perfect constraint for this view. If the constraint is missing, no view will be present in the view controller. Create an outlet for this view to access from the code behind.
There is one problem -- to apply data to view, you couldn't access this outlet's from any other class, so we can create one method to update data for views
- internal void UpdateCell(string title, bool visible)
- {
- titleLabel.Text = title;
- titleLabel.TextColor = UIColor.White;
-
- if (visible)
- indicatorline.Hidden = false;
- else
- indicatorline.Hidden = true;
- }
Step 6
Next moving into the coding part. First, we are going to write a code for the collection view. The view needs CollectionView needs collection view source and delegate class.
In the collection view there is no way to give input directly, so we need to write source class and pass your data to this class. The delegate class is for cell item sizing and handling the item click event. Afterward, apply these two classes to this collection view.
Add Collection View Source Class
First, create a source class named CollectionViewSource and this class should be inherited from UICollectionViewSource and pass the data through the contractor. This page code is given below.
- public class CollectionViewSource : UICollectionViewSource
- {
- private List<string> titles;
- public static int selectedIndex;
-
- public CollectionViewSource(List<string> titles, int Index)
- {
- this.titles = titles;
- selectedIndex = Index;
- }
- public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath)
- {
- var cell = collectionView.DequeueReusableCell("TabCollectionViewCell", indexPath) as TabCollectionViewCell;
-
- if (indexPath.Row == selectedIndex)
- cell.UpdateCell(this.titles[indexPath.Row], true);
- else
- cell.UpdateCell(this.titles[indexPath.Row], false);
-
- return cell;
- }
- public override nint GetItemsCount(UICollectionView collectionView, nint section)
- {
- return titles.Count;
- }
- }
Add the Collection View Delegate Class
Create another delegate class named CollectionViewSourceDelegate and this class should be inherited from UICollectionViewDelegateFlowLayout. In this class, a constructor is passing one ITab interface to the view controller.
- public class CollectionViewSourceDelegate : UICollectionViewDelegateFlowLayout
- {
- int listCount;
- ITab iTab;
- public CollectionViewSourceDelegate(int count, ITab iTab)
- {
- this.listCount = count;
- this.iTab = iTab;
- }
- public override nfloat GetMinimumInteritemSpacingForSection(UICollectionView collectionView, UICollectionViewLayout layout, nint section)
- {
- return 0;
- }
- public override CGSize GetSizeForItem(UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)
- {
- var size = new CGSize();
- size.Width = collectionView.Frame.Width / 2;
- size.Height = collectionView.Frame.Height;
- return size;
- }
- public override void ItemSelected(UICollectionView collectionView, NSIndexPath indexPath)
- {
- iTab.OnTabChange(indexPath.Row);
- CollectionViewSource.selectedIndex = indexPath.Row;
- collectionView.ReloadData();
- }
- }
Create ITab interface
Create a new Interface named ITab.cs by going to Solution Explorer >> Add new file >> select Interface and give the name as ITab and click Add. Add one method OntabChange and one integer parameter value.
- public interface ITab
- {
- void OnTabChange(int indexPath);
- }
Next, open ViewController.cs file. First, we need to setup view controllers and present them into view. Add the FirstViewController and SecondViewController as Child View Controller of this class and set the bounds equal of baseView view. Load the view controller based on Index selection. In the OnTabMethod call the LoadViewMethod and pass the index. create a static string list and pass to collection view source class.
- using Foundation;
- using System;
- using System.Collections.Generic;
- using UIKit;
-
- namespace ManageChildVC
- {
- public partial class ViewController : UIViewController, ITab
- {
- private FirstChildViewController firstController;
- private SecondChildViewController secondController;
-
- public ViewController(IntPtr handle) : base(handle)
- {
- }
-
- public override void ViewDidLoad()
- {
- base.ViewDidLoad();
-
-
- var tabTitles = new List<string>() { "Tab 1 💝", "Tab 2 👨🏻💻" };
-
- SetUpChildViewControllers();
-
- collectionView.RegisterNibForCell(TabCollectionViewCell.Nib, "TabCollectionViewCell");
- collectionView.Source = new CollectionViewSource(tabTitles, 0);
- collectionView.Delegate = new CollectionViewSourceDelegate(tabTitles.Count, this);
- collectionView.ReloadData();
-
- LoadController(0);
- }
-
- private void SetUpChildViewControllers()
- {
- AddViewControllerAsChildViewController(FirstTabViewController());
- AddViewControllerAsChildViewController(SecondTabViewController());
- }
- public UIViewController FirstTabViewController()
- {
- firstController = this.Storyboard.InstantiateViewController("FirstChildViewController") as FirstChildViewController;
- return firstController;
- }
- public UIViewController SecondTabViewController()
- {
- secondController = this.Storyboard.InstantiateViewController("SecondChildViewController") as SecondChildViewController;
- return secondController;
- }
-
- private void AddViewControllerAsChildViewController(UIViewController viewController)
- {
- this.AddChildViewController(viewController);
- View.AddSubview(viewController.View);
- viewController.View.Frame = ViewControllerSpace.Frame;
- viewController.DidMoveToParentViewController(this);
- viewController.View.Hidden = true;
- }
-
- public override void DidReceiveMemoryWarning()
- {
- base.DidReceiveMemoryWarning();
-
- }
-
- public void OnTabChange(int indexPath)
- {
- LoadController(indexPath);
- }
-
- private void LoadController(int indexPath)
- {
- collectionView.ReloadData();
-
- if (indexPath == 0)
- {
- firstController.View.Hidden = false;
- secondController.View.Hidden = true;
- }
- else if (indexPath == 1)
- {
- firstController.View.Hidden = true;
- secondController.View.Hidden = false;
- }
- }
- }
- }
Step 7
Now, run the application, you will get a view like below, select the tabs, based on tab selection the view will change.
The full source code is
here
Conclusion
In this blog, we learned to handle the view controllers in iOS. Thanks for reading, and please share your comments.