I'm porting a codebase from native Holo (Theme.Holo
etc) to the appcompat-v7
(Theme.AppCompat
and so on). The last section contains the tl;dr if you don't want to read the details.
The issue
Everything's working but I had issues replicating one behaviour that was quite easy to have using the old ActionBar. I have a video player, and in landscape I want it to behave like YouTube: hide (animating) the player controls, app bar and status bar. On user interaction, the UI controls should leave this "lights out" mode and go back to the normal state. A timer would then go back to lights out mode if the user doesn't touch the screen for X seconds. The same code that worked with the ActionBar doesn't do the trick with a Toolbar
.
So, what I am using is:
- An opaque Status Bar
setSystemUiVisibility()
using one of these combos:- default:
View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- lights out:
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- default:
minSdkVersion
is 16- to show and hide the ActionBar I simply called
show()
andhide()
on it - to implement the same behaviour on the app bar I subclassed
Toolbar
and added ashow()
and ahide()
method that do the same (first simply usingsetVisibility()
, and then using animations -- getting the same results)
The LAYOUT_STABLE
made so that the appbar would end up behind the status bar, of course (as it implies a fitSystemWindows
. Since the appbar is a normal View in the view hierarchy and is not in the decor like the ActionBar was, it is affected by that flag. This was what I was seeing on screen:
Not immediately clear what the toolbar bounds are, as the app bar is dark on dark, but you can see the title is cut and "misaligned". This is because the toolbar was correctly sized but behind the status bar. My main problem was at that point that there is no public API to get the status bar height, rectangle or anything else to shift my app bar vertically to show below the status bar.
Testing was performed mostly on a N5 on LPX13D (latest Lollipop public build at the time of writing), but the same could be seen happening on Android 4.4.
The hacky solution
That said, after quite some time and some failed attempts at making it work in a not-too-hacky way (including the rather desperate attempt of trying to put it into the decor myself), I resorted to this nasty way of making it work:
In
onResume
:
a. CallsetSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE)
even when I wouldn't normally do it (landscape)
b. Register anOnPreDrawListener
In the
OnPreDrawListener
:
a. Get the root view usingView root = getRootView().findViewById(R.id.my_root)
b. Get the root view height:int rootTop = getAbsoluteViewTop(root)
(see below)
c. Use that top (intending it as a status bar height) as a paddingTop for the appbar
d. Set the SystemUiVisibility I'd normally use (LAYOUT_STABLE
etc)
e. Suppress the drawing pass- In the next drawing pass, unregister the
OnPreDrawListener
This is the getAbsoluteViewTop()
method:
private int getAbsoluteViewTop(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
return location[LOCATION_Y];
}
tl;dr and question
tl;dr: there is no way to do a proper "lights out" mode with a Toolbar
unless hacky hacks are employed.
Question: is there an official and clean way to implement this lights out mode with Toolbar
?
I couldn't find anything in the docs. The status bar is not accessible (and all the ways to find out its size you can find on SO are broken, FYI). But maybe I'm missing something. I would love to get rid of this hack.