CollapsingToolbarLayout: Change home button color when expanded - android

I have implemented the new CollapsingToolbarLayout from Chris Banes example code.
However, the images for the backdrop image view have all a white background. The toolbar theme is ThemeOverlay.AppCompat.Dark.ActionBar so the icons are white too, thus I can't see the home button when the CollapsingToolbarLayout is fully expanded.
With app:expandedTitleTextAppearance i can set the color for the title field. Is there also a possibility to set the color of the home buttons and menu icons?

Here is the example how I change my drawer and options icons color when layout is expanded and collapsed:
protected void onCreate(Bundle savedInstanceState) {
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
#Override
public void onOffsetChanged(AppBarLayout appBarLayout, int offset)
{
Drawable upArrow = ResourcesCompat.getDrawable(getResources(), R.drawable.drawer_icon, null);
if (offset < -200)
{
upArrow.setColorFilter(Color.parseColor("#000000"), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setHomeAsUpIndicator(upArrow);
Drawable drawable = ContextCompat.getDrawable(getApplicationContext(),R.drawable.option_menu_icon);
drawable.setColorFilter(Color.parseColor("#000000"), PorterDuff.Mode.SRC_ATOP);
toolbar.setOverflowIcon(drawable);
}
else
{
upArrow.setColorFilter(Color.parseColor("#ffffff"), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setHomeAsUpIndicator(upArrow);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Drawable drawable = ContextCompat.getDrawable(getApplicationContext(),R.drawable.option_menu_icon);
drawable.setColorFilter(Color.parseColor("#ffffff"), PorterDuff.Mode.SRC_ATOP);
toolbar.setOverflowIcon(drawable);
}
}
});

It is better to use 2 different images in Toolbar. Others may cause some unwanted problems:
Trying to set 2 different Toolbar themes will never work because themes are set only on Activity creation, setting another theme has no effect, you need to re-create the Activity.
Using color filter may not result what exactly you want. You may use shadowed arrow and color filter will also paint that shadow which becomes more like outer glow.
So your Toolbar will look like this:
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetStart="0dp"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways|snap">
<ImageView
android:id="#+id/imageViewBack"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:scaleType="center"
android:src="#drawable/button_back_white" />
</android.support.v7.widget.Toolbar>
And you will set imageViewBack drawable as your Toolbar collapses:
appBarLayout.addOnOffsetChangedListener((appBarLayout, offset) -> {
final boolean isCollapsed = (offset == (-1 * appBarLayout.getTotalScrollRange()));
imageViewBack.setImageDrawable(ContextCompat.getDrawable(context,
isCollapsed ?
R.drawable.button_back_red :
R.drawable.button_back_white));
});

You can get a nice color transition while scrolling with the following approach using a ColorFilter. Hope you like Kotlin
app_bar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout: AppBarLayout, offset: Int ->
val colorComponent = Math.max(0.3f,offset.toFloat() / -appBarLayout.totalScrollRange)
toolbar.navigationIcon?.colorFilter =
PorterDuffColorFilter(Color.rgb(colorComponent, colorComponent, colorComponent), PorterDuff.Mode.SRC_ATOP)
})
This will give you a dark navigation icon when the CollapsingToolbarLayout is expanded and a white icon in collapsed state.

In my eyes this is only possible if you change the drawables of the home button, the menu icons and the overflow button. Fortunately Google has give us a new API called Tinted Drawables which allows us to set the collor of a drawable or nine-patch image. Here is how it works:
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#android:drawable/ic_menu_camera"
android:tint="#color/menu_icon_color"/>
Now you can use this new defined Drawable like any other in your layout. For the home button and the overflow button you also have to override the style definitions like so:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="android:homeAsUpIndicator">#drawable/tinted_home_button</item>
<item name="android:actionOverflowButtonStyle">#style/OverFlowButton</item>
</style>
<style name="OverFlowButton" parent="AppTheme">
<item name="android:src">#drawable/tinted_overflow_button</item>
</style>
All these stuff (except the style definitions) is unfortunately only available on API level 21+ and is not included into the support library. If you have to support devices lower then Lollipop I think the best way is to use the Android Assets Studio where you can tint the icons by yourself and download them as a png file.

