Go to file
Manuel Lorenze a32b810b1a update appeared state in IndicatorView when disappear 2023-01-31 18:13:44 -03:00
.github New library version (#106) 2023-01-27 15:10:29 -03:00
.swiftpm/xcode/package.xcworkspace rename project 2021-08-05 18:50:30 -03:00
Example added ability to customize swipe gesture transition animation 2023-01-30 23:21:18 -03:00
PagerTabStripView New library version (#106) 2023-01-27 15:10:29 -03:00
PagerTabStripView.xcodeproj New library version (#106) 2023-01-27 15:10:29 -03:00
PagerTabStripView.xcworkspace refactor 2021-08-05 19:10:27 -03:00
PagerTabStripViewTests New library version (#106) 2023-01-27 15:10:29 -03:00
Sources update appeared state in IndicatorView when disappear 2023-01-31 18:13:44 -03:00
.gitignore first commit 2020-07-17 16:41:19 -03:00
.swiftlint.yml add linter (#66) 2021-12-08 16:10:37 -03:00
CHANGELOG.md update changelog (#108) 2023-01-30 11:07:24 -03:00
Cartfile.private base oss project created with https://github.com/xmartlabs/Swift-Framework-Template 2020-07-17 16:41:52 -03:00
Cartfile.resolved base oss project created with https://github.com/xmartlabs/Swift-Framework-Template 2020-07-17 16:41:52 -03:00
LICENSE base oss project created with https://github.com/xmartlabs/Swift-Framework-Template 2020-07-17 16:41:52 -03:00
Package.swift New library version (#106) 2023-01-27 15:10:29 -03:00
PagerTabStripView.podspec New library version (#106) 2023-01-27 15:10:29 -03:00
README.md New library version (#106) 2023-01-27 15:10:29 -03:00

README.md

PagerTabStripView

build and test Platform iOS Swift 5 compatible Carthage compatible CocoaPods compatible License: MIT

Made with ❤️ by Xmartlabs team. XLPagerTabStrip for SwiftUI!

Introduction

PagerTabStripView is the first pager view built in pure SwiftUI. It provides a component to create interactive pager views which contains child views. It allows the user to switch between your views either by swiping or tapping a tab bar item.

Unlike Apple's TabView it provides:

  1. Flexible way to fully customize pager tab views.
  2. Each pagerTabItem view can be of different type.
  3. Bar that contains pager tab item is placed on top.
  4. Indicator view indicates selected child view.
  5. Ability to update pagerTabItem according to highlighted, selected, normal state.

..and we've planned many more functionalities, we have plans to support each one of the XLPagerTabStrip styles.

Usage

Creating a page view is super straightforward, you just need to place your custom tab views into a PagerTabStripView view and apply the pagerTabItem modifier to each one to specify its navigation bar tab item. The tag parameter is the value to identify the tab item.

import PagerTabStripView

struct MyPagerView: View {

    var body: some View {

        PagerTabStripView() {
            MyFirstView()
                .pagerTabItem(tag: 1) {
                    TitleNavBarItem(title: "Tab 1")
                }
            MySecondView()
                .pagerTabItem(tag: 2) {
                    TitleNavBarItem(title: "Tab 2")
                }
            if User.isLoggedIn {
                MyProfileView()
                    .pagerTabItem(tag: 3) {
                        TitleNavBarItem(title: "Profile")
                    }
            }
        }

    }
}


To specify the initial selected page you can pass the selection init parameter (for it to work properly this value have to be equal to some tag value of the tab items).

struct MyPagerView: View {

    @State var selection = 1

    var body: some View {
        PagerTabStripView(selection: $selection) {
            MyFirstView()
                .pagerTabItem(tag: 1) {
                    TitleNavBarItem(title: "Tab 1")
                }
            ...
            ..
            .
        }
    }
}

As you may've already noticed, everything is SwiftUI code, so you can update the child views according to SwiftUI state objects as shown above with if User.isLoggedIn.

The user can also configure if the swipe action is enable or not (the swipe is based on a drag gesture) and setup what edges have the gesture disabled.

Params:

  • swipeGestureEnabled: swipe is enabled or not (default is true).
  • edgeSwipeGestureDisabled: is an HorizontalContainerEdge (OptionSet) value where the array could have this options: .left, .right, .both or be empty (default is an empty array).

What is the importance to have this parameter? Regarding the next PagerTabStripView example in MyPagerView2: if the pager is in the first page and the user try to swipe to the left, is possible to catch a parent view gesture (where this pager is embebbed) instead of catching the actual pager swipe gesture because it is disabled with the edgeSwipeGestureDisabled paramenter.

struct MyPagerView2: View {

    @State var selection = 1

    var body: some View {
        PagerTabStripView(swipeGestureEnabled: .constant(true),	
			  edgeSwipeGestureDisabled: .constant([.left]),
			  selection: $selection) {
            MyFirstView()
                .pagerTabItem(tag: 1) {
                    TitleNavBarItem(title: "Tab 1")
                }
            ...
            ..
            .
        }
    }
}

Customize pager style

PagerTabStripView provides 5 different ways to show the views. You can select it and customize some aspects of each one using the pagerTabStripViewStyle modifier.

Scrollable style

In this style you can add as many pages as you want. The tabs are placed in a scroll.

The customizable settings are:

  • Placed in toolbar
  • Pager animation when appear
  • Spacing between navigation bar items
  • Navigation bar items height
  • Padding to insets
  • Bar background view
  • Indicator view
  • Indicator view height
struct PagerView: View {

	var body: some View {
		PagerTabStripView(selection: 1) {
			MyView()
				.pagerTabItem(tag: 1) {
					TitleNavBarItem(title: "First big width")
				}
			AnotherView()
				.pagerTabItem(tag: 2) {
					TitleNavBarItem(title: "Short")
				}
            ...
            ..
            .

		}
        .pagerTabStripViewStyle(.scrollableBarButton(tabItemSpacing: 15, 
						     tabItemHeight: 50, 
	    					     indicatorView: {
            						Rectangle().fill(.blue).cornerRadius(5)
            					     }))
	}
}

In this example, we add some settings like the tab bar height, indicator view and tab item spaces. Let's see how it looks!

Button bar style

The customizable settings are:

  • Placed in toolbar
  • Pager animation when appear
  • Spacing between navigation bar items
  • Navigation bar items height
  • Padding to insets
  • Bar background view
  • Indicator view
  • Indicator view height
struct PagerView: View {

	var body: some View {
		PagerTabStripView(selection: 1) {
			MyView()
				.pagerTabItem(tag: 1) {
					TitleNavBarItem(title: "Tab 1")
				}
			AnotherView()
				.pagerTabItem(tag: 2) {
					TitleNavBarItem(title: "Tab 2")
				}
			if User.isLoggedIn {
				ProfileView()
					.pagerTabItem(tag: 3) {
						TitleNavBarItem(title: "Profile")
                    }
			}
		}
        .pagerTabStripViewStyle(.barButton(tabItemSpacing: 15, 
					   tabItemHeight: 50, 
	    			           indicatorView: {
            				   	Rectangle().fill(.gray).cornerRadius(5)
            				   }))
	}
}

In this example, we add some settings like the tab bar height, indicator view and indicator bar height. Let's see how it looks!

Bar style

This style only shows a bar that indicates the current view controller.

The customizable settings are:

  • Placed in toolbar
  • Pager animation when appear
  • Indicator view
  • Indicator view height

Segmented style

This style uses a Segmented Picker to indicate which view is being displayed. You can indicate the selected color, its padding and if you want it to be set in the toolbar.

The customizable settings are:

  • Placed in toolbar
  • Pager animation when appear
  • Background color
  • Padding to insets

Custom style

The styles uses the provided view to indicate and background Views to create the item bar. You can use any and fully customized Views for the indicator and the background view in any way you need.

        .pagerTabStripViewStyle(.barButton(placedInToolbar: false,
                                           pagerAnimation: .interactiveSpring(response: 0.5,
                                                                              dampingFraction: 1.00,
                                                                              blendDuration: 0.25),
                                           tabItemHeight: 48,
                                           barBackgroundView: {
            LinearGradient(
               colors: 🌈,
               startPoint: .topLeading,
               endPoint: .bottomTrailing
           )
           .opacity(0.2)
        }, indicatorView: {
            Text("👍🏻").offset(x: 0, y: -24)
        }))

See how it looks:

Navigation bar

The navigation bar supports custom tab items. You need to specify its appearance creating a struct that implements View protocol.

For simplicity, we are going to implement a nav bar item with only a title. You can find more examples in the example app.

struct TitleNavBarItem: View {
    let title: String

    var body: some View {
        VStack {
            Text(title)
                .foregroundColor(Color.gray)
                .font(.subheadline)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.white)
    }
}

Customize selected and highlighted items

You can define the style of your nav items when they are selected or highlighted by conforming PagerTabViewDelegate protocol in your nav item view.

In the following example we change the text and background color when the tab is highlighted and selected.

private class NavTabViewTheme: ObservableObject {
    @Published var textColor = Color.gray
    @Published var backgroundColor = Color.white
}

struct TitleNavBarItem: View, PagerTabViewDelegate {
    let title: String
    @ObservedObject fileprivate var theme = NavItemTheme()

    var body: some View {
        VStack {
            Text(title)
                .foregroundColor(theme.textColor)
                .font(.subheadline)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(theme.backgroundColor)
    }

    func setState(state: PagerTabViewState) {
        switch state {
        case .selected:
            self.theme.textColor = .blue
            self.theme.backgroundColor = .lightGray
        case .highlighted:
            self.theme.textColor = .pink
        default:
            self.theme.textColor = .gray
            self.theme.backgroundColor = .white
        }
    }
}

Examples

Follow these 3 steps to run Example project

  • Clone PagerTabStripView repo.
  • Open PagerTabStripView workspace.
  • Run the Example project.

Installation

CocoaPods

To install PagerTabStripView using CocoaPods, simply add the following line to your Podfile:

pod 'PagerTabStripView', '~> 4.0'

Carthage

To install PagerTabStripView using Carthage, simply add the following line to your Cartfile:

github "xmartlabs/PagerTabStripView" ~> 4.0

Requirements

  • iOS 16+
  • Xcode 14.2+

Author

Getting involved

  • If you want to contribute please feel free to submit pull requests.
  • If you have a feature request please open an issue.
  • If you found a bug or need help please check older issues and threads on StackOverflow (Tag 'PagerTabStripView') before submitting an issue.

Before contribute check the CONTRIBUTING file for more info.

If you use PagerTabStripView in your app We would love to hear about it! Drop us a line on Twitter.