Bottom tab navigation with Turbo Android

Is there an example of how to use bottom tabs with turbo android? When I use the below code, the tabs don’t really switch, even though the turbo view content changes.

Path configuration:

{
  "patterns": [
    "^\/customers\/history$",
    "^\/customers\/workouts$",
    "^\/customers\/measure$",
    "^\/customers\/profile$"
  ],
  "properties": {
    "context": "default",
    "uri": "turbo://fragment/main_tabs",
    "pull_to_refresh_enabled": true
  }
}

Fragment

TurboNavGraphDestination(uri = "turbo://fragment/main_tabs")
class MainTabs : TurboWebFragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_main_tabs, container, false)
    }

    override fun onStart() {
        super.onStart()
        bottom_nav.setOnNavigationItemSelectedListener { item ->
            when (item.itemId) {
                R.id.action_history -> {
                    replace("history")
                }
                R.id.action_workouts -> {
                    replace("workouts")
                }
                R.id.action_measure -> {
                    replace("measure")
                }
                R.id.action_profile -> {
                    replace("profile")
                }
            }
            true
        }
    }

    fun replace(path: String) {
        navigate(BASE_URL + path, options = TurboVisitOptions(action = TurboVisitAction.REPLACE))
    }
}

Layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include
        layout="@layout/turbo_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/bottom_nav"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/bottom_nav"
        app:layout_constraintBottom_toBottomOf="parent"
        app:labelVisibilityMode="labeled"
        app:menu="@menu/main_tab_items" />
</androidx.constraintlayout.widget.ConstraintLayout>
1 Like

A bit of debugging, and I see it’s recreating the fragment, thus the active tab defaults to first tab. Is there any way to prevent that?

Did you manage to get this working? I’m struggling to find any examples of working tabs with turbo-android

Check out this discussion: Multiple TurboWebView issue and sheet modal problem · Issue #189 · hotwired/turbo-android · GitHub

With the sample code here: Sample code for Multiple TurboWebView issue · shkim/turbo-android@de06c6b · GitHub

All you need to do to get the sample code working is to set both the sessionName and the startLocation to a unique string using the $tag property (in MainSessionNavHostFragment).

2 Likes

This is how Android navigation works. Turbo Android uses Jetpack’s navigation library to manage the backstack and the default behavior is that fragments are to be recreated every time they are removed or replaced.

To handle your case, move your BottomNavigationView to the base activity class and rewrite your replace method as:

fun replace(path: String) {
        delegate.navigate(BASE_URL + path, options = TurboVisitOptions(action = TurboVisitAction.REPLACE))
}

I just tried it and it works!

CC: @gafemoyano

1 Like

Hello, I’m new to Android dev and have loosely followed the guidance in Multiple TurboWebView issue and sheet modal problem · Issue #189 · hotwired/turbo-android · GitHub to get a bottom navigation with tabs working, using the code sample at Sample code for Multiple TurboWebView issue · shkim/turbo-android@de06c6b · GitHub with a ViewFlipper to swap between each TurboSessionNavHostFragment. One thing I noticed is when the app first launches, all the tabs are loading before the user taps them. As in, each tab points to a URL in my rails app that is being hit when the app loads, but I expected only the first tab URL to be called. Any ideas how to have each TurboSessionNavHostFragment loaded more lazily?

I used approach from Optimize the bottom navigation · Issue #12 · blackcandy-org/black_candy_android · GitHub

There is one change required: you need FragmentContainerView in Activity for each of your tab/fragment.