Material design toolbar on devices pre-lollipop - android

I'm flollowing next tutorial:
https://chris.banes.me/2014/10/17/appcompat-v21/
I want do that similar design:
I know i need use Two toolbars.
values/themes.xml
<resources>
<style name="Theme.MiThema" parent="Theme.AppCompat.Light">
<!-- Here we setting appcompat’s actionBarStyle -->
<!--<item name="actionBarStyle">#style/MyActionBarStyle</item>-->
<!-- ...and here we setting appcompat’s color theming attrs -->
<item name="colorPrimary">#color/primary</item>
<item name="colorPrimaryDark">#color/primary_dark</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#color/accent</item>
</style>
</resources>
class.java
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.Toolbar;
public class RegistrarInciTraActivity extends ActionBarActivity
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.registrar_inci_traf_layout);
//ocultamos ActionBar
getSupportActionBar().hide();
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
}
layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="horizontal">
<!-- The toolbar -->
<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="?attr/colorPrimary" />
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/my_drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- drawer view -->
<LinearLayout
android:layout_width="304dp"
android:layout_height="match_parent"
android:layout_gravity="left|start">
<!-- drawer content -->
</LinearLayout>
<!-- normal content view -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- The rest of content view -->
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
Tha code report one error on "setSupportActionBar(toolbar);":
(first problem) ¿What is the problem about that? (SOLVED)
(Second problem)
On my layout appear
"?attr/actionBarSize" and "?attr/colorPrimary"
Where do I have to declare those attributes?
(Third problem)
When I do two toolbars only appear once of them and I want one inside the other to display content.
What I do have to display both toolbars?
Thanks

I can give you an answer for your first problem. It is very simple - you only have to read the message given by your IDE. You're using the wrong toolbar. The toolbar you're trying to pass to the setSupportActionBar-Method is from the package android.widget. But you've to use the toolbar from the package android.support.v7.widget. So your imports are wrong - correct them and your code should work.

As 1st Problem is solved, let me try Second one,
First of all, you do not have to define these values anywhere, they are pre-defined.
"?attr/actionBarSize" : this is a default value provided by Android. You will get it at android.support.v7.appcompat/R,but it will give you an int reference. If you want to know the actual height of the Actionbar, you have to resolve the attribute actionBarSize at runtime. Follow this Link : Get ActionBar Size(answer given on other SO Q.).
Also Now with Material Design, Google shared some standards to be used while designing new Apps (or upgrading old one) in Material Design. You can follow those norms here : LayoutMetrics & keylines
"?attr/colorPrimary" : This is also a pre-defined value. You can get it at android.support.v7.appcompat/R, but it will give you an int reference. But if you want a custom background color to your ToolBar then just add an appropriate color palette, android:background="#color/colorPrimary" and define colorPrimary value in color.xml. Use this site to get different color values : Material Palette (I prefer this site).

Related

Remove extra background color rectangle from overflow menu enter/exit animations?

When I open the overflow menu in my application, I see a solid rectangle of the menu background color displayed behind the menu itself throughout the enter/exit animations. Here's an animation showing this (slowed to 75% speed):
The presence of this extraneous colored rectangle spoils the nice enter/exit animations! How can I remove it while retaining all other Toolbar styling?
Research
I've read a bunch of answers on Toolbar styling on SO, and Chris Banes' own posts on the subject. It seems that usage of the style/theme tags on a per-View basis has changed in the past couple years, which has made it difficult to find definitive information anywhere.
I've reproduced this using versions 22.1.0 through 23.2.0 (inclusive) of the support library.
App files
styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
</style>
<style name="ToolbarStyle" parent="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:background">#color/colorPrimary</item>
</style>
</resources>
activity_main.xml
<LinearLayout
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="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:style="#style/ToolbarStyle" />
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Runtime View Analysis
As #Commonsware suggested, I took a look at the view hierarchy at run time. Editing in the results:
Menu collapsed (overflow button present, no mysterious extra rectangle):
Menu expanded (overflow menu views displayed in separate Window):
The main application view hierarchy (as displayed in the original Window) is unchanged when comparing the two menu (steady) states. My guess is therefore that the extra rectangle is temporarily added to the main application's window during menu animations, and immediately removed upon their completion. I'm not sure why this would be done - perhaps it's a hangover from an older (and now unused) method of showing and hiding the overflow menu? If my deduction is correct, then this question could be resolved if we can determine how to prevent this transitory behavior...
An extract from the Chris Bane's answer to the question AppCompat style background propagated to the Image within the ToolBar
style = local to the Toolbar
theme = global to everything inflated in the Toolbar
Based on the above post it seems, the android:background attribute you are setting in the android:theme is the reason for the extra background color during the animation.
I'd set the background to the toolbar directly and used the android:colorBackground attribute to set the background color for the popup. The animation seems to work fine.
Code:
activity_main.xml
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:theme="#style/CustomToolbarTheme" />
styles.xml
<style name="CustomToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
<item name="android:colorBackground">#color/colorPrimary</item>
<item name="android:textColorPrimary">#android:color/white</item>
</style>

