XUtils

SwiftUIMaterialTabs

Material 3-style tabs and Sticky Headers rolled into one SwiftUI library


MaterialTabItemModifier

The MaterialTabItemModifier view modifier is used to identify and configure tabs for the tab bar. It is conceptually similar to a combination of the tag() and tagitem() view modifiers used with a standard TabView

There are two built-in selector labels: PrimaryTab and SecondaryTab. You don’t typically create these directly, but specify them when applying .materialTabItem() to your tab contents:

Text("First Tab Content")
    .materialTabItem(
        tab: Tab.first,
        label: .primary("First", icon: Image(systemName: "car"))
    )

Both styles are highly customizable through the optional config and deselectedConfig parameters:

Text("Second Tab Content")
    .materialTabItem(
        tab: Tab.first,
        label: .secondary("First", config: customLabelConfig, deselectedConfig: custonDeselectedLabelConfig)
    )

You may also supply your own custom selector label:

Text("Second Tab Content")
    .materialTabItem(
        tab: Tab.first,
        label: { tab, context, tapped in
            Text(tab.description)
                .foregroundColor(tab == context.selectedTab ? .blue : .black)
                .onTapGesture(perform: tapped)
        }
    )

StickyHeaderScroll

StickyHeaderScroll is completely analogous to MaterialTabsScroll.

HeaderStyleModifier

The HeaderStyleModifier view modifier works with the HeaderStyle protocol to implement sticky header scroll effects, such as fade, shrink and parallax. You may apply different headerStyle(context:) to modifiers to different header elements or apply multiple styles to a single element to achieve unique effects.

To have the title fade out as it scrolls off screen:

Text("Header Title")
    .padding()
    .headerStyle(OffsetHeaderStyle(fade: true), context: context)

To have the title shrink and fade out:

Text("Header Title")
    .padding()
    .headerStyle(ShrinkHeaderStyle(), context: context)

To apply parallax to a background image:

Image(.coolBackground)
    .resizable()
    .aspectRatio(contentMode: .fill)
    .headerStyle(ParallaxHeaderStyle(), context: context)

Under the hood, these styles are using parameters provided in the StickyHeaderHeaderContext/MaterialTabsHeaderContext to adjust .scaleEffect(), .offset(), and .opacity(). You may implement your own styles by adopting HeaderStyle or manipulate your header views directly.

MinTitleHeightModifier

The MinTitleHeightModifier view modifier can be used to inform the library what the minimum collapsed height of the title view should be. By default, the title view scrolls entirely out of the safe area. However, if you apply .minTitleHeight(), whatever amount you specify will stick to the top of the safe area.

To make a bottom title element stick at the top:

VStack() {
    Text("Top Title Element").
        .padding()
    Text("Bottom Title Element")
        .padding()
        .minTitleHeight(.content())
}

The use of the .content() option causes the library to measure the height of the receiving view and use that height as the minimum.

The FixedHeaderStyle header style can be used to make a top title element stick:

VStack() {
    Text("Top Title Element").
        .padding()
        .headerStyle(
            ShrinkHeaderStyle(
                fade: false,
                minimumScale: 0.5,
                offsetFactor: 0,
                anchor: .top
            ),
            context: context
        )
        .headerStyle(FixedHeaderStyle(), context: context)
        .minTitleHeight(.content(scale: 0.5))
    Text("Bottom Title Element")
        .padding()
}

In this case, we’ve created a shrinking top title element, reducing the scale to 0.5. This scale factor is also provided to .minTitleHeight() so that it uses the height of the scaled down element.

About SwiftKick Mobile

We build high quality apps for clients! Get in touch if you need help with a project.


Articles

  • coming soon...