I'm trying to build a Single Activity App and using a custom SupportActionBar in my Activity. The other Views are all Fragments.
My custom SupportActionBar looks like this:
Now I have the case that I have to display a video in fullscreen mode in a Fragment. Therefore I'm just calling the hide function of the SupportActionBar:
override fun onResume() {
super.onResume()
(activity as MainActivity).supportActionBar!!.hide()}
That works fine, but when I want to display the bar again after the video is finished the bar looks not the same.
In my Fragment I'm calling the show function from SupportActionBar and the initToolbar function of the MainActivity:
override fun onStop() {
super.onStop()
(activity as MainActivity).supportActionBar!!.show()
(activity as MainActivity).initToolbar()
}
And here is the initToolbar method from my Activity:
fun initToolbar() {
setSupportActionBar(toolbar_all_custombar)
supportActionBar!!.setDisplayShowTitleEnabled(false)
supportActionBar!!.setIcon(R.drawable.ic_launcher)
}
The toolbar layout:
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar_all_custombar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:fitsSystemWindows="true"
android:minHeight="?attr/actionBarSize"
app:titleTextAppearance="#style/AppTheme.TitleTextStyle"
app:titleTextColor="#color/textColorPrimary">
<TextView
android:id="#+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/all_toolbar_title"
android:textColor="#android:color/white"
android:textStyle="bold|italic"/>
</android.support.v7.widget.Toolbar>
I don't get it why my bar looks different after showing it again.
What is the cause of this behaviour?
Try it once by putting some paddings or margins (bottom) on the TextView.
Use setSystemUiVisibility
Instead of supportActionBar!!.hide()
hide(): If the window hosting the ActionBar does not have the feature FEATURE_ACTION_BAR_OVERLAY it will resize application content to fit the new space available.
setSystemUiVisibility(): Hiding the ActionBar through this system UI flag allows you to more seamlessly hide it in conjunction with other screen decorations.
After making the SupportActionBar visible again, you could try calling (activity as MainActivity).supportActionBar.invalidate(); to redraw all views within it. This should cause your supportActionBar to be correctly redrawn.
You can set supportToolBar as null when you want to hide it and then restore the previous value when you want to show it.
This is tested and works in my case.
Thank you for your help!
I finally solved it. The problem was that I used some View flags to achieve the fullscreen mode in the respective Fragment. Therefore I removed following function in this Fragment:
private fun hideSystemUiFullScreen() {
exoplayer_videoview_container!!.systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
}
I don't changed my onResume and onStop method. So the issue was only the use of the View flags to get fullscreen mode.
Related
I've a single Activity with a BottomNavigationView inside of it's layout:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_host"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior"
app:menu="#menu/menu_home_bottom_navigation"
/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
My bottom_avigation changes nav_host FragmentContainerView with fragments. All of this fragments have NestedScrollView or RecyclerView and because of app:layout_behavior="#string/hide_bottom_view_on_scroll_behavior", my bottom_navigation automatically hides/shows on scrollDown/scrollUp.
I saw this question: Hide/Show bottomNavigationView on Scroll
. I'm currently using the answer given by Abhishek Singh but the problem is not this.
This is my problem: Imagine FragA and FragB both have RecyclerViews but FragA has less items causing that all items fit to the screen and not scrollable. Now when I switch from FragA to FragB and then scrollDown, bottom_navigation hides with animation and if I press back button I cannot see bottom_navigation anymore and because FragA is not scrollable I cannot make it visible by scrolling.
I've also tried bottom_navigation.visibility = View.Visible in FragA onResume event, but still does not work. I think that it somehow translates bottom_navigation to the bottom and because of that this code does not help.
So how can I fix this issue?
Since there is no part from your code here my solution would be to listen on the back button:
maybe you can check this article it would be helpful
Android: onBackPressed() for Fragments
And there change the visibility for the BottomNavigationView.
I found the answer. instead of changing the visibility property of the bottom_navigation, I wrote two extension functions on BottomNavigationView for hiding/showing it:
private fun BottomNavigationView.showUp() {
animate().setDuration(200L).translationY(0f).withStartAction { visibility = View.VISIBLE }.start()
}
private fun BottomNavigationView.hideDown() {
animate().setDuration(200L).translationY(height.toFloat()).withEndAction { visibility = View.GONE }.start()
}
Now in onResume of FragA I have this:
override onResume() {
super.onResume()
bottom_navigation.showUp()
}
For some reason BottomNavigationView has a visual bug in layout. Does anyone know any way to fix it? The problem resolves after any button is clicked or after I minimize app and restore it.
This is how it is supposed to look:
Everything works when menu is inflated via XML.
<com.google.android.material.bottomnavigation.BottomNavigationView
android:layout_width="match_parent"
android:layout_height="56dp"
...
app:menu="#menu/bottom_navigation_4_game" />
When I added MenuItem programmatically:
navigationView.menu.clear()
navigationView.inflateMenu(R.menu.bottom_navigation4)
We may see in LayoutInspector, that there are actually 5 items, but two of them are overlayed and not seen:
The problem is probably in BottomNavigationMenuView. In LayoutInspector getWidth() returns 0. Invalidating views didn't help.
If you are trying to create dynamic BottomNavigationView with 2 different menu items set,
So instead of dynamically adding the menu item, use 2 different xml layouts (which have define 2 different app:menu property) and based on the conditions switch between them in your code then.
So, XML would look like this:
<BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="#dimen/bottom_bar_height"
app:elevation="8dp"
app:itemIconTint="?attr/nav_item_color_state_red"
app:itemTextColor="?attr/nav_item_color_state_red"
app:labelVisibilityMode="labeled"
app:menu="#menu/bottom_navigation_1" />
<BottomNavigationView
android:id="#+id/bottom_navigation_mini_player"
android:layout_width="match_parent"
android:layout_height="#dimen/bottom_bar_height"
app:elevation="8dp"
app:itemIconTint="?attr/nav_item_color_state_red"
app:itemTextColor="?attr/nav_item_color_state_red"
app:labelVisibilityMode="labeled"
app:menu="#menu/bottom_navigation_2" />
I found a weird code block in the app, that was to blame. Turns out, that TransitionManager didn't end its transitions with ConstraintLayout. This code: updateConstraints {} was called immediately after dynamically changing BottomNavigationView, hence its child views transition was interrupted, I guess.
private fun updateConstraints(f: ConstraintSet.() -> Unit) {
TransitionManager.beginDelayedTransition(root)
val set = ConstraintSet().apply { clone(root) }
set.f()
set.applyTo(root)
}
I am using a toolbar but without an Actionbar or a AppBarLayout. Pressing on the Up (Back) button arrow in the top left corner does not trigger the onSupportNavigateUp method. One Stackoverflow ticket indicates that if you override onOptionsItemSelected, it will not be called. So I removed onOptionsItemSelected. But that didn't help. Here's my code:
setSupportActionBar(toolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
xml layout:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00FFFFFF"/>
In onCreateOptionsMenu I was returning false, which prevents onSupportNavigateUp from being called. I returned false because I needed to hide the overflow menu (3 dots in the upper right corner). Looks like I'll have to find another way of hiding that menu.
I have an app with Single Activity multiple Fragments architecture in my app. The problem is, there is one listing fragment with normal Toolbar, from here user can click and go to Details screen. Now in Details screen, I want the Activity to become Fullscreen with CoordinatorLayout and Collapsing Toolbar with StatusBar area covered in layout as transparent. And when user goes back to Listing screen. The Activity should disable fullscreen and again get the StatusBar color.
The problem here is I am setting the activity as fullscreen using following code:
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
And when the user goes back, I am disabling the Fullscreen by the following code:
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
After disabling the fullscreen, in my previous fragment, I am getting UI bounds clipped off.
Thanks in advance.
Try this in your DetailsActivity -
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// remove title
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
}
I would recommend using
android:theme="#style/AppTheme.NoActionBar"
for your activity.
and in your XML activity build in custom toolbar
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar_top"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="#color/action_bar_bkgnd"
app:theme="#style/ToolBarTheme" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Toolbar Title"
android:layout_gravity="center"
android:id="#+id/toolbar_title" />
</android.support.v7.widget.Toolbar>
and in your activity class
Toolbar toolbarTop = (Toolbar) findViewById(R.id.toolbar_top);
TextView mTitle = (TextView) toolbarTop.findViewById(R.id.toolbar_title);
Now for your fragments, all you have to do is to show or hide this toolbar depends on the fragment you want to the same or another toolbar , And you can do that with OnResume and OnPause of the fragments.
The proposed practise for the new navigation components were presented at I/O with the following template and proposed philosophy:
One Activity for an App
Activity contains Toolbar and Bottom Navigation Bar
A typical app often has a detail view with a CollapsingToolbar in it. How would one build that under that architecture?
Move Toolbar to each Fragment XML?
Implement the collapsing toolbar programmatically?
Move the detail fragment to its own activity (it may use its own deeplink anyway) and 'break' the philosophy?
A typical app often has a detail view with a CollapsingToolbar in it. How would one build that under that architecture?
Great question! I struggled with this for a bit as well and came to the conclusion that there should be one Activity with a NavHostFragment and, ideally, nothing else. This gives you ultimate flexibility to display (or not display) whatever you need for each screen. Importantly, make sure your theme removes the ActionBar:
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
Which leads to your next question...
Move Toolbar to each Fragment XML?
In my opinion, yup! Everything you'd typically use the ActionBar for can be done via a Toolbar. Here's a quick snippet that shows how a Toolbar can be used to do the most important things you've used ActionBar for in the past (up navigation, title, options menu, etc...):
toolbar.apply {
setNavigationOnClickListener { findNavController().navigateUp() }
setTitle(R.string.toolbar_title)
inflateMenu(R.menu.fragment_menu)
setOnMenuItemClickListener(::onMenuItemClick)
}
Implement the collapsing toolbar programmatically?
It depends on what exactly you are trying to do, but most likely, there's no need for that. You can drop an AppBarLayout, CollapsingToolbarLayout, and Toolbar into your layout and use them just like normal. Give your AppBarLayout an ActionBar theme overlay. Here's an example:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.MaterialComponents.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="#+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentScrim="#color/primary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:navigationIcon="#drawable/ic_up_white"/>
...
Move the detail fragment to its own activity (it may use its own deeplink anyway) and 'break' the philosophy?
No need for that with the above, right? It's an approach that's flexible enough to accommodate multiple levels easily in one nav graph and still be able to customize the appearance and behavior of every destination in the graph (including ActionBar-like functionality).
try
appBarLayout = (AppBarLayout) findViewById(R.id.appbar);
if(expandToolbar){
appBarLayout.setExpanded(true,true);
}else{
appBarLayout.setExpanded(false,true);
}
Here is a usufal link
disable expand on CollapsingToolbarLayout for certain fragments
also for other people inteasing of changing some parts of their toolBar
you should write your custom toolbar view in separate XML and try to inflate the custom view in your details Fragment grammatically then hide the unused elements
of the old toolbar if there are any.
setSupportActionBar(toolbar);
View logo = getLayoutInflater().inflate(R.layout.view_logo, null);
toolbar.addView(logo);
and here is how u can hide unwanted Views
for (int i = 0; i < toolbar.getChildCount(); ++i) {
View child = toolbar.getChildAt(i);
// here u can hide all text views for example.
if (child instanceof TextView) {
child.setVisibility(View.GONE );
}
}
this way is a lot better than writing two activities
Let's assume that we have
One Activity for an App
Activity contains Toolbar and Bottom Navigation Bar
All possible appearances for the toolbar that you need for your app should be implemented in that single toolbar and controllable be the currently active fragment.
Not to violate the Dependency inversion principle all Fragments that need a feature from the activity's toolbar must implement an interface. You could use the OnBackStackChangedListener to check for updates of the view
getFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
Fragment visibleFragment = ...
if(visibleFragment instanceof ToolbarControlFragment) {
if(visibleFragment.shouldExpandToolbar()) {
// set AppBarLayout expanded state
}
// ...
}
}
}
);
You maybe remember that principle when a Fragment requires an OptionsMenu.
I would generally recommend having only one Bottom Navigation Bar controlled by an activity and several Toolbars in Fragments. This reduces complexity and makes components of the app more independent.