Make TabLayout ViewPager by SwiftUI
By: Sanzeev Gautam
Tags: Tabview, Swift, Swiftui, Tablayout, Scrollview

Photo by Maxwell Nelson on Unsplash

TabLayout is the list of horizontal tabs. If you are know little bit about android then assuming that you heared it. Now we will build it in iOS by SwiftUI framework.

Recently Apple launched SwiftUI 2.0. There are lots of updates in this version. So we will use version 2.0 😊

Get Started

Let’s start by developing a demo project which contains scrollable list of tabs with respective pages.

In the below video, you can see that there is list of tabs views e.g. Tab 1, Tab 2 and so on.. with its respective pages. Every tab has own page. Page changed by every tab selection.

In this sample project, we’ll cover some basic knowledge about following key topics:

TabView ScrollView ScrollViewReader Some more view’s modifiers

Let’s jump into the code

Here, I am attaching screenshots of sourcecode for a better view in less space. But don’t worry, below of this post, i’ll add git repository link where you can checkout full source code.

I am dividing this sample project in 5 steps:

Step 1 : Create data model Step 2 : Create Page View Step 3 : Create Single Tab View Step 4 : Create TabLayout View Step 5 : Create Main View to add TabLayout View & Page Views

Step 1 : Create data model

Data Model

Firstly, I created a data model class for TabLayout view which will provide all the required inputs to design view. In the below image, you can see all the properties of data model structure.

Protocol which confirmed by data model struct.

Step 2 : Create Page View

Now, create the Tab Page View for every tab.

Step 3 : Create Single Tab View

Now, create tab view which will be add on scrollview. Creating a separate view.

Firstly, added following properties:

tagIndex : index id of this tag dataModel : to provide all the data to design view currentSelectedIndex : get current selected tab index action closure : to send callback of tab click

let tagIndex: Int var dataModel: TabDataModel var currentSelectedIndex: Int var action: (Int) -> Void

Local variable isThisTagSelected to check state of this tag — selected or unselected

private var isThisTagSelected: Bool { get { return (currentSelectedIndex == tagIndex) } }

Now, create view. Add button with action, label & view modifiers.

Button added with action callback

Button(action: { action(tagIndex) }

Added button label

, label: { Text(dataModel.tabTitles[tagIndex]) .foregroundColor(isThisTagSelected ? dataModel.selectedTabDataModel.textColor : dataModel.unselectedTabDataModel.textColor) .padding() })

Added button’s modifiers

// frame

.frame(minHeight: 10, maxHeight: .infinity) // background color based on selected/unselected state

.background(isThisTagSelected ? dataModel.selectedTabDataModel.backgroundColor : dataModel.unselectedTabDataModel.backgroundColor) // corner radius based on selected/unselected state

.cornerRadius(isThisTagSelected ? dataModel.selectedTabDataModel.cornerRadious : dataModel.unselectedTabDataModel.cornerRadious) // border based on selected/unselected state

.overlay(RoundedRectangle(cornerRadius: ((isThisTagSelected ? dataModel.selectedTabDataModel.cornerRadious : dataModel.unselectedTabDataModel.cornerRadious))).stroke(((isThisTagSelected ? dataModel.selectedTabDataModel.borderColor : dataModel.unselectedTabDataModel.borderColor)), lineWidth: 1))

full code of tab view

Step 4 : Create TabLayout View

TabLayoutView is the view to draw all tabs on scrollview.

Firstly, added following properties:

dataModel : to provide all the data to design view action closure : to send callback of tab click selectedTab : @state property wrapper for selected tab index.

// data model to draw TabLayout View var dataModel: TabDataModel // action on tab select var action: (Int) -> Void // variable to store selectTab index @State private var selectedTab: Int = 0

Let’s, draw view.

Add ScrollView horizontally & hide indicator. Add ScrollViewReader Add HStack Start Loop for all tabs to create Draw SingleTagView for all indexes of the loop process. Also add SingleTagView id to uniquely identified by ScrollViewReader for scrolling programmatically. In the action closure, assign selected tab index to selectedTab property wrapper. And scroll to ScrollView to selected tab position in animation.

Step 5 : Create Main View to add TabLayout View & Page Views

Firstly, create data model object to pass it to the TabLayout View. Now in the VStack, added TabLayoutView with fixed height (40)

// Add TabLayoutView TabLayoutView(dataModel: dataModel, action: { index in print("TabLayoutView tab tapped index: \(index)") self.currentPage = index }) .frame(height: 40)

Now added TabView to add all the PageViews of tabs.

// Add Page Views in TabView TabView(selection: $currentPage) { ForEach(0..<titles.count) { index in PageView(pageIndex: index) } } // Display page dots view .tabViewStyle(PageTabViewStyle(indexDisplayMode: .always)) // animate on scroll .animation(.easeIn)

That's done ✅ 😊

In the code snapshots, you can see that I used some view’s modifiers to make it perfect. You can use it in your own way.

Summary

SwiftUI makes it so light weighted. Hope, you liked it. I just focused on main highlight concept of feature that how can you achieve this. ✍️

Here is link of full source code: https://github.com/sanjeevworkstation/SwiftUITabLayout

Thank You. Happy coding! 👍