Material Toolbar & Jetpack navigation glitch issues - android

I have some strange "glitch" and refresh issues with my application, using jetpack navigation library (2.3.5), Material Toolbar and view bindings.
The demo scenario is the following: a simple navigation between 3 different fragments.
ENTRY POINT ---> SCREEN C ---> SCREEN D
DISCLAIMER
Sorry for the "pseudo-blur boxes" on the screen, but I can't show the real UI, and if I change the fragment layout for demo purpose, the issue changes. So I need to use the real UI.
First step : ENTRY POINT ---> SCREEN C
The user enter in our app: an empty MaterialToolbar is on screen top, with a standard back icon.
Then the user tap on a button and enter into SCREEN C.
When the SCREEN C is fully rendered, the Material Toolbar is updated with the screen title "SCREEN C", a custom navigation icon and a menu item on the right (the question mark icon).
As you can see in the gif, there are 2 main issues during the navigation:
The screen title "SCREEN C" is initially shown with a very large font and wrong color (the white one). This is the style of the empty MaterialToolbar in the ENTRY POINT fragment.
The back icon is initially the standard one, after a while (when the whole screen is rendered) it is changed with the custom navigationIcon.
Second step: SCREEN C ---> SCREEN D
The user is on "SCREEN C". Then tap on a card and enter into "SCREEN D".
When the SCREEN D is fully rendered, the Material Toolbar is updated with the screen title "SCREEN D", a custom back arrow icon and the menu item on the right will disappear.
As you can see in the gif, there are also some issues:
First, the title "SCREEN D" is shown to the user, with the standard back icon and the menu item on the right
Then, when "SCREEN D" is fully rendered, the back icon is the custom one and the menu item disappears.
The MaterialToolbar, in every fragment, is configured as following:
val navController = NavHostFragment.findNavController(fragment)
val appBarConfiguration = AppBarConfiguration(navController.graph)
setupWithNavController(navController, appBarConfiguration)
This is called in the fragment onViewCreated callback.
Why there is such rendering issue during every navigation step?

When you pass a toolbar to setupWithNavController, it'll automatically set the title as you navigate around the app, using the label value of the navigation destination. It's designed so you have a static toolbar in your activity, with the destination fragments swapped out underneath it, and the toolbar updates to reflect the current fragment.
When you have a separate toolbar in every fragment, you get this glitch where the title updates on the current fragment's toolbar before the navigation to the next fragment happens. The easiest fix here is to just clear the label values on each fragment in the navigation graph, and set them manually on each toolbar (e.g. in the layout XML). I've seen Ian Lake (one of the developers) say that the labels are really intended for that automatic-title-change behaviour, and you shouldn't use them if you have separate toolbars
here we are - in the comments on this question:
How to remove glitch when navigating between Fragments with different toolbars?
Why are you using labels in your navigation graph at all then? Toolbars have APIs to set a static title, which is certainly appropriate if you know that Toolbar is only associated with one fragment.

Related

How to navigate to a non bottom bar screen with jetpack compose?

So i have an app in compose that has startDestination set as a screen with scaffold with bottom nav bar having 3 items and top app bar, i am able to navigate through the 3 bottom navigation tabs. But suppose i want to click on a card in one of the bottom tab screen which should open a details screen without the bottom bar and app bar (Since Navhost is inside the scaffold, bottom and top bars show up on details screen too), what is the right way to do that? Currently i have tried the following ways:-
1. Starting the details screen in a new activity.
2. Using currentDestination route as state to conditionally hide bottom and app bar for details screen route.
Both work but, the problem with first approach is that, it isn't recommended to use multiple activity with jetpack navigation and rather we should stick to a single activity, it also further breaks the navigation if in case i want to move from details to another screen. The problem with second approach is that hiding and showing bottom/top bars create very bad transition between the screens and app doesn't feel smooth.
Hence, i am looking for an appropriate way to handle this as per the guidelines, although i couldn't find any info on this.
Update
I went with showing/hiding the bottom and app bar based on routes, turns out that bad and laggy animation i was facing was because i was running a debug app, with a release app with minifyEnabled true (R8) ,the transitions are very smooth and natural, as i wanted them.
Also it turns out, as per Google's official compose sample app JetSnack , this is the appropriate way of achieving navigation from a bottombar screen to a non-bottombar screen. Thanks to #vitidev for pointing it out in the comments.
You can use a nested Navigation Graph:
one principal graph according to your BottomBar
one nested graph inside each screen you want to go further
https://developer.android.com/jetpack/compose/navigation#nested-nav

Use jetpack navigation to display back arrrow in the action bar

I have a jetpack navigation graph setup with bottom navigation and an action bar. The bottom navigation has 3 tabs. 1 of these tabs has a detailed fragment that I would like to display the back-arrow on in the action bar.
In MainActivity onCreate(), I've added:
supportActionBar?.setDisplayHomeAsUpEnabled(true)
This displays the back button on every tab & fragment.
How can I prevent display of the back button unless the user is navigated to a non-top level fragment? Is there a method that detects when this particular navigation has occured? If so, I presume I can do something like supportActionBar?.setDisplayHomeAsUpEnabled(false)
Additionally, is there a way I can display a custom back arrow on the child pages? The default arrow does not fit the UI.
Happy to provide more detail if needed.
You could use a combination of setupWithNavController(BottomNavigationView,NavController) and setupActionBarWithNavController(AppCompatActivity,NavController,AppBarConfiguration) from NavigationUI. The first will bind the bottom navigation to the navigation controller, the second will set up the support action bar to regard the navigation.
With the AppBarConfiguration.getTopLevelDestinations() you will be able to configure when to display the back arrow. The default is to only regard the root of the navigation graph as a top level destination, but you can also use another builder to define a set of top level destinations.