How to implement Toolbar Layout

How do I remove the boundary between action and toolbar?
Bad Case
Good Case, I want to like it.
Activity XML
Fragment XML
What you are looking for is a way to remove the shadow under toolbar.
For android 4.4 or below, you will have to set the window content overlay in your activity theme like this
<style name="Theme.MyApp" parent="Theme.AppCompat.Light.NoActionBar">
...
<!--To hide shadow effect in toolbar for Android 4.4 or below-->
<item name="android:windowContentOverlay">#null</item>
</style>
For Android 5.0+, you will also need to set the toolbar elevation to 0 in the activity layout like this.
<LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
...
>
<android.support.design.widget.AppBarLayout
...
app:elevation="0dp">
...
</android.support.design.widget.AppBarLayout>
</LinearLayout>
Actually, many people ask about this. See answer here
Try to search for existing answer next time ;)

How to disable Toolbar fade-in animation?

Is there a way to disable the fade-in / fade-out animation for ToolBar elements?
I found a solution for the status bar:
getWindow().getEnterTransition().excludeTarget(android.R.id.statusBarBackground, true);
But I can not find a similar fix for the ToolBar. Everytime I load a new Activity, it causes an undesired flash.
Edit:
styles.xml
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Status Bar Color -->
<item name="android:colorPrimaryDark" tools:targetApi="21">#color/primary_4</item>
</style>
<!-- Toolbar Style -->
<style name="toolbar">
<item name="android:textColorPrimary">#color/primary_0</item>
<item name="colorControlNormal">#color/primary_0</item>
<item name="colorControlHighlight">#color/primary_3</item>
</style>
</resources>
In activity_main.xml & activity_details.xml
<android.support.v7.widget.Toolbar
xmlns:app="http://schemas.android.com/apk/res-auto"
app:theme="#style/toolbar"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/actionBarSize"
android:background="#color/primary_4" />
The Elevation animation duration value is R.integer.app_bar_elevation_anim_duration which by default is 150.
To avoid the animation, just put following into any xml under res/values and that's it:
<integer name="app_bar_elevation_anim_duration" tools:override="true">0</integer>
The documentation for excludeTarget() says:
public Transition excludeTarget (View target,
boolean exclude) :
Whether to add the given target to the list of targets to exclude from
this transition. The exclude parameter specifies whether the target
should be added to or removed from the excluded list.
Excluding targets is a general mechanism for allowing transitions to
run on a view hierarchy while skipping target views that should not be
part of the transition. For example, you may want to avoid animating
children of a specific ListView or Spinner. Views can be excluded
either by their id, or by their instance reference, or by the Class of
that view
This means that the way you excluded the status bar from the enter transition would also work for the toolbar.
I tried it and it's working.
secondActivity.xml:
...
<include
android:id="#+id/customToolbar"
layout="#layout/toolbar" />
...
SecondActivity.java (Inside onCreate()):
...
getWindow().getEnterTransition().excludeTarget(R.id.customToolbar, true);
...

Android Navigation Drawer and windowActionBarOverlay = true

