Android Tutorial Material Design 3 - Using a ToolBar as ActionBar

Note: You should use B4A 6.0 or above for this tutorial.

Google recommends to use a ToolBar instead of the standard system ActionBar for Material Design apps. In this tutorial we will use a ACToolBar(Light/Dark) object from the AppCompat library (1.10 and above) as an ActionBar.

One of the main differences between a ToolBar and the standard ActionBar is that the ActionBar is a system component which is automatically added by the os and a ToolBar is part of our layout so we can add it to the activity with the designer or by code.

Using the ToolBar object

First we need to set up our project like in the Material Design 2 tutorial.
Then we need to add some more items to the theme:

B4X:
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="windowActionModeOverlay">true</item>

This disables the standard ActionBar in the theme. With the windowActionModeOverlay set to true ActionMode Actionbars will replace the ToolBar and are not displayed above it.

Now we can create our layout. For the example project I decided to split the layout into two parts. One "main" layout which contains the ToolBar and a simple Panel for the content.
So add a CustomView of type "ACToolBarLight" to a new layout called "main" and set the following properties:

Layout_ActionBar.png


Note that "Use as main ActionBar" is checked to use this Toolbar as the main ActionBar for the Activity. You can only use one Toolbar as the Activity ActionBar.
Elevation should be set to 4 for a normal ActionBar. This will produce a small shadow below it.
Additionally you should disable the Background color in the properties.

There are two versions of the ToolBar object. ACToolBarLight uses a light theme and ACToolBarDark uses a dark theme by default. This is only for historical reasons. You can set the light or dark theme for the ToolBar and the overflow menu with the designer properties now.

Now we add a Panel named pContent to the Layout with the following properties:

Layout_pContent.png


Because the standard height of the ToolBar/ActionBar in Material Design depends on the device orientation and screen size we add a small designer script:
B4X:
If ActivitySize > 6.5 Then
  ActionBar.Height = 64dip
Else
  If Portrait Then
    ActionBar.Height = 56dip
  Else
    ActionBar.Height = 48dip
  End If
End If

pContent.SetTopAndBottom(ActionBar.Bottom, 100%y)
This will set the ActionBar height to 64dip on tablets and to 56dip on portrait phones and 48dip on landscape phones. These specifications are in the Material Design guide.

Now we have a minimal example of how to setup a ToolBar as an ActionBar.

ToolBar_Shadow.png


Misc stuff

You can use the ACActionBar object to control some ActionBar features like showing the "Up" indicator arrow.

B4X:
Dim ABHelper as ACActionBar

ABHelper.ShowUpIndicator = True

Adding actions and overflow menu

You can use the normal Activity.AddMenuItem() methods to add a menu or actions to the ToolBar:

B4X:
Dim xml As XmlLayoutBuilder
Dim bd As BitmapDrawable
bd = xml.GetDrawable("ic_plus_one_black_24dp")
Activity.AddMenuItem3("Plus one", "Menu", bd.Bitmap, True)
bd = xml.GetDrawable("ic_refresh_black_24dp")
Activity.AddMenuItem3("Refresh", "Menu", bd.Bitmap, True)
Activity.AddMenuItem("Overflow1", "Menu")
Activity.AddMenuItem("Overflow2", "Menu")
Activity.AddMenuItem("Overflow3", "Menu")

I prefer to use drawables for action icons than use the LoadBitMap() function. The drawables are available in different resolutions and will always load in the perfect size for your device. To load drawables you will have to use the XmlLayoutBuilder library.

The attached example has some UI elements to control some features of the ToolBar. Have fun with it.

ExampleApp.png
 

Attachments

  • ACToolBarExample2_0.zip
    25.3 KB · Views: 3,887
Last edited:

Inman

Well-Known Member
Licensed User
Longtime User
When you find time, please work on a transparent toolbar. Google uses it in their Play Store app (screenshot on the right side).

Play-Store-with-Material-Design-UI-2.jpg
 

shashkiranr

Active Member
Licensed User
Longtime User
Can you attach the code of your addcreditcard Activity?