Strange behavior of a bottom navigation view when is set visible

I try to make an app using one activity multiple fragments pattern. I handle navigation with Navigation architecture component using a bottom navigation view. In one of the fragment I have a Recyclerview which displays a list of custom cards. On item click it navigates to another fragment where I need to hide the bottom navigation view.
The problem appears when I navigate back and set the bottom navigation view visible again. The bar seems to appear in two steps giving the feeling of lag. (first time appears just 60% of the bottom navigation view).
The behavior seems to be related with the status bar. When I change the theme to full screen or I set windowTranslucentStatus=true, everything behaves okay. In addition, first time the nav bar seems to be with exactly 24dp smaller, that is the dimension of status bar.
Have you any idea what can I do?
PS. I'm new on stackoverflow and this is my first question. I'm glad to join this wonderful community.
Delay is one way to go, but I wouldn't suggest that.
I am assuming that the your navigation view is rendered before the entire activity is rendered, which is causing it to be rendered again after the UI is rendered. Why don't you try setting the visibility after the UI is rendered, like here

android - How to implement navigation with bottom app bar

I have a project with the following 4 layouts:
I have actually 1 activity holding a bottom app bar and the NavHostFragment where the fragments get injected. The Main Fragment is the home view. There is a Management and a Setting fragment, both are top-level views like the home view but doesn't depend on each other. These 3 fragments can be switched by clicking an item in the nav drawer. For simplification, I'm trying the new navigation architecture component.
Now I have some design questions:
Should I move the bottom app bar into the fragments, cause they don't depend on each other and the FAB button has another action, otherwise I had to change the onClickListener in the activity when the fragments switch?
1.1 Or should I even show the bottom app bar in the management fragment? Maybe just the top bar with the Up caret.
1.2 Or bottom app bar + top bar and Up caret
1.3 and what about the drawer icon, should I display it in the Mgmt fragment
Should I use a fragment or an activity for the Settings fragment? When I use a fragment, I have to move the bottom app bar into the fragments. Otherwise, the bottom app bar would be visible in the Settings Fragment
The Management Fragment has just a recycler view. Clicking on an item should open a DetailView. Should I use a fragment or an activity here?
I read the doc about the navigation architecture component and there is a section about customizing the destination. Also, ich checked the source code and know that the fragments get replaced.
Further, I checked out some frequently used Apps how they implemented the navigation with a nav drawer and noticed, they all replace their fragments. Why does no one hide/show the fragments, is there a reason not to doing this?
Assume we have a fragment with a listview that holds data collected from a database or another expensive task. So wouldn't it be better to show/ hide these fragments instead of replacing it?
Sorry, it's my first app and I'm really confused about this topic, and it seems there are no official recommendations about it out there not even Material Design guidelines don't really make a reference about it.
How would you do it?
setupWithNavController on a Toolbar (or subclasses like BottomAppBar) only set up the Up icon and the title - they do not hook up menu items added to the Toolbar.
As per the Tie destinations to menu items documentation, you must set up your own listener and call onNavDestinationSelected(). For a BottomAppBar, that would be done by setting a Toolbar.OnMenuItemClickListener:
val navController = Navigation.findNavController(this, R.id.navigation_fragment)
myBottomBar.replaceMenu(R.menu.menu_with_nav_item)
myBottomBar.setupWithNavController(navController)
// Connect MenuItems to the NavController
myBottomBar.setOnMenuItemClickListener { menuItem ->
menuItem.onNavDestinationSelected(navController)
}

Setting Navigation Icon on Android ActionBar

So I'm working on adding ActionBarSherlock and the Navigation Drawer to a project that previously implemented a custom (very poorly written) "action bar". Instead of using fragments and a backstack of activities for navigation, some activities show and hide different layouts. (That is, suppose I am in a list mode and then select a button to go into an edit screen. The app currently hides the list layout and shows another layout.).
So I've added actionbar sherlock and a navigation drawer to all the activities. I want to be able to programmatically switch the navigation icon from the 3 lines to the arrow when certain buttons are pressed.
I can't figure out how to do this though. Any ideas?
Thanks!
The solution to this problem is to use the method:
setDrawerIndicatorEnabled(boolean enable)
inside the ActionBarDrawerToggle class.
After:
drawer.setDrawerListener(toggle);
Use this code:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.select);
It depends how wedded you are to built-in actionbar artifacts. You can always redraw the current actionbar by inflating a layout of your choosing, then calling
getSherlockActivity().getSupportActionBar().setDisplayShowTitleEnabled(false);
getSherlockActivity().getSupportActionBar().setDisplayShowHomeEnabled(false);
getSherlockActivity().getSupportActionBar().setDisplayShowCustomEnabled(true);
// Inflate and do whatever you need to your view...
getSherlockActivity().getSupportActionBar().setCustomView(abView);
getSherlockActivity().getSupportActionBar().show();
When you want to go back to your standard (assuming you're using a DrawerLayout to do your navigation drawer), you can just set make a call to setDisplayShowCustomEnabled(false) (re-enable showHome and showTitle as you please).
As far as I know, customization of the back button can only be done via themes. Besides, swapping the drawer icon for the back icon (within the same Activity) doesn't make sense, since users would still be able to access the navigation drawer by sliding the left most edge to the right. It just wouldn't make sense.
If you absolutely need the back icon, then it would make the most sense to make that screen a new Activity since you would indeed be adding another "level" to the stack, which is what the back icon represents.

Categories

Resources