i am trying to set status bar transparent on my content frame inside navigation drawer. I create the app using the template contain on android studio. I need make status bar transparent when navigation drawer is not open so my toolbar back ground is draw behind it.
This one:
This One What I mean
Not this one, because it already transparent:
Not this one
I actually had an issue related to this due to some custom rendering with parallax effects... Anyway, you can just set the status bar background color in onDrawerClosed(View drawerView) and then set it back to transparent when opening the drawer:
public class WindowHelper {
public static void setColoredStatusBar(Activity activity){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(activity.getResources().getColor(R.color.secondary_color));
}
}
public static void setTranslucentStatusBar(Activity activity){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
}
So for you it'd something like:
#Override
public void onDrawerClosed(View drawerView) {
WindowHelper.setColoredStatusBar(activity);
}
Related
I have an app which is based on single activity and multiple fragments and some fragments needs to show into fullscreen when enters fragment and exit from fullscreen when exit. I am currently using flags to show fullscreen in Android Kitkat but its not optimal way i think. I also read ImmersiveMode but it's not working in lower Android version. Currently i am using these methods for fullscreen enter and exit.
//This method not showing transparent status bar also navigation bar and not showing system icons either
public static void setFullscreen(Activity activity) {
if (Build.VERSION.SDK_INT > 10) {
int flags = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN;
boolean isImmersiveAvailable = android.os.Build.VERSION.SDK_INT >= 19;
if (isImmersiveAvailable) {
flags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
} else {
activity.getWindow()
.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
public static void exitFullscreen(Activity activity) {
if (Build.VERSION.SDK_INT > 10) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
} else {
activity.getWindow()
.setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
}
public static void ShowHideFullscreen(boolean isFullscreen,Context cntx){
int newUiOptions = 0;
if (isFullscreen){
// BEGIN_INCLUDE (get_current_ui_flags)
// The UI options currently enabled are represented by a bitfield.
// getSystemUiVisibility() gives us that bitfield.
int uiOptions = ((Activity)cntx).getWindow().getDecorView().getSystemUiVisibility();
newUiOptions = uiOptions;
// END_INCLUDE (get_current_ui_flags)
// BEGIN_INCLUDE (toggle_ui_flags)
boolean isImmersiveModeEnabled =
((uiOptions | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) == uiOptions);
if (isImmersiveModeEnabled) {
Log.d(TAG, "Turning immersive mode mode off. ");
} else {
Log.d(TAG, "Turning immersive mode mode on.");
}
// Navigation bar hiding: Backwards compatible to ICS.
if (Build.VERSION.SDK_INT >= 14) {
newUiOptions ^= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
}
// Status bar hiding: Backwards compatible to Jellybean
if (Build.VERSION.SDK_INT >= 16) {
newUiOptions ^= View.SYSTEM_UI_FLAG_FULLSCREEN;
}
// Immersive mode: Backward compatible to KitKat.
// Note that this flag doesn't do anything by itself, it only augments the behavior
// of HIDE_NAVIGATION and FLAG_FULLSCREEN. For the purposes of this sample
// all three flags are being toggled together.
// Note that there are two immersive mode UI flags, one of which is referred to as "sticky".
// Sticky immersive mode differs in that it makes the navigation and status bars
// semi-transparent, and the UI flag does not get cleared when the user interacts with
// the screen.
if (Build.VERSION.SDK_INT >= 18) {
newUiOptions ^= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
}
((Activity)cntx).getWindow().getDecorView().setSystemUiVisibility(newUiOptions);
}else {
((Activity)cntx).getWindow().clearFlags(newUiOptions);
}
}
These are method we use to enter or exit from fullscreen in fragment with hiding action bar. We use these to entered in fullscreen on onCreate and exit on onPause but sometimes it fails to show desired result.
We need to know what are the optimal way to show fullscreen fragment on lower API too(KITKAT) and also which are the best way to hide toolbar when showing fullscreen because our code ((AppCompatActivity)Objects.requireNonNull(getActivity())).getSupportActionBar().hide();
throws nullpointerexception sometimes.
Our issue:
Show fullscreen fragment with transparent status bar and drawing system icon over fullscreen fragment and transparent navigation bar.
Hiding and showing toolbar with method which safe to call without getting NullpointerExepection
We can target android Kitkat as lowest android version.
Fragment Fullscreen example with system icons and transparent navigation bar.
Update: I set IMMERSIVE mode on my fragment onResume and reset it back at onStop by these method.
private void hideSystemUI() {
// Enables regular immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
View decorView = getActivity().getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show.
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Hide the nav bar and status bar
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN);
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar().hide();
}
// Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars.
private void showSystemUI() {
View decorView = getActivity().getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
((AppCompatActivity) Objects.requireNonNull(getActivity())).getSupportActionBar().show();
}
It shows my fragment in fullscreen with status bar hidden (that's not what i want) and my fragments belong to Navigation Drawer. when i press back button from fullscreen fragment it shows my status bar over toolbar in previous fragment.
I solved this issue by creating a method which clears desired flags at onStop and add flags at onResume
#Override
public void onResume() {
super.onResume();
App_Functions.transparentStatusBar(getActivity(),true,false);
}
#Override
public void onStop() {
super.onStop();
App_Functions.transparentStatusBar(getActivity(),false,false);
}
if i want to show transparent statusbar but navigation bar should be same then i use true in first parameters of method and for clearing that flag just use false. Same way i am using true for complete fullscreen and false for clearing fullscreen flags
public static void transparentStatusBar(Activity activity, boolean isTransparent, boolean fullscreen) {
if (isTransparent){
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
((AppCompatActivity) Objects.requireNonNull(activity)).getSupportActionBar().hide();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
defaultStatusBarColor = activity.getWindow().getStatusBarColor();
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// FOR TRANSPARENT NAVIGATION BAR
//activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
Log.d(TAG,"Setting Color Transparent "+Color.TRANSPARENT+ " Default Color "+defaultStatusBarColor);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Log.d(TAG,"Setting Color Trans "+Color.TRANSPARENT);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
}else {
if (fullscreen){
View decorView = activity.getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}else {
((AppCompatActivity) Objects.requireNonNull(activity)).getSupportActionBar().show();
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
activity.getWindow().setStatusBarColor(defaultStatusBarColor);
}else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
}
}
}
Please feel free to recommend better way to use this method across all platform.
How to handle the toolbar from fragment?
Where to put the toolbar is highly opinionated. But I recommend you to put the toolbar in each fragment xml file rather than keeping one toolbar for the whole application in the Activity xml file. See this sample app by Google, they are also placing the AppbarLayout and toolbar per Fragment rather than keeping it in the activity layout file.
So if you place the toolbar with in the fragment, you can easily hide/show it from the fragment without the fear of getting null pointer exceptions.
So your activity xml file will simply contain the NavHost Fragment only. So the whole screen will be managed by the currently visible Fragment :)
How to get the transparent statusbar for older API levels?
Devices below kitkat would not support transparent statusbar feature. Kitkat supports transluent statusbar, not transparent. So you can use transparent statusbar for API level lollipop or above. If the device version is below lollipop, ignore it as the platform does not support the feature. So rest of my answer assumes you want to achieve transparent status bar when the device version is lollipop or above.
Well then, How to get transparent status-bar for lollipop and above for selected fragments?
We need to create a custom NavHostFragment. This is required because, during fragment transitions, multiple fragment's view hierarchies can be added at the same time. If one consumes window insets, the other might not be laid out properly. To workaround that, we need to make sure we dispatch the insets to all children, regardless of how they are consumed.
class DispatchInsetsNavHostFragment : NavHostFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
view.setOnApplyWindowInsetsListener { v, insets ->
(v as? ViewGroup)?.forEach { child ->
child.dispatchApplyWindowInsets(insets)
}
insets
}
}
}
}
Wrap your nav host fragment with a Framelayout as shown below and put android:fitsSystemWindows="true"
<FrameLayout
android:id="#+id/navHostContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<fragment
android:id="#+id/navHostFragment"
android:name="com.yourdomain.app.DispatchInsetsNavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/main" />
</FrameLayout>
Set the following flags to the navHostContainer which we defined above, from your MainActivity class onCreate method after setContentView.
val navHostContainer: FrameLayout = findViewById(R.id.navHostContainer)
navHostContainer.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Make the content ViewGroup ignore insets so that it does not use the default padding
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
navHostContainer.setOnApplyWindowInsetsListener(NoopWindowInsetsListener)
}
Here is the NoopWindowInsetsListener
object NoopWindowInsetsListener : View.OnApplyWindowInsetsListener {
override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets {
return insets
}
}
Thats all, from now on, your fragments has the complete ownership to the statusbar area. Your views will be drawn behind the transparent status bar. For some fragments, you may not want the statusbar to overlap your content, for those fragments, simply put android:fitsSystemWindows="true" to your root layout in the Fragment xml file.
How to set custom statusbar color for some Fragments?
Use the app:statusBarBackground attribute of CoordinatorLayout with android:fitsSystemWindows="true"
That's all. Happy coding :)
1- in style xml file change AppTheme parent to NoActionBar:
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
2- use this method in your activity for transparent statusBar
private void hideStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
getWindow().setStatusBarColor(ContextCompat.getColor(this, android.R.color.transparent));
}
}
3- match_parent frameLayout tag in your activity_main(xml) for full screen the fragment
I've got a promblem with Android app.
I use this code to hide navigation bar.
public class Initer {
public static void fullScreen(Window window) {
if (Build.VERSION.SDK_INT >= 19) {
View decor = window.getDecorView();
fullScreen(decor);
} else {
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
}
public static void fullScreen(View decor) {
if (Build.VERSION.SDK_INT >= 19) {
decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
View.SYSTEM_UI_FLAG_FULLSCREEN |
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
}
}
But when I show PopupWindow or Dialog up, navigation bar will come up again.
I tried do this
PopupWindow popupWindow =new PopupWindow(getWindow().getContext());
View popupWindowView = LayoutInflater.from(getWindow().getContext()).
inflate(R.layout.dialog_interval_insert, null);
Initer.fullScreen(popupWindowView);
...
popupWindow.showAsDropDown(button_start);
to hide navigation bar when PopupWindow showing up. But it doesn't work. When I call the PopupWindow, the navigation bar will show up then hide again. And when I dismiss() it, navigation bar will be there.
How can I hide navigation bar permanently in Whole application?
you can use this code
public void FullScreen_Activity(Activity activity) {
activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
and change StatusBar Color with
public void setStatusBarColor(Activity activity, int RecColor) {
if (isApi21()) {
Window window = activity.getWindow();
// clear FLAG_TRANSLUCENT_STATUS flag:
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
// finally change the color
window.setStatusBarColor(ContextCompat.getColor(activity, RecColor));
}
}
and how to use FullScreen_Activity method
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getMethod().FullScreen_Activity(this);
setContentView(R.layout.activity_splash);
}
}
I am trying to set Gradient Color to status bar in My android application. For Activity, i placed below code in BaseActivity. It is working fine.
public void setStatusBarColor()
{
try
{
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
Drawable background = this.getResources().getDrawable(R.drawable.gradient);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(this.getResources().getColor(R.color.transparent));
window.setNavigationBarColor(this.getResources().getColor(R.color.transparent));
window.setBackgroundDrawable(background);
}
}
catch (Exception ex)
{
GSLogger.e(ex);
}
}
Now, I would like to apply same gradient color to Fragment. I have a navigation drawer where i have nearly 8 fragments. I would like to apply this gradient color to status bar there. The same above code applied there in BaseFragment. It is not affecting any color. But, when i apply single color code, it is working fine. Here is the below code.
public void setStatusBarColor()
{
try
{
Window window = getActivity().getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(getResources().getColor(R.color.black));
}
}
catch (Exception ex)
{
GSLogger.e(ex);
}
}
What could be the Issue here? I am not able to apply gradient color to Fragment. But the same code is working fine for Activity.
Help would be appreciated.
Your fragment is must be the part of the activity. You can write this code in activity and call it in the fragment.
public void updateStatusBarColor(String color){// Color must be in hexadecimal fromat
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor(color));
} }
Call this method from your fragment
((ActivityName)getActivity()).updateStatusBarColor("#000000")
I've exhausted essentially every post I've found regarding changing the status bar color programmatically, but none of them touch on this specific case.
I have an Activity that contains a ViewPager and a BottomNavigationView. The ViewPager holds three Fragments and the BottomNavigationView moves between them with smoothscroll turned off.
As the first of the three Fragments is a map, I'd like the status bar to be transparent when the first Fragment is shown, but revert back to its opaque color on the other two Fragments.
Here's some code that shows how I'm attempting to set and revert the status bar states.
private class TabSelectedObserver implements Observer<Integer> {
#Override
public void onChanged(#Nullable Integer selectedTab) {
if (selectedTab != null) {
activityMainBinding.mainPager.setCurrentItem(selectedTab, false);
switch (selectedTab) {
case 0:
applyTransparentStatusBarTheme();
break;
default:
applyOpaqueStatusBarTheme();
break;
}
}
}
}
private void applyTransparentStatusBarTheme() {
hideSystemUi();
getWindow().setStatusBarColor(ContextCompat.getColor(this, android.R.color.transparent));
}
private void applyOpaqueStatusBarTheme() {
showSystemUi();
getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.rippallete_700));
}
private void hideSystemUi() {
// Set flags for hiding status bar and navigation bar
mSystemUiVisibility = mSystemUiVisibility
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
getWindow().getDecorView().setSystemUiVisibility(mSystemUiVisibility);
}
private void showSystemUi() {
// Reset flags for hiding status bar and navigation bar
mSystemUiVisibility = mSystemUiVisibility
& ~View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
getWindow().getDecorView().setSystemUiVisibility(mSystemUiVisibility);
}
Here's a gif showing the behavior I end up with
Every thing I tried with fitSystemWindows didn't produce the result I wanted.
If anyone has any suggestions for how you would give each Fragment an individual status bar color, with 1 being transparent, I'd really appreciate it.
So assuming you're setting the status bar colours based on the position of whatever tab you have selected you could do something similar to this:
private void updateStatusBarColour(int tabPosition) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
switch (tabPosition) {
case FIRST_TAB:
case SECOND_TAB:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mRootView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
window.setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryLight));
break;
case THIRD_TAB:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mRootView.setSystemUiVisibility(0);
}
window.setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimary));
break;
case FOURTH_TAB:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mRootView.setSystemUiVisibility(0);
}
window.setStatusBarColor(ContextCompat.getColor(this, R.color.colorDarkTan));
break;
}
}
}
Note that I call setSystemUiVisibility on mRootView, where mRootView is the root parent view containing the ViewPager (or whatever is the root layout of your containing Activity). The call specifically sets the theme of the status bar so that status bar items (like the battery symbol) can be visible on dark or light background depending on what colour you end up setting.
I'm using a YouTubePlayerFragment in my activity, and attempting to overlay the player with an app bar (aka action bar) when the player is in fullscreen. I'm following the guidelines and example in the YouTube Player API "Overlay ActionBar Demo" sample application and YouTubePlayerFragment documentation (more detail below).
All of this worked fine when I was extending from Activity and using the core ActionBar. But when I switch to using AppCompatActivity with the support Toolbar, a few issues arise:
The Toolbar is laid out under the status bar and navigation bar
The player no longer plays when the Toolbar is on top of it
It seems as though the player fullscreen mode used to treat the action bar as part of the system UI (along with the status bar and navigation bar), in terms of positioning and overlay, but no longer does so with the Toolbar.
Any thoughts on why this is happening or how I can use the Toolbar to properly overlay the YouTube player in fullscreen mode? I realize the Toolbar is just another view and I could probably force it to resize and reposition under the status bar, and I could set up a listener for system UI changes and show and hide my Toolbar accordingly, but I'm hoping there's a cleaner fix that I'm missing.
Here's a screenshot:
More detail: I was able to reproduce this behavior in the "Overlay ActionBar Demo" sample app (ActionBarDemoActivity), with the following changes:
Extend AppCompatActivity
Change import from android.app.ActionBar to android.support.v7.app.ActionBar
Add Toolbar to layout
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<view
class="com.examples.youtubeapidemo.ActionBarDemoActivity$ActionBarPaddedFrameLayout"
android:id="#+id/view_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="#color/material_deep_teal_500" />
</FrameLayout>
Change the theme to Theme.AppCompat.Light.NoActionBar and add windowActionBarOverlay
<style name="OverlayActionBarTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowActionBarOverlay">true</item>
<item name="windowActionBarOverlay">true</item>
</style>
Set the Toolbar as the action bar in onCreate()
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Note that the sample app also does the following (I didn't change these):
Implement YouTubePlayer.OnFullscreenListener
Extend the layout and set padding when not in fullscreen so that content displays below Toolbar
#Override
public void onFullscreen(boolean fullscreen) {
viewContainer.setEnablePadding(!fullscreen);
...
}
public static final class ActionBarPaddedFrameLayout extends FrameLayout {
public void setEnablePadding(boolean enable) {
paddingEnabled = enable;
requestLayout();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int topPadding =
paddingEnabled && actionBar != null && actionBar.isShowing() ? actionBar.getHeight() : 0;
setPadding(0, topPadding, 0, 0);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Set YouTube player fullscreen control flag
player.addFullscreenControlFlag(YouTubePlayer.FULLSCREEN_FLAG_CUSTOM_LAYOUT);
Handle config changes
<activity
...
android:configChanges="keyboardHidden|orientation|screenSize"
...
</activity>
I suspect this is a bug. I filed a new bug report for the layout problem, and added a comment to an existing report about the support ActionBar/Toolbar being treated as an illegal overlay.
Toolbar overlay hidden under system UI in YouTube player fullscreen
With AppCompat theme on older devices, ActionBar is detected as an illegal overlay
In the meantime, as a workaround I'm doing the following:
Layout issue
As Troy suggested, I added android:fitsSystemWindows="true" to the Toolbar XML. This fixed the layout in fullscreen, but caused padding to be added to the Toolbar when leaving fullscreen (screenshot). I added logic to the onFullscreen(boolean) method to remove the Toolbar padding (toolbar.setPadding(0, 0, 0, 0)) but this unfortunately still shows white space in place of the padding, which disappears when the layout is next redrawn (e.g., when clicking an item, starting the player, etc). I'm still a little stumped on how to properly set the layout/padding, but the current workaround will do for now.
Illegal overlay issue
Given that showing the Toolbar will pause the YouTube player in fullscreen, I've added logic to only show the Toolbar when the player is already paused. This isn't ideal, as it forces the user to pause the player to see the Toolbar, but it's the best option I can think of.
In onFullscreen(boolean), if we enter fullscreen and the player is playing, the Toolbar is hidden.
public void onFullscreen(boolean isFullscreen) {
mFullscreen = isFullscreen;
if (isFullscreen && youTubePlayer.isPlaying()) {
toolbar.setVisibility(View.GONE);
}
else {
toolbar.setVisibility(View.VISIBLE);
}
}
When setting up the player (in onInitializationSuccess()), I added a listener to show and hide the Toolbar on play and pause:
youTubePlayer.setPlaybackEventListener(new YouTubePlayer.PlaybackEventListener() {
...
#Override
public void onPlaying() {
if (mFullscreen) {
toolbar.setVisibility(View.GONE);
}
}
#Override
public void onPaused() {
if (mFullscreen) {
toolbar.setVisibility(View.VISIBLE);
}
}
});
This code will solved your issue.
To hide navigation bar and toolbar
public void fullScreenCall() {
if(Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { //lower api
View v = getActivity().getWindow().getDecorView();
v.setSystemUiVisibility(View.GONE);
} else if(Build.VERSION.SDK_INT >= 19) {
//for new api versions.
View decorView = getActivity().getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
}
to back normal mode
public void normalScreenCall() {
if(Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
View v = getActivity().getWindow().getDecorView();
v.setSystemUiVisibility(View.VISIBLE);
} else if(Build.VERSION.SDK_INT >= 19) {
//for new api versions.
View decorView = getActivity().getWindow().getDecorView();
decorView.setSystemUiVisibility(0);
}
}
Try adding android:fitsSystemWindows="true" to your toolbar in your XML file.