Hi Corwin,

PFB the activity code

B4X:
#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: False
#End Region

#Extends: android.support.v7.app.ActionBarActivity

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
   
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim Basescv As ScrollView
    Private SaveButton As Button
    Private CPanel As Panel
    Private EditText1 As EditText
    Private EditText2 As EditText
    Private EditText3 As EditText
   
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Basescv.Initialize(Activity.Height)
    Activity.AddView(Basescv,0,0,100%x,100%y)
    Basescv.Panel.LoadLayout("CardLayout")
    Basescv.Panel.Height = SaveButton.Top+SaveButton.Height
    Log(Basescv.Panel.Height)
    Log(Basescv.Height)
    If Basescv.Panel.Height < Activity.Height Then
        Basescv.Panel.Height = Activity.Height
    Else If Basescv.Panel.Height > Basescv.Height Then
        CPanel.Height = SaveButton.Top+SaveButton.Height
    End If
   
    EditText2.InputType = EditText2.INPUT_TYPE_NUMBERS
    EditText3.InputType = EditText3.INPUT_TYPE_NUMBERS
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub dummy
End Sub


Sub SaveButton_Click
    Dim sb As StringBuilder
    sb.Initialize
    sb.Append("Bank :").Append(EditText1.Text).Append("Cardnumber :").Append(EditText2.Text).Append("cvv :").Append(EditText3.Text)
    Log(sb.ToString)
   
   
   
End Sub
 

corwin42

Expert
Licensed User
Longtime User
Hi Corwin,

PFB the activity code
I think the problem is that you set #IncludeTitle: false
This may not work correctly with AppCompat. If you want to disable the title do it in the theme like in the example project.
 

corwin42

Expert
Licensed User
Longtime User
When you find time, please work on a transparent toolbar. Google uses it in their Play Store app (screenshot on the right side).
Have you tried to make the ToolBar background transparent?
 

koaunglay

Member
Licensed User
Longtime User
Google recommends to use a ToolBar instead of the standard system ActionBar for Material Design apps. In this tutorial we will use a ACToolBar(Light/Dark) object from the AppCompat library (1.10 and above) as an ActionBar.

One of the main differences between a ToolBar and the standard ActionBar is that the ActionBar is a system component which is automatically added by the os and a ToolBar is part of our layout so we can add it to the activity with the designer or by code.

Using the ToolBar object

The best approach to learn how to use the ToolBar is by an example. So we create a new project and set it up very similar to the project from the Material Design 2 tutorial. Here we go with a quick setup:
Add the following code to your activity to add additional ressources and extend the ActionBarActivity:
B4X:
#AdditionalRes : ..\resource
#AdditionalRes : <Path to appcompat custom libs res>\b4a_appcompat, de.amberhome.objects.appcompat
#AdditionalRes : <Path to Android sdk>\android-sdk\extras\android\support\v7\appcompat\res, android.support.v7.appcompat
#Extends : android.support.v7.app.ActionBarActivity

Change the following line in the manifest editor to use our custom theme:
B4X:
SetApplicationAttribute(android:theme, "@style/MyAppTheme")

We need to create our own theme file. So add the theme.xml file to the resource\values folder:
B4X:
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <style name="MyAppTheme" parent="Theme.AppCompat.Light">
  <item name="colorPrimary">#FF9800</item>
  <item name="colorPrimaryDark">#F57C00</item>
  <item name="colorAccent">#FFA726</item>
  <item name="android:windowNoTitle">true</item>
  <item name="windowActionBar">false</item>
  </style>
</resources>

Because we want to use a ToolBar instead of the normal system ActionBar we have to disable the ActionBar in our theme. This is done with
B4X:
<item name="android:windowNoTitle">true</item>
<item name="windowActionBar">false</item>
Just setting the #IncludeTitle attribute to false does not work here and will produce an error. So we need the two lines in our theme.

Now we can create our layout. For the example project I decided to split the layout into two parts. One "main" layout which contains the ToolBar and a simple Panel for the content.
So add a CustomView of type "ACToolBarLight" to a new layout called "main" and set the following properties:

