How can one toggle between immersive to non-immersive mode without layout being re-calculated and thus experience a bounce effect?
Here's the relevant code that I'm using to toggle between the states:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
immersive_btn.setOnClickListener {
toggleImmersive()
}
}
val isInFullScreenImmersiveMode: Boolean
get() = window!!.decorView.systemUiVisibility and View.SYSTEM_UI_FLAG_IMMERSIVE == View.SYSTEM_UI_FLAG_IMMERSIVE
private fun toggleImmersive() {
if (isInFullScreenImmersiveMode) {
showSystemBar()
} else {
setFullScreenImmersiveMode()
}
}
fun showSystemBar() {
window!!.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
}
fun setFullScreenImmersiveMode() {
window!!.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE)
}
A video showing the bounce:
Only solution I came up with is using window?.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) in OnCreate() but that would result in another problem: The status bar won't be shown, even when not in full screen immersive mode.
Edit: layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="#+id/immersive_btn"
android:layout_centerInParent="true"
android:layout_centerHorizontal="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Toggle Immersive" />
</RelativeLayout>
I'm using design library navigation view in full screen. But transparency of Navigation Bar and Status Bar bleeds onto NavigationView.Transparent black rectangles occur on right and top of the NavigationView.
My Layout
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<include
android:layout_width="match_parent"
android:layout_height="match_parent"
layout="#layout/layout_custom_view" />
</RelativeLayout>
<!-- Navigation View -->
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/navigation_view_header"
app:menu="#menu/navigation_menu" />
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
if (Build.VERSION.SDK_INT < 16) {
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
hideSystemUI();
}
setContentView(R.layout.activity_main);
// Set NavigationView with Header and Menu
setNavigationView();
}
/*
* ************ SETTING FULLSCREEN TRANSIONS ************
*/
/**
* Hide Status and Navigation bars
*/
public void hideSystemUI() {
if (Build.VERSION.SDK_INT >= 16) {
View decorView = getWindow().getDecorView();
// Hide both the navigation bar and the status bar.
// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and
// higher, but as
// a general rule, you should design your app to hide the status bar
// whenever you
// hide the navigation bar.
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
// Views can use nav bar space if set
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// hide nav bar
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
// hide status bar
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
}
}
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
hideSystemUI();
}
}
Removing View.SYSTEM_UI_FLAG_LAYOUT_STABLE solves the issue.
To test kotlin with anko DSL I decided to start a new proyect in last android studio ide (2.1.3), using kotlin plugin (1.0.3) and latest anko library (0.9)
I used the default proyect Navigation Drawer Activity, so I just had to convert the main xml to anko.
This is the xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<android.support.design.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:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.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" />
</android.support.design.widget.AppBarLayout>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
app:layout_behavior="#string/appbar_scrolling_view_behavior" >
<TextView
android:text="Hello World!"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</android.support.v4.widget.DrawerLayout>
And it is working perfectly, as you can see here:
With anko, I tried to copy every detail from the xml, getting this code:
class MainActivityUi: AnkoComponent<MainActivity> {
override fun createView(ui: AnkoContext<MainActivity>) = with(ui) {
drawerLayout {
id = R.id.drawer_layout
fitsSystemWindows = true
coordinatorLayout {
appBarLayout(R.style.AppTheme_AppBarOverlay) {
toolbar {
id = R.id.toolbar
backgroundColor = colorAttr(R.attr.colorPrimary)
popupTheme = R.style.AppTheme_PopupOverlay
}.lparams(height=dimenAttr(R.attr.actionBarSize),width=matchParent)
}.lparams(width=matchParent)
relativeLayout {
padding = dip(16)
textView("Hello World!")
}.lparams(height=matchParent,width=matchParent) {
behavior = AppBarLayout.ScrollingViewBehavior()
}
}.lparams(height=matchParent,width=matchParent)
navigationView {
id = R.id.nav_view
inflateHeaderView(R.layout.nav_header_main)
inflateMenu(R.menu.activity_main_drawer)
}.lparams(height=matchParent) {
gravity = Gravity.START
fitsSystemWindows = true
}
}
}
}
And instead, I'm getting this white statusbar:
The only changes I did was in the MainActivity change the setContentView(R.layout.activity_main), to MainActivityUi.setContentView(this).
So, my question is, why is this happening when they are the same views and layouts? and how can I fix that?
EDIT: I'm using the default proyect that it's created when in Android Studio you choose new proyect, and then you choose DrawerNavigationActivity. If in setContentView I choose to show the xml's view, the statusbar is blue (first screenshot), but if I choose to show the anko's view I get the white statusbar.
In both cases, I'm using same themes, colors, etc, and when using the xml layout, everything is working perfectly, so it must be an anko's problem
Try to do
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
inside onCreate()
it worked for me
Reference
EDIT:
Also My Code
drawerLayout {
lparams(width = matchParent, height = matchParent)
coordinatorLayout {
setPadding(0, dip(24), 0, 0)
appBarLayout {
toolbar {
backgroundColor = primaryColor
setTitleTextColor(primaryColorText)
}.lparams(width = matchParent, height = dip(toolbar_size))
}.lparams(width = matchParent, height = dip(toolbar_size))
}.lparams(width = matchParent, height = matchParent)
navigationView {
}.lparams(width = dip(302), height = matchParent) {
gravity = Gravity.START
}
}
EDIT 2:
By looking at the source code of androidx, they add some code to handle "fitsSystemWindows". We can copy and paste to archive the same effect. Although Anko is dead, it still useful to create Drawerlayout programmatically (and with any other DSL library)
if (ViewCompat.getFitsSystemWindows(this)) {
if (Build.VERSION.SDK_INT >= 21) {
setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
#Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
final DrawerLayout drawerLayout = (DrawerLayout) view;
drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
return insets.consumeSystemWindowInsets();
}
});
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
final TypedArray a = context.obtainStyledAttributes(THEME_ATTRS);
try {
mStatusBarBackground = a.getDrawable(0);
} finally {
a.recycle();
}
} else {
mStatusBarBackground = null;
}
}
You're wrong thinking that the status bar is transparent by default.
According to this image
taken from Android Developers Reference. Check: https://developer.android.com/training/material/theme.html
the status bar color depends on what you have defined in colors.xml or styles.xml in values folder as colorPrimaryDark, so it's not transparent.
Your problem is not white color in status bar which is correct for transparency, but not enough knowledge of using themes in Android applications.
EDIT: Changing status bar color (Java):
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(activity.getResources().getColor(R.color.my_statusbar_color));
or
public void setStatusBarColor(View statusBar,int color){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//status bar height
int actionBarHeight = getActionBarHeight();
int statusBarHeight = getStatusBarHeight();
//action bar height
statusBar.getLayoutParams().height = actionBarHeight + statusBarHeight;
statusBar.setBackgroundColor(color);
}
}
Hope it will help
It is not your statusbar color issue. Correct me if I am wrong, I believe you are using the Cyanogenmod OS 13.0 edition by the looks of your battery symbol. Switch it back to the default theme in your themes section. Then report back if the issue still persists with your colors.xml file.
Refer this link here for your Kotlin translucent status bar issue.
https://github.com/fython/MaterialStatusBarCompat
I'm trying make my status bar overlay over my content, which includes a CollapsingToolBarLayout ( inside CoordinatorLayout obviously ). So this is my current afford to make it happen;
a sampling from my layout is in the following:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="240dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="false"
app:contentScrim="?attr/colorPrimary">
<ImageView
android:id="#+id/employeeAvatarImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax" />
And in the source, I did the following;
private void setupDecorView() {
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
private void setupStatusBar() {
Window window = getWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor("#3F51B5FF"));
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
} else {
}
}
And I keep getting this image in the initial looking. Status bar is having is original color - no transparency.
However, when I first attemp to scroll, the status bar gets the transparent color I've set and want like the following:
So what might be the problem? Any ideas?
Context
I have a base activity which contains a drawer navigation from the example in android studio. I made the statusbar transparent and I want the menu to slide under it allowing its color to overflow into the transparency like this:
(notice the blue on the right)
However on default it looks like this:
Question
The blue color is from the theme colorPrimaryDark, however I want to dynamically change this color, so I can't rely on the theme. Is there any way to dynamically/programmatically set the color?
Things I've tried
Adjusting the color of the decor view; getWindow().getDecorView().setBackgroundColor(Color.White)
Setting color of the statusbar and use the flag
DRAWS_SYSTEM_BAR_BACKGROUNDS:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.BLUE);
}
(Sorry for the poor coding block, it doesn't want to listen)
This will not make it transparent as the first image, but simply a solid color.
Changing the color of the rootView anyView.getRootView().setBackgroundColor()
XML file: root_controller.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:clipToPadding="false"
tools:openDrawer="end">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- toolbar -->
<include android:id="#+id/toolbar_group"
layout="#layout/toolbar"/>
<FrameLayout
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
XML file toolbar:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
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="52dp">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="52dp"
app:layout_scrollFlags="scroll|enterAlways" />
</android.support.design.widget.AppBarLayout>
RootController activity
public class RootController extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener {
#Override
public void setContentView(int layoutResID) {
rootView = getLayoutInflater().inflate(R.layout.root_controller, null);
drawer = (DrawerLayout)rootView.findViewById(R.id.drawer_layout);
FrameLayout frameLayout = (FrameLayout) drawer.findViewById(R.id.main_content);
targetView = getLayoutInflater().inflate(layoutResID, frameLayout, true);
initMenu(drawer);
super.setContentView(rootView);
}
private void initMenu(DrawerLayout drawer){
// get toolbar
toolbarGroup = rootView.findViewById(R.id.toolbar_group);
initToolbarGroup(toolbarGroup, "test");
// get the navigation view
nav = (NavigationView) drawer.findViewById(R.id.nav_view);
nav.setBackgroundColor(ColorDelegate.getNavColor());
Menu menu = nav.getMenu();
// set navigation listener
nav.setNavigationItemSelectedListener(this);
// ... fill menu
}
Try with this in your Activity:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
String dynamicColor = "#99000000";
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); /*You were missing this*/
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.parseColor(dynamicColor));
}