Gianluca Veschi
Gianluca Veschi

Reputation: 1608

Implement Compose Bottom Navigation using Fragments

I followed the compose documentation to create a bottom navigation bar by creating such a sealed class

sealed class Screen(val route: String, val label: String, val icon: ImageVector) {
    object ScreenA: Screen("screenA", "ScreenA", Icons.Default.AccountBox)
    object ScreenB: Screen("screenB", "ScreenB", Icons.Default.ThumbUp
}

with something such as the following screen, simply containing a Text item.

@Composable
fun ScreenA() {
    Text(text = "This is ScreenA",
        style = TextStyle(color = Color.Black, fontSize = 36.sp),
        textAlign = TextAlign.Center)
}

and have also implemented the Scaffold, BottomNavigation, and NavHost exactly like in the docs and everything is working just fine.

Let´s say I now want to have one of the screens with a whole bunch of data displayed in a list with all sorts of business logic methods which would need a Fragment, ViewModel, Repository, and so on. What would be the correct approach be? Can I still create the fragments and somehow pass them to the sealed class or should we forget about fragments and make everything composable?

Upvotes: 3

Views: 1823

Answers (1)

Nikola Despotoski
Nikola Despotoski

Reputation: 50538

Since you are following the documentation you need to forget about Fragments. Documentations suggests that view models per screen will be instantiated when the composable function is called/navigated to. The viewmodel will live while the composeable is not disposed. This is also motivated by single activity approach.

@Inject  lateinit var factory : ViewModelProvider.Factory


@Composable
fun Profile(profileViewModel = viewModel(factory),
    userId: String,
    navigateToFriendProfile: (friendUserId: String) -> Unit) {
  
}

This can be seen in compose samples here.


If you want to mix both, you can omit using navigation-compose, and roll with navigation component and use Fragment and only use composable for fragment UI.

@AndroidEntryPoint
class ProfileFragment: BaseFragment() {

    private val profileViewModel by viewModels<ProfileViewModel>(viewModelFactory)
    private val profileFragmentArgs by navArg<ProfileFragmentArgs>()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return ComposeView(requireContext()).apply {
            setContent {
               Profile(profileViewModel = profileViewModel, id = profileFragmentArgs.id, navigateToFriendProfile = { findNavController().navigate(...)  })  
            }
        }
    }

Upvotes: 2

Related Questions