View attachment 30934

There are two versions of the ToolBar. ACToolBarLight uses a light theme and ACToolBarDark uses a dark theme. Two objects are needed because for designer CustomViews you can't set any initialization parameters and the theme of the ToolBar can't be changed at runtime. It is possible to create a ToolBar by code, too. Be aware that the new layout animation feature of B4A 4.0 and above does not affect any ToolBar.
The theme for the overflow menu can be set at runtime with the ACToolBarLight.PopupTheme property.

Then add a Panel named pContent with the following properties:

View attachment 30935

Because the standard height of the ToolBar/ActionBar in Material Design depends on the device orientation and screen size we add a small designer script:
B4X:
If ActivitySize > 6.5 Then
  ActionBar.Height = 64dip
Else
  If Portrait Then
    ActionBar.Height = 56dip
  Else
    ActionBar.Height = 48dip
  End If
End If

pContent.SetTopAndBottom(ActionBar.Bottom, 100%y)
This will set the ActionBar height to 64dip on tablets and to 56dip on portrait phones and 48dip on landscape phones. These specifications are in the Material Design guide.

Now we can load our layout to the activity and can set up the ToolBar. There are two possibilities to use ToolBars. As standalone objects or as the system ActionBar. You can only set up one ToolBar as an ActionBar but you can place the ToolBar anywhere on the activity.

B4X:
Activity.LoadLayout("main")

'Set the ToolBar (it is called ActionBar in the layout file) as the ActionBar of this activity.
ActionBar.SetAsActionBar

'Set Title and Subtitle for the ToolBar
ActionBar.Title = "AppCompat"
ActionBar.SubTitle = "ToolBar Example 1"

So now we have a minimal example of how to setup a ToolBar as an ActionBar.

Adding a shadow

The ToolBar looks nice but the standard ActionBar had a small shadow so it looks like it is floating above the activity. The ToolBar by default don't have this shadow. In the Material Design guidelines it is not really clear if a ToolBar should have a shadow or not. Some of the Google apps have the shadow, others not. The AppCompat wrapper library contains a method to set the elevation of every view so we set a small elevation of 8dip to our ToolBar to get a nice shadow:

B4X:
Dim AC As AppCompat

AC.SetElevation(ActionBar, 8dip)

The AppCompat.SetElevation() method can set the elevation of every view. Try it with normal Panels for example. Unfortunately the shadow will only show on Android 5.0 or above.

View attachment 30936

Misc stuff

You can use the ACActionBar object to control some ActionBar features like showing the "Up" indicator arrow.

B4X:
Dim ABHelper as ACActionBar

ABHelper.ShowUpIndicator = True

Adding actions and overflow menu

You can use the normal Activity.AddMenuItem() methods to add a menu or actions to the ToolBar.
If you want to add actions you need some icons. Google released a huge set of Material Design icons wich can be used as action icons. Unfortunately these icons are packed in a bad directory structure which makes it hard to pick a single icon and use it as drawables for the actions. So I wrote a small tool that reorganizes the icons in a better directory structure.

Ok, if we picked some icons and copied their drawable folders to our resources folder we can start to add some actions and overflow menu items:

B4X:
Dim xml As XmlLayoutBuilder
Dim bd As BitmapDrawable
bd = xml.GetDrawable("ic_plus_one_black_24dp")
Activity.AddMenuItem3("Plus one", "Menu", bd.Bitmap, True)
bd = xml.GetDrawable("ic_refresh_black_24dp")
Activity.AddMenuItem3("Refresh", "Menu", bd.Bitmap, True)
Activity.AddMenuItem("Overflow1", "Menu")
Activity.AddMenuItem("Overflow2", "Menu")
Activity.AddMenuItem("Overflow3", "Menu")

I prefer to use drawables for action icons than use the LoadBitMap() function. The drawables are available in different resolutions and will always load in the perfect size for your device. To load drawables you will have to use the XmlLayoutBuilder library.