I'm trying to implement the new Android Navigation Drawer in my application. I have created a BaseActivity.java that handles the Drawer setup and listeners, and I have two subactivities that extend this base class. On the second activity, I plan to use a different action bar style, using the following attrs:
<item name="android:windowActionBarOverlay">true</item>
<item name="android:background">#android:color/transparent</item>
to make the action bar transparent, and make content richer, as there is a picture header in my layout.
I've achieved just that, but now the problem is, that because the content is expanding to take advantage of the extra space of using the ActionBar as overlay, the Navigation Drawer itself is expanding too and it overlaps the ActionBar, creating a pretty awful looking layout:
What I'd like to have done, is the actual content (frame layout that will be populated with a fragment) to take up the extra space, but have the nav drawer still go underneath the action bar, similar to the Play Music App:
Any ideas on what I can do to make that happen?
EDIT So, as per Ahmad's assistance I set the marginTop on the ListView only. Here's the layout:
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
<!-- This was added after seeing the crazy effect, but does nothing -->
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_width="240dp"
android:layout_height="fill_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:background="?attr/listviewBackground"
/>
And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
Not sure what's causing it :(
And now, it works great for the top side, but for some reason there's also a margin at the bottom of the view, which doesn't make any sense to me at all. Here's a screenshot.
If you set your ListView gravity to start|bottom it solves your problem. No additional margin is added at the bottom. Looks like the DrawerLayout default gravity is start|center
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start|bottom"/>
In case anyone is interested in another take to this question. Here's what happened.
I tried setting only the margin to the top of the list view like this:
android:layout_marginTop="?android:attr/actionBarSize"
But as mentioned on the edited question, that had a weird behaviour where there was also a margin on the bottom despite not being set on the layout resource file.
So, I was looking closely at the Play Music App and noticed that it's not actually a margin, but rather some padding, and additionally they are using a custom background that fills the space specified by the padding with a transparent color.
Here's what I did:
Set Padding at the top of the ListView, rather than margin:
android:paddingTop="?android:attr/actionBarSize"
As said before, it's important to not hard code the dimensions as they vary per device.
Create a custom drawable that has a top part transparent, and then rest of a solid color:
It looks somehow like this:
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle">
<solid android:color="#80000000" />
</shape>
</item>
<item android:top="#dimen/action_bar_default_height">
<shape
android:shape="rectangle">
<solid android:color="#color/light_gray" />
</shape>
</item>
Note that I tried to use ?android:attr/actionBarSize on the drawable, but that made the app force close. Instead, I searched through grepcode and found a few dimen files with different sizes for the action bar, so I added those to my own project's dimen files.
For values: 48dp
For values-land: 40dp
For values-sw600dp: 56dp
And after that, I think I looks great, notice on the screenshot how the listview and the actionbar don't overlap, and the transparent part of the listview is just the right size.
Hope that helps anyone who was wondering how to achieve this.
You can set a margin at the top of your layout, so that the content draws itself below the ActionBar.
Just add this in your parent layout:
android:layout_marginTop="?android:attr/actionBarSize"
The attribute actionBarSize refers to, like you would have already guessed, to the size of the ActionBar. You can't set an absolute value as a margin, since the ActionBar does not always have the same size across all Android devices (It's bigger on tablets, smaller on handset devices).
Edit:
Set the margin to the ListView.
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/left_drawer"
android:layout_marginTop="?android:attr/actionBarSize"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
</android.support.v4.widget.DrawerLayout>
The Google Music app does the same:
I solved this problem using paddingTop:
<FrameLayout
android:id="#+id/menu_frame"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:paddingTop="?attr/actionBarSize" >
<ListView
android:id="#+id/left_drawer_list"
android:layout_width="240dp"
android:layout_height="match_parent" />
</FrameLayout>
Hope that helps
I have created a working demo following the above guide and tested on 2.x to 5.x
You can clone from Github
The important thing to play around is in Main Activity
toolbar = (Toolbar) findViewById(R.id.toolbar);
res = this.getResources();
this.setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
ScrimInsetsFrameLayout scrimInsetsFrameLayout = (ScrimInsetsFrameLayout)
findViewById(R.id.linearLayout);
scrimInsetsFrameLayout.setOnInsetsCallback(this);
}
and the call back
#Override
public void onInsetsChanged(Rect insets) {
Toolbar toolbar = this.toolbar;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
toolbar.getLayoutParams();
lp.topMargin = insets.top;
int top = insets.top;
insets.top += toolbar.getHeight();
toolbar.setLayoutParams(lp);
insets.top = top; // revert
}
Absolutely the Theme for V21 does the magic
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- API 21 theme customizations can go here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/accent_material_light</item>
<item name="windowActionModeOverlay">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">#android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
</style>

How to set a default layout in a theme

I'm using a custom titlebar in my app, but everytime I create a new layout I have to call:
<include
android:id="#+id/titlebar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="#integer/titlebar_weight"
layout="#layout/titlebar" />
Instead calling this in all the layouts how can I define it in a theme (in other words: define a default layout for the theme)?
My default layout:
Although the old title bar can be customized a bit via a theme (windowTitleStyle, windowTitleSize, windowTitleBackgroundStyle), you cannot set your own layout. Also the title bar was replaced by the ActionBar in Android 3.0, so that won't help you anyway.
Setting a default layout in a theme is not possible, at least I could not find a way to do it. But you still have several options to reduce repetition when adding your header layout:
Create a master layout with your header and a ViewStub for your content, then set the inflatedId by code.
Consider building your screens with fragments and add/remove them programmatically from your master layout.
Add the header programmatically in a base activity (suggested by user1527136)
Include it (that is what you are already doing, and it is not that bad imho)
I would recommend against creating the actionbar yourself, you can either try:
Actionbar Sherlock or ActionbarCompat (from the Google samples in your SDK).
<resources>
<style name="Theme.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
</resources>
<activity
android:theme="#style/Theme.Transparent"
</activity>
I don't think this can be achieved through theming alone. You would need to create an abstract Activity that will include your title bar and wrap the content view set by the extended Activity classes. Here's an example:
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<include
android:id="#+id/titleBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
layout="#layout/titlebar" />
<FrameLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Abstract Activity
public abstract class TitleBarActivity extends Activity {
#Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
super.setContentView( R.layout.title_bar_activity );
}
#Override
public void setContentView( int layoutResId ) {
FrameLayout contentFrameLayout = (FrameLayout) findViewById( R.id.content );
contentFrameLayout.removeAllViews();
getLayoutInflater().inflate( layoutResId, contentFrameLayout );
}
}
This is a very simple implementation, but should give you the general idea of what you need to do. Now for any Activity that extends TitleBarActivity, you'll already have the title bar at the top by default. Any customization of the title you want your activities to control, add methods in TitleBarActivity to do so.

Categories

Resources