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:
- 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: 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:
- 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 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.
- 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 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! 👍