The attached example has some UI elements to control some features of the ToolBar. Have fun with it.

View attachment 30937

I like so much. But I have some error. please help what is my error?
B4X:
B4A version 4.30
Parsing code.  0.10
Compiling code.  0.30
Compiling layouts code.  0.05
Generating R file.  Error
..\resource\values\themes.xml:6: error: Error: No resource found that matches the given name: attr 'colorAccent'.
..\resource\values\themes.xml:4: error: Error: No resource found that matches the given name: attr 'colorPrimary'.
..\resource\values\themes.xml:5: error: Error: No resource found that matches the given name: attr 'colorPrimaryDark'.
 

gyruss68

Member
Licensed User
Longtime User
Hi Corvin,
i have downloaded your example and compile it.
When i try to execute and debug it , it's stop on emulation.

What's are the problem ?

Thenk's
Franco

The line on IDE is :
Activity.LoadLayout("main")

The declaration is :
#AdditionalRes: ..\resource
#AdditionalRes: C:\Users\Rataplan\Desktop\AppCompatToolbarMenuExample\b4a_appcompat, de.amberhome.objects.appcompat
#AdditionalRes: C:\Android\android-sdk\extras\android\support\v7\appcompat\res, android.support.v7.appcompat
#Extends: android.support.v7.app.ActionBarActivity



The error is :
** Activity (main) Create, isFirst = true **


java.lang.RuntimeException: java.lang.reflect.InvocationTargetException


at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:166)
at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:208)
at de.amberhome.appcompat.toolbarexample1.main._activity_create(main.java:353)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at de.amberhome.appcompat.toolbarexample1.main.afterFirstLayout(main.java:100)
at de.amberhome.appcompat.toolbarexample1.main.access$100(main.java:17)
at de.amberhome.appcompat.toolbarexample1.main$WaitForLayout.run(main.java:78)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)


at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.objects.CustomViewWrapper.AfterDesignerScript(CustomViewWrapper.java:54)
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:158)
... 17 more
Caused by: java.lang.NoSuchMethodError: android.support.v4.content.ContextCompat.getDrawable
at android.support.v7.internal.widget.TintManager.getDrawable(TintManager.java:133)
at android.support.v7.internal.widget.TintTypedArray.getDrawable(TintTypedArray.java:62)
at android.support.v7.widget.Toolbar.<init>(Toolbar.java:249)
 

corwin42

Expert
Licensed User
Longtime User
Caused by: java.lang.NoSuchMethodError: android.support.v4.content.ContextCompat.getDrawable
at android.support.v7.internal.widget.TintManager.getDrawable(TintManager.java:133)
at android.support.v7.internal.widget.TintTypedArray.getDrawable(TintTypedArray.java:62)
at android.support.v7.widget.Toolbar.<init>(Toolbar.java:249)
Seems that you have not copied the latest android-support-v4.jar to your custom libs folder.
 

gyruss68

Member
Licensed User
Longtime User
Seems that you have not copied the latest android-support-v4.jar to your custom libs folder.
Thank's Corvin,
I solved.
The problem was that the IDE B4a, even though I had set the path to the custom lib, sought the lib folder libraries of program files.
I copied the two libraries and it worked.

Franco
 

Inman

Well-Known Member
Licensed User
Longtime User
I am adding views to toolbar using actionbar.addview() instead of Activity.AddMenuItem3() as I need to toggle the visibility of certain contents based on the content of that activity. While views get added correctly, I can't find a way to space them correctly, even with gravity. If I use left or center for gravity, the icon is very near to actionbar title text. If I use right for gravity, the icon is at the very right edge of the actionbar. I would like to leave some space from the right edge, sort of like how much space you get on the left edge when you set the ABHelper.ShowUpIndicator.

Is it possible?
 

RandomCoder

Well-Known Member
Licensed User
Longtime User

corwin42

