DEV Community


Posted on

Light up your SwiftUI TabView

In SwiftUI, the TabView APIs and customization is somewhat limited. We can often see tutorials and articles on how to create custom tab view components replicating similar layouts and behaviors. This time I want to show you very simple explorations I did last night with the native TabView component that will add some sparks to your app.

The code is super simple, let's start with a basic TabView layout in SwiftUI within our main view's body.

var body: some View {
  TabView(selection: $selectedTab) {
          .tabItem {
            Image(systemName: "")
            Text("First tab")
          .tabItem {
            Image(systemName: "")
            Text("Second tab")
          .tabItem {
            Image(systemName: "")
            Text("Third tab")
Enter fullscreen mode Exit fullscreen mode

A couple of things here:

  • We are using the initializer of TabView that receives a Binding for the selected value. We will use it later also, but for now, we will declare a @State var in our host view:
@State private var selectedTab: RootTab = .second
Enter fullscreen mode Exit fullscreen mode
  • This is how it looks the RootTab enum, but you can basically use you own typed tabs.
internal enum RootTab: Int {
  case first, second, third

  /// We use this to color the light of each tab when selected.
  var selectionColor: Color {
    switch self {
    case .first, .third:
      return .purple
    case .second:
      return .main

Enter fullscreen mode Exit fullscreen mode

Now, this is the standard look and feel of the TabView, which doesn't bring that much joy :(

The idea is to add a light that focuses on the selected tab, and changes when the user switches to other tabs. For that, let's use an overlay modifier in out TabView like follows:

TabView() {...}
  .overlay(alignment: .bottom) {
        let color = selectedTab.selectionColor
        GeometryReader { geometry in
          let aThird = geometry.size.width / 3
          VStack {
              .background(color.blur(radius: 20))
              .frame(width: aThird, height: 30)
              .shadow(color: color, radius: 40)
                x: CGFloat(selectedTab.rawValue) * aThird,
                y: 30
Enter fullscreen mode Exit fullscreen mode

How does it work?

  1. The overlay adds a Circle shape on top of our TabView.
  2. We style the circle to have a shadow with big blur value that will simulate the light in the selected tab.
  3. The background modifier doesn't really need to be a blurred color but it enhanced the light effect a bit. You can play around and see how it works for you.
  4. We set the width of the Circle to third of the screen's width by using a GeometryReader to get the size of the TabView. The height is up to you but it changes the strength of the shadow so again, play around to get the best results.
  5. Then we use an offset modifier to position the Circle shape, this allow us to position the shape itself below the TabView and letting only the shadow portion visible.
  6. The horizontal offset(x axis), will be updated when the selectedTab changes, so the light moves when the user switches tabs.
  7. Last, but no least, the edgesIgnoringSafeArea allows the overlay to ignore the safe area and go beyond the screen.

Then, we can add a simple Spring animation when the selectedTab value changes to give a better overall experience:
.animation(.spring(), value: selectedTab)

🎉 This is the final result:

Light TabView

It gets better on dark mode:

Dark TabView

One thing to have in mind is that the overlay is on top of our TabView, as the name says, so we have to be careful not to cover our tab items if we add something more than a light.

That is it, simple and effective. I hope you enjoy the simplicity of SwiftUI like I do. 🚀

Top comments (0)