Make TabLayout ViewPager by SwiftUI

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:

  1. TabView
  2. ScrollView
  3. ScrollViewReader
  4. 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:

  1. tagIndex : index id of this tag
  2. dataModel : to provide all the data to design view
  3. currentSelectedIndex : get current selected tab index
  4. action closure : to send callback of tab click
let tagIndex: Intvar dataModel: TabDataModelvar currentSelectedIndex: Intvar 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))

Step 4 : Create TabLayout View

TabLayoutView is the view to draw all tabs on scrollview.

Firstly, added following properties:

  1. dataModel : to provide all the data to design view
  2. action closure : to send callback of tab click
  3. selectedTab : @state property wrapper for selected tab index.
// data model to draw TabLayout Viewvar dataModel: TabDataModel// action on tab selectvar action: (Int) -> Void// variable to store selectTab index@State private var selectedTab: Int = 0

Let’s, draw view.

  1. Add ScrollView horizontally & hide indicator.
  2. Add ScrollViewReader
  3. Add HStack
  4. Start Loop for all tabs to create
  5. Draw SingleTagView for all indexes of the loop process. Also add SingleTagView id to uniquely identified by ScrollViewReader for scrolling programmatically.
  6. 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 TabLayoutViewTabLayoutView(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 TabViewTabView(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! 👍

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store