Expert
Licensed User
Longtime User
I am adding views to toolbar using actionbar.addview() instead of Activity.AddMenuItem3() as I need to toggle the visibility of certain contents based on the content of that activity. While views get added correctly, I can't find a way to space them correctly, even with gravity. If I use left or center for gravity, the icon is very near to actionbar title text. If I use right for gravity, the icon is at the very right edge of the actionbar. I would like to leave some space from the right edge, sort of like how much space you get on the left edge when you set the ABHelper.ShowUpIndicator.

Is it possible?

Can you show an example what the problem looks like?

Please advise how I should add tabs in the Toolbar? I read in the Appcompat library thread that NavigationMode is deprciated... AppCompat - Make Material Design apps compatible with older Android versions
The material design guidelines still shows Tabs being used within the toolbar though http://www.google.com/design/spec/components/tabs.html#
Or is the idea just to sit a TabBar directly under the Toolbar?

Advice or a sample would be greatly appreciated :D

Yes, just add a TabBar directly under the Toolbar.
 

Inman

Well-Known Member
Licensed User
Longtime User
Can you show an example what the problem looks like?

lNrORfY.png


The above is the result of this code
B4X:
    pb.Initialize("")
    pb.Indeterminate=True
    actionbar.AddView(pb,24dip,24dip,Gravity.left)

imgabshare.Initialize("imgabshare")
    imgabshare.Gravity=Gravity.FILL
    imgabshare.Bitmap=LoadBitmap(File.DirAssets,"ic_share_white_24dp.png")
    actionbar.AddView(imgabshare,24dip,24dip,Gravity.RIGHT)

As you can see, the share icon is on the extreme right and progressbar are very close to title. I would like to add some padding for them, from their neighbor/edge.

Compare that to how it looks on Google Drive app

OG06aZO.png
 

Inman

Well-Known Member
Licensed User
Longtime User
Here is another issue I am having with Toolbar

After adding the toolbar, I add a panel to the activity. This panel is nearly full-size width and height is therefore supposed to be on top of toolbar as well (it is used as a popup). On Android 5.0 device, the top portion of the panel is behind the toolbar and is therefore cut-off. But on Android 4.x versions it works as intended.

I tried with and without toolbar.SetAsActionBar but that doesn't seem to have any effect. Any idea?
 

corwin42

Expert
Licensed User
Longtime User
As you can see, the share icon is on the extreme right and progressbar are very close to title. I would like to add some padding for them, from their neighbor/edge.

Adding Views to a Toolbar should mainly be used for custom views as a replacement for the title. Action items should be added as menu items.

After adding the toolbar, I add a panel to the activity. This panel is nearly full-size width and height is therefore supposed to be on top of toolbar as well (it is used as a popup). On Android 5.0 device, the top portion of the panel is behind the toolbar and is therefore cut-off. But on Android 4.x versions it works as intended.

I can only guess what happens here. Do you set an elevation value for the ToolBar?
If yes, thats the problem here. In Android 5.0 Google introduced the elevation value for views. With this value you can control the depth order of views. So views with higher elevation will always display in front of views with lower elevation. Try to set a higher elevation for the panel than for the ToolBar and it should display in front of it.
 

Inman

Well-Known Member
Licensed User
Longtime User
Adding Views to a Toolbar should mainly be used for custom views as a replacement for the title. Action items should be added as menu items.

But if I add action items as menu items, will I be able to selectively show/hide it when needed? I have your ViewPager in the Activity and when the user swipes to different pages, I need to show and hide certain items on toolbar based on the CurrentPage.

I can only guess what happens here. Do you set an elevation value for the ToolBar?
If yes, thats the problem here. In Android 5.0 Google introduced the elevation value for views. With this value you can control the depth order of views. So views with higher elevation will always display in front of views with lower elevation. Try to set a higher elevation for the panel than for the ToolBar and it should display in front of it.

You are absolutely correct. I had elevation for toolbar as mentioned in your tutorial for shadow effect. Now I set a higher elevation for the panel and it worked. Thank you so much for this wonderful library.
 

migrec

Member
Licensed User
Longtime User
what is the "click event" for the "up" indicator?
like:
B4X:
ABHelper.ShowUpIndicator = True
 
Top