The home button, overflow button, and some select stock icons from the sdk are affected by colorControlNormal:
<style name="ActionBar" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="colorControlNormal">#color/accent</item>
</style>
If you have other icons, you would need to loop through and manually filter them:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.sample_actions, menu);
for(int i = 0; i < menu.size(); i++){
Drawable drawable = menu.getItem(i).getIcon();
if(drawable != null) {
drawable.mutate();
drawable.setColorFilter(getResources().getColor(R.color.accent), PorterDuff.Mode.SRC_ATOP);
}
}
return true;
}

Related

Changing all toolbar icon colors dynamically

I implemented following function to change the color of all items in actionbar. and i use it to change the color of elements smoothly, when expanding or collapsing CollapsingToolbarLayout.
private void setToolbarElementsColor(int color) {
PorterDuffColorFilter colorFilter
= new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP);
toolbar.getNavigationIcon().setColorFilter(colorFilter);
//overflowDrawable is IconicDrawable from com.mikepenz.iconics
if (toolbar.getOverflowIcon() != overflowDrawable){
toolbar.setOverflowIcon(overflowDrawable);
}
overflowDrawable.color(color);
toolbar.setTitleTextColor(color);
for (int i = 0; i< toolbar.getMenu().size(); i++){
Drawable icon = toolbar.getMenu().getItem(i).getIcon();
if (icon !=null) {
// HERE IS THE CODE WITH EXPLAINED PROBLEM
icon.setColorFilter(colorFilter);
}
}
}
And here is code for menu items:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_back"
android:title="#string/add_remove_filter"
app:showAsAction="always" />
<item
android:id="#+id/action_filter"
android:title="#string/add_filter"
app:showAsAction="always" />
<item
android:id="#+id/action_save_report"
app:showAsAction="never"
android:title="#string/action_save_report">
</item>
</menu>
The code works fine. but one strange problem: when i open overflow menu once and close it, the menu icons retain the last color they have before opening overflow menu, and do not change in accordance to other toolbar elements (the new colors i set for all elements).
Example: Elements are black for expanded state with light toolbar, and white for collapsed state with dark toolbar. now if i collapse the toolbar and open the overflow menu and close it, after that the icon colors remain white, regardless of toolbar expanded or collapsed state, even thought the piece of [icon.setColorFilter(colorFilter);] is run correctly.
The problem solves when the activity goes to background and resumes again. e.g. pressing home button and returning to the activity using recent app list or opening new activity from that activity and returning.
I changed the code inside for loop to the code below but no luck (I am using IconicDrawables for menu icons)
IconicsDrawable icon = (IconicsDrawable) toolbar.getMenu().getItem(i).getIcon();
if (icon !=null) {
icon.color(color);
}
Replacing the icon drawable from IconicDrawable to PNG drawable inside drawables folder also didn't solve the problem.
Try to change the colors of the icon like this,using drawable mutation:-
if (icon !=null) {
icon.mutate();
icon.setColorFilter(colorFilter);
}
After some search, I solved the problem by adding the code below:
#Override
public boolean onMenuOpened(int featureId, Menu menu) {
invalidateOptionsMenu();
return super.onMenuOpened(featureId, menu);
}
It just redraws icons just after opening the overflow menu. but the reason of above mentioned problem is yet unknown to me.

Custom image and color for the back button on toolbar

