Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Single Activity with Navigation Component: how to handle different AppBar / Themes

I've been using the new Navigation Component since shortly after it has been announced at Google I/O, and also started to embrace the single-activity as much as possible.

The Single Activity allowed me to share ViewModels between view for an awesome experience and I really don't want to go back to multi-activity if I'm not forced to.

But there's something that gets in the way: AppBar / Themes (status bar) to the single activity concept.

This is part of the design I'm working in:

AppBar design in different sections

As you can see there are different requirments for how the Actionbar / status bar should look.

  1. It's a simple drawer with standard actionbar
  2. Classic detail with image going under the translucent status bar, supposed to use CollapsingToolbarLayout to turn into a standard actionbar when scrolling up
  3. In this case it is non-standard actionbar, I'd call it a "floating toolbar" cause it doesn't expand to the full with of the screen and contains an already expanded SearchView / EditText
  4. Fairly standard AppBar with tabs

List of issues that arise from leaving the single activity:

  • can't share ViewModels between activities
  • complex navigations which re-use parts already defined in another activity navigation graph have to be duplicated / moved into a dedicated activity
  • back navigation "re-construction" doesn't work between activities

Those are issues I want to avoid if possible, but how do you guys manage these kind of situation on a single-activity with navigation component. Any idea?

like image 463
Daniele Segato Avatar asked Aug 21 '18 14:08

Daniele Segato


People also ask

Can we use navigation component for activities?

Note: If your app uses multiple activities, each activity uses a separate navigation graph. To take full advantage of the Navigation component, your app should use multiple fragments in a single activity. However, activities can still benefit from the Navigation component.


2 Answers

I was also thinking the same but never got time to do some experiment. So it's not a solution, it's an experiment, where I want to replace a view with another, here, the toolbar with a toolbar that contains an ImageView.

So I created a new Application using "Basic Activity" template. Then created two destinations within the graph, Home and destination. And lastly, created another layout for Toolbar:

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar 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="?actionBarSize">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@mipmap/ic_launcher_round" />

</androidx.appcompat.widget.Toolbar>

The activity_main.xml has:

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    tools:context=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    ...

And then within Activity, of-course depends on the setup, but let's say that I want to setup an support-actionbar with toolbar:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = findViewById(R.id.toolbar);
    Toolbar toolbar2 = (Toolbar) getLayoutInflater().inflate(R.layout.destination_toolbar, null);

    AppBarLayout appBarLayout = findViewById(R.id.appbar_layout);

    navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph())
            .build();

    navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
        switch (destination.getId()) {
            case R.id.homeFragment:
                appBarLayout.removeAllViews();
                appBarLayout.addView(toolbar);
                setSupportActionBar(toolbar);
                toolbar.setTitle("Home Fragment");
                NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
                break;
            case R.id.destinationFragment:
                appBarLayout.removeAllViews();
                appBarLayout.addView(toolbar2);
                setSupportActionBar(toolbar2);
                toolbar2.setTitle("");
                NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
                break;
        }
    });
}

And thus, this works, making it somewhat ugly as destination grows and new Toolbar/any other view is being added.

P.S. As I told earlier, this is just an experiment, if anyone has a better solution, please do post a new answer.

like image 128
Rajarshi Avatar answered Oct 10 '22 03:10

Rajarshi


As mentioned here, the developer document said

Adding the top app bar to your activity works well when the app bar’s layout is similar for each destination in your app. If, however, your top app bar changes substantially across destinations, then consider removing the top app bar from your activity and defining it in each destination fragment, instead.

like image 37
Dilanka Laksiri Avatar answered Oct 10 '22 04:10

Dilanka Laksiri