I want to show the "x" button instead of the default back arrow as the "home" button on toolbar. I have searched how to use a custom image and it works and I have searched how to use a specific color for the back arrow and it works. The problem is, when I put both the custom image and the custom color, it shows the image with its default color, black, when I want it to be blue.
This is the xml for the toolbar:
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="#+id/toolbar"
android:theme="#style/ThemeToolbar">
And this is the ThemeToolbar style:
<style name="ThemeToolbarDetails" parent="Theme.AppCompat.Light">
<item name="colorControlNormal">#color/blue</item>
<item name="homeAsUpIndicator">#drawable/close</item>
</style>
I have tried colorControlNormal, android:textColorSecondary but none of this works when using a custom image.
First of all, keep this line on your style: <item name="homeAsUpIndicator">#drawable/close</item>.
Then, you have a couple of ways of solving the color part.
Option 1: If you're working with Vector Drawables, it's easier to just change the color inside the XML file.
Option 2: Alternatively, you can also programmatically tint any menu item. Get the Menu object in the onCreateOptionsMenu() method, and then try the snippet below:
private void tintIcon(#NonNull MenuItem item, int color) {
Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
Option 3: Change the drawable and the color programatically.
final Drawable myIcon = ContextCompat.getDrawable(context, R.drawable.your_icon);
myIcon.setColorFilter(ContextCompat.getColor(context, R.color.your_color), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setHomeAsUpIndicator(myIcon);

how to dynamically change OverflowButton's background for press state

Having the android.support.v7.widget.Toolbar and it's background color is changing based on different cases.
The OverflowButton button (the three vertical dots at right of the toolbar) is always having the same background when press on it.
Saw some posts about how to change statically, like quoted below. But really want is to do it dynamically based the toolbar's background color.
Any idea?
To change statically:
You can change the image used for it using the following style declaration.
<style name="MyCustomTheme" parent="style/Theme.Holo">
<item name="android:actionOverflowButtonStyle">#style/MyCustomTheme.OverFlow</item>
</style>
<style name="MyCustomTheme.OverFlow">
<item name="android:src">#drawable/my_overflow_image</item>
</style>
And if you're using ActionBarSherlock, here's how to do it
<style name="MyCustomTheme" parent="style/Theme.Sherlock">
<item name="android:actionOverflowButtonStyle">#style/MyCustomTheme.OverFlow</item>
<item name="actionOverflowButtonStyle">#style/MyCustomTheme.OverFlow</item>
</style>
<style name="MyCustomTheme.OverFlow">
<item name="android:src">#drawable/my_overflow_image</item>
</style>
Edit-- The answer should be:
It could be achieved by just to set partial transparent background in the style of actionOverflowButtonStyle so that whatever the toolbar's color will be blended in.
one solution might be just disable the press state by making it transparent for all toolbars, but it is no desirable.
Another one found, but feel like a hack.
Not sure if anyone have better way to get access to the overflow button so it's background could be set dynamically with proper drawable.
from this bug report,
it could be done as the following setupOverflowMenuButton().
public boolean setupOverflowMenuButton (Menu menu, Toolbar toolbar) {
Toolbar t = toolbar;
for(int i = 0; i < t.getChildCount(); i++) {
if(t.getChildAt(i) instanceof ActionMenuView) {
ActionMenuView v = (ActionMenuView)t.getChildAt(i);
for(int j = 0; j < v.getChildCount(); j++) {
if(v.getChildAt(j) instanceof TintImageView) {
TintImageView v1 = (TintImageView)v.getChildAt(j);
v1.setBackgroundResource(R.drawable.overflow_bt_bg_selector);
}
}
}
}
return super.onPrepareOptionsMenu(menu);
}

Toolbar icon tinting on Android

I've noticed that using AppCompat themes, default toolbar icons get tinted by the attribute colorControlNormal in my style.
<style name="MyTheme" parent="Theme.AppCompat">
<item name="colorControlNormal">#color/yellow</item>
</style>
As you can see above, however, it does not happen with all icons. I provided the "plus" sign, which I got from the official icons, and it does not get tinted (I used the "white" version of the png). From what I have understood from this question, system tints only icons with just an alpha channel. Is this true?
If so: Is there a place where I can find alpha-defined, official material icons? If not - and if Toolbar icons need to be alpha-only to be tinted - how is Google expecting us to use provided icons in a Toolbar?
Somewhere in the SDK I found some icons ending in _alpha.png, and they actually get tinted well. However I need the full set of material icons, and from the official sources I could only find white, grey600 and black ones.
Applying a ColorFilter at runtime would be slightly painful, and my actual Toolbar - with some icons tinted, some others not - looks quite bad.
Another option is to use the new support for vector drawables in the support library.
See res/xml/ic_search.xml in blog post AppCompat — Age of the vectors
Notice the reference to ?attr/colorControlNormal
<vector xmlns:android="..."
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:pathData="..."
android:fillColor="#android:color/white"/>
</vector>
Here is the solution that I use. Call tintAllIcons after onPrepareOptionsMenu or the equivalent location. The reason for mutate() is if you happen to use the icons in more than one location; without the mutate, they will all take on the same tint.
public class MenuTintUtils {
public static void tintAllIcons(Menu menu, final int color) {
for (int i = 0; i < menu.size(); ++i) {
final MenuItem item = menu.getItem(i);
tintMenuItemIcon(color, item);
tintShareIconIfPresent(color, item);
}
}
private static void tintMenuItemIcon(int color, MenuItem item) {
final Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
private static void tintShareIconIfPresent(int color, MenuItem item) {
if (item.getActionView() != null) {
final View actionView = item.getActionView();
final View expandActivitiesButton = actionView.findViewById(R.id.expand_activities_button);
if (expandActivitiesButton != null) {
final ImageView image = (ImageView) expandActivitiesButton.findViewById(R.id.image);
if (image != null) {
final Drawable drawable = image.getDrawable();
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
image.setImageDrawable(drawable);
}
}
}
}
}
This won't take care of the overflow, but for that, you can do this:
Layout:
<android.support.v7.widget.Toolbar
...
android:theme="#style/myToolbarTheme" />
Styles:
<style name="myToolbarTheme">
<item name="colorControlNormal">#FF0000</item>
</style>
This works as of appcompat v23.1.0.
I actually was able to do this on API 10 (Gingerbread) and it worked very well.
Edit: It worked on API 22 also...
Here's the final result.
Note: The icon is a drawable resource in the drawable folder(s).
Now here's how its done:
#Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
MenuItem item = menu.findItem(R.id.action_refresh);
Drawable icon = getResources().getDrawable(R.drawable.ic_refresh_white_24dp);
icon.setColorFilter(getResources().getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN);
item.setIcon(icon);
}
At this point you can change it to any color you want!
That's the final and true answer
First create style for toolbar like this:
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" >
<item name="iconTint">#color/primaryTextColor</item>
<!--choice your favorite color-->
</style>
Then in your main app or activity theme add this line
<item name="actionBarPopupTheme">#style/AppTheme.PopupOverlay</item>
And finally in you'r layout file add this line to toolbar
android:theme="?attr/actionBarPopupTheme"
And Then you will see your toolbar icons colored in your favorite color
I see this question is getting some views so I'm going to post an answer for those who don't read the comments.
My conjectures in the question were all wrong and it is not a matter of alpha channels, at least not externally. The fact is simply that, quoting #alanv ,
AppCompat only tints its own icons. For now, you will need to manually
tint any icons that you're providing separately from AppCompat.
This might change in the future but also might not. From this answer you can also see the list of icons (they all belong to the internal resource folder of appcompat, so you can't change them) that are automatically tinted and with which color.
Personally I use a colorControlNormal which is black or white (or similar shades), and import the icons with that particular color. Colored icons on a colored background look a little bad. However, another solution I found pleasant is this class on github. You just call MenuColorizer.colorMenu() when you create the menu.
You could just create a custom Toolbar that uses your tint color when inflating the menu.
public class MyToolbar extends Toolbar {
... some constructors, extracting mAccentColor from AttrSet, etc
#Override
public void inflateMenu(#MenuRes int resId) {
super.inflateMenu(resId);
Menu menu = getMenu();
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
Drawable icon = item.getIcon();
if (icon != null) {
item.setIcon(applyTint(icon));
}
}
}
void applyTint(Drawable icon){
icon.setColorFilter(
new PorterDuffColorFilter(mAccentColor, PorterDuff.Mode.SRC_IN)
);
}
}
Just make sure you call in your Activity/Fragment code:
toolbar.inflateMenu(R.menu.some_menu);
toolbar.setOnMenuItemClickListener(someListener);
No reflection, no view lookup, and not so much code, huh?
And don't use onCreateOptionsMenu/onOptionsItemSelected, if you use this approach
For sdk 23 or higher:
<style name="AppThemeToolbar" parent="MyAppTheme">
....
<item name="android:drawableTint">#color/secondaryLightColor</item>
</style>
My toolbar
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:theme="#style/AppThemeToolbar"
android:layout_width="match_parent"
android:layout_height="attr/actionBarSize">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
With androidX you can define your Toolbar like this
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="#style/Toolbar" />
Then, extend an AppCompat theme and set colorControlNormal property as you like:
<style name="Toolbar" parent="Theme.AppCompat.Light">
<item name="colorControlNormal">#color/colorBaseWhite</item>
<item name="android:background">#color/colorPrimary</item>
</style>
This can be done in Kotlin with:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
menu.getItem(0)?.icon?.setTint(Color.WHITE)
}
else {
#Suppress("DEPRECATION")
menu.getItem(0)?.icon?.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN)
}
It should work on all modern versions of Android, and will fail without a crash if getItem or icon returns null.
try this ... 😊
menu.getItem(0).getIcon().setTint(Color.parseColor("#22CC34"));
#NonNull
public static Drawable setTintDrawable(#NonNull Drawable drawable, #ColorInt int color) {
drawable.clearColorFilter();
drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
drawable.invalidateSelf();
Drawable wrapDrawable = DrawableCompat.wrap(drawable).mutate();
DrawableCompat.setTint(wrapDrawable, color);
return wrapDrawable;
}
and call in this manner:
MenuItem location = menu.findItem(R.id.action_location);
DrawableUtils.setTintDrawable(location.getIcon(), Color.WHITE);
Basically, when you set menu, the three-dot icon takes up the color of android:textColorSecondary from the AppTheme, which in default is set to Black.
So if you are not using, textColorSecondary anywhere in your project, then you can simply add the following line
<item name="android:textColorSecondary">#color/White</item>
After adding it may look like this.
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customise your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:textColorSecondary">#color/White</item>
</style>

Lollipop : draw behind statusBar with its color set to transparent

I have set my statusBar color to transparent for Lollipop only with the following line in my theme :
<item name="android:statusBarColor">#android:color/transparent</item>
Now I need to draw behind it, but I can't get any view draw behind it. I know how to do it with the windowTranslucentStatus property, but don't want to use this property since it will then ignore the color of the statusBar set to transparent.
Method #1:
To achieve a completely transparent status bar, you have to use statusBarColor, which is only available on API 21 and above. windowTranslucentStatus is available on API 19 and above, but it adds a tinted background for the status bar. However, setting windowTranslucentStatus does achieve one thing that changing statusBarColor to transparent does not: it sets the SYSTEM_UI_FLAG_LAYOUT_STABLE
and SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flags. The easiest way to get the same effect is to manually set these flags, which effectively disables the insets imposed by the Android layout system and leaves you to fend for yourself.
You call this line in your onCreate method:
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
Be sure to also set the transparency in /res/values-v21/styles.xml:
<item name="android:statusBarColor">#android:color/transparent</item>
Or set the transparency programmatically:
getWindow().setStatusBarColor(Color.TRANSPARENT);
The good side to this approach is that the same layouts and designs can also be used on API 19 by trading out the transparent status bar for the tinted translucent status bar.
<item name="android:windowTranslucentStatus">true</item>
Method #2:
If you only need to paint a background image under your status bar, instead of positioning a view behind it, this can be done by simply setting the background of your activity's theme to the desired image and setting the status bar transparency as shown in method #1. This was the method I used to create the screenshots for the Android Police article from a few months ago.
Method #3:
If you've got to ignore the standard system insets for some layouts while keeping them working in others, the only viable way to do it is to work with the often linked ScrimInsetsFrameLayout class. Of course, some of the things done in that class aren't necessary for all scenarios. For example, if you don't plan to use the synthetic status bar overlay, simply comment out everything in the init() method and don't bother adding anything to the attrs.xml file. I've seen this approach work, but I think you'll find that it brings some other implications that may be a lot of work to get around.
I also saw that you're opposed to wrapping multiple layouts. In the case of wrapping one layout inside of another, where both have match_parent for height and width, the performance implications are too trivial to worry about. Regardless, you can avoid that situation entirely by changing the class it extends from FrameLayout to any other type of Layout class you like. It will work just fine.
This worked for my case
// Create/Set toolbar as actionbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Check if the version of Android is Lollipop or higher
if (Build.VERSION.SDK_INT >= 21) {
// Set the status bar to dark-semi-transparentish
getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// Set paddingTop of toolbar to height of status bar.
// Fixes statusbar covers toolbar issue
toolbar.setPadding(0, getStatusBarHeight(), 0, 0);
}
// A method to find height of the status bar
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
For more information about working with statusBars: youtube.com/watch?v=_mGDMVRO3iE
Try this theme
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="colorPrimaryDark">#android:color/transparent</item>
<item name="colorPrimary">#color/md_blue_200</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
Be sure that, your layout set
android:fitsSystemWindows="false"
Instead of
<item name="android:statusBarColor">#android:color/transparent</item>
Use the following:
<item name="android:windowTranslucentStatus">true</item>
And make sure to remove the top padding (which is added by default) on your 'MainActivity' layout.
Note that this does not make the status bar fully transparent, and there will still be a "faded black" overlay over your status bar.
The solution from Cody Toombs almost did the trick for me. I'm not sure if this is Xamarin related or not, but I now have an acceptable solution:
This is my setup:
I have an Android project where I have referenced the Android.Support v4 and v7 packages. I have two styles defined:
values/styles.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<style name="MyStyle" parent="#style/Theme.AppCompat.Light.NoActionBar">
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
values-v21/styles.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<style name="MyStyle" parent="#style/Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">#android:color/transparent</item>
</style>
</resources>
AndroidManifest targets "MyStyle":
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.agn.test.test">
<uses-sdk android:minSdkVersion="10" />
<application android:allowBackup="true" android:icon="#mipmap/icon" android:label="#string/app_name" android:theme="#style/MyStyle">
</application>
</manifest>
And finally the code in the Main Activity:
[Activity (Label = "Test", MainLauncher = true, Icon = "#mipmap/icon")]
public class MainActivity : Activity
{
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main);
//Resource.Layout.Main is just a regular layout, no additional flags. Make sure there is something in there like an imageView, so that you can see the overlay.
var uiOptions = (int)Window.DecorView.SystemUiVisibility;
uiOptions ^= (int)SystemUiFlags.LayoutStable;
uiOptions ^= (int)SystemUiFlags.LayoutFullscreen;
Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions;
Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds);
}
}
Notice that I set DrawsSystemBarBackgrounds flag, this makes all the difference
Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds);
I spent a lot of time getting it right, too much time in fact. Hopefully this answer helps anyone trying to achieve the same thing.
#Cody Toombs's answer lead to an issue that brings the layout behind the navigation bar. So what I found is using this solution given by #Kriti
here is the Kotlin code snippet for the same:
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true)
}
if (Build.VERSION.SDK_INT >= 19) {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false)
getWindow().setStatusBarColor(Color.TRANSPARENT)
}
private fun setWindowFlag(activity: Activity, bits: Int, on: Boolean) {
val win: Window = activity.getWindow()
val winParams: WindowManager.LayoutParams = win.getAttributes()
if (on) {
winParams.flags = winParams.flags or bits
} else {
winParams.flags = winParams.flags and bits.inv()
}
win.setAttributes(winParams)
}
You also need to add
android:fitsSystemWindows="false"
root view of your layout.
I had the same problem so i create ImageView that draw behind status bar API 19+
Set custom image behind Status Bar gist.github.com
public static void setTransparent(Activity activity, int imageRes) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
return;
}
// set flags
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
// get root content of system window
//ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
// rootView.setFitsSystemWindows(true);
// rootView.setClipToPadding(true);
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
if (contentView.getChildCount() > 1) {
contentView.removeViewAt(1);
}
// get status bar height
int res = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
int height = 0;
if (res != 0)
height = activity.getResources().getDimensionPixelSize(res);
// create new imageview and set resource id
ImageView image = new ImageView(activity);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
image.setLayoutParams(params);
image.setImageResource(imageRes);
image.setScaleType(ScaleType.MATRIX);
// add image view to content view
contentView.addView(image);
// rootView.setFitsSystemWindows(true);
}
You can use ScrimInsetFrameLayout
https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java
android:fitsSystemWindows="true" should set on scrim layout!
I will be adding some more information here. The latest Android developments have made it pretty easy to handle a lot of cases in status bar. Following are my observations from the styles.xml
Background color: for SDK 21+, as a lot of answers mentioned,<item name="android:windowTranslucentStatus">true</item> will make the status bar transparent and show in front of UI. Your Activity will take the whole space of the top.
Background color: again,for SDK 21+, <item name="android:statusBarColor">#color/your_color</item> will simply give a color to your status bar, without affecting anything else.
However, in later devices (Android M/+), the icons started coming in different shades. The OS can give a darker shade of gray to the icons for SDK 23/+ , if you override your styles.xml file in values-23 folder and add <item name="android:windowLightStatusBar">true</item>.
This way, you will be providing your user with a more visible status bar, if your status bar has a light color( think of how a lot of google apps have light background yet the icons are visible there in a greyish color).
I would suggest you to use this, if you are giving color to your status bar via point #2
In the most recent devices, SDK 29/+ comes with a system wide light and dark theme, controllable by the user. As devs, we are also supposed to override our style file in a new values-night folder, to give user 2 different experiences.
Here again, I have found the point #2 to be effective in providing the "background color to status bar". But system was not changing the color of status bar icons for my app. since my day version of style consisted of lighter theme, this means that users will suffer from low visibility ( white icons on lighter background)
This problem can be solved by using the point #3 approach or by overriding style file in values-29 folder and using a newer api <item name="android:enforceStatusBarContrast">true</item> . This will automatically enforce the grayish tint to icons, if your background color is too light.
With Android Studio 1.4, the template project with boiler plate code sets Overlay theme on your AppbarLayout and/or Toolbar. They are also set to be rendered behind the status bar by fitSystemWindow attribute = true. This will cause only toolbar to be rendered directly below the status bar and everything else will rendered beneath the toolbar. So the solutions provided above won't work on their own. You will have to make the following changes.
Remove the Overlay theme or change it to non overlay theme for the toolbar.
Put the following code in your styles-21.xml file.
#android:color/transparent
Assign this theme to the activity containing the navigation drawer in
the AndroidManifest.xml file.
This will make the Navigation drawer to render behind the transparent status bar.
Similar to some of the solutions posted, but in my case I did the status bar transparent and fix the position of the action bar with some negative margin
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(Color.TRANSPARENT);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) toolbar.getLayoutParams();
lp.setMargins(0, -getStatusBarHeight(), 0, 0);
}
And I used in the toolbar and the root view
android:fitsSystemWindows="true"
There is good library StatusBarUtil from #laobie that help to easily draw image in the StatusBar.
Just add in your build.gradle:
compile 'com.jaeger.statusbarutil:library:1.4.0'
Then in the Activity set
StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View viewNeedOffset)
In the layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:background="#color/white"
android:orientation="vertical">
<ImageView
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:adjustViewBounds="true"
android:layout_height="wrap_content"
android:src="#drawable/toolbar_bg"/>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/view_need_offset"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#android:color/transparent"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<!-- Your layout code -->
</android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
For more info download demo or clone from github page and play with all feature.
Note: Support KitKat and above.
Hope that helps somebody else!
All you need to do is set these properties in your theme
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
The accepted answer worked for me using a CollapsingToolbarLayout. It's important to note though, that setSytstemUiVisibility() overrides any previous calls to that function. So if you're using that function somewhere else for the same view, you need to include the View.SYSTEM_UI_FLAG_LAYOUT_STABLE and View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN flags, or they will be overridden with the new call.
This was the case for me, and once I added the two flags to the other place I was making a call to setSystemUiVisibility(), the accepted answer worked perfectly.
Here is the theme I use to accomplish this:
<style name="AppTheme" parent="#android:style/Theme.NoTitleBar">
<!-- Default Background Screen -->
<item name="android:background">#color/default_blue</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
The Right solution is to Change a property in XML under your Activity tag to below style. It just works
android:theme="#style/Theme.AppCompat.Light.NoActionBar"

Categories

Resources