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,899
Last edited:

Homerclese

Member
Licensed User
Longtime User
This is a great toolbar, thank you corwin42! Is there a way to overlay a search field in the toolbar when the user taps a search button, as the Gmail and Google Contacts apps do?
 

divinglog

Member
Licensed User
Longtime User
This is a great toolbar, thank you corwin42! Is there a way to overlay a search field in the toolbar when the user taps a search button, as the Gmail and Google Contacts apps do?
Yes, you have to place a panel with a TextView and a ImageView (as back button) on top of the toolbar and toogle the visibility.

01.png 02.png
 
Last edited:

Homerclese

Member
Licensed User
Longtime User
Yes, you have to place a panel with a TextView and a ImageView (as back button) on top of the toolbar and toogle the visibility.

Thanks! I thought there might be some intrinsic/native way to handle this, but, other than the underscore, this looks pretty close to Google's Material apps.
 

corwin42

Expert
Licensed User
Longtime User
Thanks! I thought there might be some intrinsic/native way to handle this, but, other than the underscore, this looks pretty close to Google's Material apps.

There is a native way. See the SearchView example in the AppCompat library thread. Maybe that the example is a bit outdated (I'm currently working on a new version of AppCompat and then I will update the examples).
 

Homerclese

Member
Licensed User
Longtime User
Is there a way to make the Toolbar.Title a dropdown menu, as in the Google Calendar app where the month name, which appears in the Title position, can be tapped to drop down a menu? I know you can add a menu to the Toolbar but I am specifically wanting to make the Title into a menu. For example the "All" title, below, has a drop-down:

TitleMenu.png
 
Last edited:

corwin42

Expert
Licensed User
Longtime User
Is there a way to make the Toolbar.Title a dropdown menu, as in the Google Calendar app where the month name, which appears in the Title position, can be tapped to drop down a menu? I know you can add a menu to the Toolbar but I am specifically wanting to make the Title into a menu. For example the "All" title, below, has a drop-down

Yes. You can add a Spinner to the Toolbar. Unfortunately the spinner theme is not inherited from the ToolBar theme in this case so the small triangle will probably display in the wrong color.

Edit: The next version of AppCompat will suport it better. I just added a Initialize2() method to ACSpinner which has a second parameter "Theme". So you can specify if the Spinner should appear in dark or light theme.
 
Last edited:

Anser

Well-Known Member
Licensed User
Longtime User
Hi,

In my app, on the ToolBar, the navigation via ShowUpIndicator ie the Arrow used to go back to the previous activity works only if I use Activity.LoadLayout. If I create an activity via code then the the navigation using the ShowUpIndicator is not working. Am I missing anything ?

Here is the code that I use ie (Activity,Toolbar etc created via code)

B4X:
#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region
#Extends: android.support.v7.app.AppCompatActivity

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.

    Private ActionBar As ACToolBarDark
    Dim AC As AppCompat
    Dim ABHelper As ACActionBar

End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")

    Activity.Color=Colors.RGB(228,228,228)
    ActionBar.Initialize("ActionBar")
    Activity.AddView(ActionBar,0,0,100%x,56dip)

    ActionBar.SetAsActionBar  
    ActionBar.Title = "My Title"

    ' Set the Toolbar Shadow
    AC.SetElevation(ActionBar, 8dip)

    ABHelper.Initialize
    ABHelper.ShowUpIndicator = True
    ActionBar.InitMenuListener 'Back arrow menu button on the left side of the Toolbar is not working

End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub ActionBar_NavigationItemClick
    Activity.Finish
End Sub

With the same code, Instead of creating the Activity by code, If I use designer and use Actrivity.LoadLayout("LayoutFile") then it is working fine.
Code used when using Activity.LaodLAyout
B4X:
#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region
#Extends: android.support.v7.app.AppCompatActivity

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.

    Private ActionBar As ACToolBarDark
    Dim AC As AppCompat
    Dim ABHelper As ACActionBar

End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("WebView")

    'Set the ToolBar (it is called ActionBar in the layout file) as the ActionBar of this activity.
    ActionBar.SetAsActionBar
    ActionBar.Title = "My Title"
    AC.SetElevation(ActionBar, 8dip)
  
    ABHelper.Initialize
    ABHelper.ShowUpIndicator = True
    ActionBar.InitMenuListener 'If this is not added then the Back button on the left side of the Toolbar is not working  

    WebView1.LoadUrl("http://www.google.com")
    WebView1.ZoomEnabled = False

End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub ActionBar_NavigationItemClick
    Activity.Finish
End Sub

Is there anything that I am missing in the code to make it working when Activity is created using code.

Regards
Anser
 
Last edited:

Anser

Well-Known Member
Licensed User
Longtime User
B4X:
  ActionBar.Initialize("ActionBar")
    Activity.AddView(ActionBar,0,0,100%x,56dip)
is missing in the second code.
The second code is using Designer and it is working fine. The problem is in the first code. I have problem only when the activity and actionbar etc created via code
 

corwin42

Expert
Licensed User
Longtime User
The proper way to add custom views is with the designer.

But it should work with adding the View by code (the ToolBar is designed for it). I will have a look on it.

In the past there was another strange effect that the Elevation did not work for the ToolBar if it was added by code. I don't know if it is still a problem.
Sometimes there are bugs in the support libraries, too and then you don't know if you have done something wrong in the wrapper.
 

JohnC

Expert
Licensed User
Longtime User
I am running into a weird problem.

I am using the light material theme:

B4X:
SetApplicationAttribute(android:theme, "@style/MyAppTheme")
CreateResource(values, theme.xml,
<resources>
    <style name="MyAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">#0098FF</item>
        <item name="colorPrimaryDark">#007CF5</item>
        <item name="colorAccent">#00AAAA</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>
</resources>)

And as you can see, the app title is in white:

blackdots.png


But you can also see that the menu/overflow dots are in black.

And if I click the 3 dots/menu, the menu background is properly a light/white background:

whitemenu.png


If I instead change the theme to dark, then the menu dots will be white, but the menu background will then be black, which I don't want.

How can I get the menu dots to be white and the menu background to also be light/white?
 

corwin42

Expert
Licensed User
Longtime User
What you want is a light theme with a dark toolbar.

Do the following:

  1. Use Theme.AppCompat.Light.DarkActionBar as your parent theme. You don't need to use a NoActionBar theme because this is done with the windowActionBar:false item.
  2. Use ACToolBarDark as your Toolbar
  3. Set your Toolbar.PopupTheme to Light.
If you use the designer to add your Toolbar (the recommended method now) then it doesn't matter if you use a light or dark toolbar. You can set the Toolbar Theme and Popup Theme in the designer properties.
 

Anser

Well-Known Member
Licensed User
Longtime User
If you use the designer to add your Toolbar (the recommended method now) then it doesn't matter if you use a light or dark toolbar. You can set the Toolbar Theme and Popup Theme in the designer properties.

The question is asked just to clear the ambiguity and to make it more clearer

Based on the previous B4A versions and the earlier versions of AppCompat examples, I am maintaining a resource folder inside my Project Folder. Inside the resource folder there is a file named themes.xml ie \Projects\resource\values\themes.xml
It is here in this themes.xml file that I am mentioning the color themes applicable to my App

B4X:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">#418BEA</item>
        <item name="colorPrimaryDark">#2C7FE8</item>
        <item name="colorAccent">#5698EC</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>
</resources>

And in the Manifest I add the below given entry.
B4X:
'Manifest Entry for AppCompat Theme available in resource\values\theme.xml as read only
SetApplicationAttribute(android:theme, "@style/MyAppTheme")
'End of lines required for AppCompat

The question is asked just to clear the ambiguity and to make it more clearer.

To use AppCompat in my app, do I still need all the above ie the Manifest entry and the resource folder ? With B4A 6 and the latest version of AppCompat, can I choose
  • The Color (backcolor) applicable for the Toolbar,
  • The color of the Text on the ToolBar ie the Title and SubTitle,
  • The background color of the PopUp menu on the ToolBar ie whether it should be white OR DarkGrey etc
  • The Text color of the PopupMenu on the ToolBar
from the Designer itself ?

If the above is possible then I believe that I can have different colors for the ToolBar in different activities in the same App.

Regards

Anser
 
Last edited:

Haris Hafeez

Active Member
Licensed User
Longtime User
Hello All,
[RESOLVED] - I just created a new layout that is exactly the same as the one I was using previously and the problem has gone away! I am not a fan of magic happening while developing but I'll accept it over frustrating NPEs.

After updating the Android SDK, I am struggling to a previously working app to work. The app crashes upon launch with the following stacktrace:
** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
main_activity_create (java line: 548)
java.lang.RuntimeException: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:166)
at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:209)
at com.impactmotor.app.main._activity_create(main.java:548)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
at com.impactmotor.app.main.afterFirstLayout(main.java:102)
at com.impactmotor.app.main.access$000(main.java:17)
at com.impactmotor.app.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Object.equals(java.lang.Object)' on a null object reference
at de.amberhome.objects.appcompat.ACToolBarWrapper.DesignerCreateView(ACToolBarWrapper.java:74)
at anywheresoftware.b4a.objects.CustomViewWrapper.AfterDesignerScript(CustomViewWrapper.java:70)
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:158)
... 16 more
** Service (starter) Create **
** Service (starter) Start **
** Service (firebasemessaging) Create **
** Service (firebasemessaging) Start **

Unfortunately, I cannot identify which part is causing this, only that I can see that the app crashes straight after trying to load the main layout that contains ACToolbarDark. This is the same layout as in the example, the one that contains the toolbar custom view and a panel. Any ideas why this might be causing it?

I have tried extending the activity using both ActionBarActivity and AppCompatActivity with the same result.

The SDK details are:
upload_2016-7-17_16-6-39.png


upload_2016-7-17_16-7-47.png
 
Last edited:

corwin42

Expert
Licensed User
Longtime User
The question is asked just to clear the ambiguity and to make it more clearer

Based on the previous B4A versions and the earlier versions of AppCompat examples, I am maintaining a resource folder inside my Project Folder. Inside the resource folder there is a file named themes.xml ie \Projects\resource\values\themes.xml
It is here in this themes.xml file that I am mentioning the color themes applicable to my App

B4X:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">#418BEA</item>
        <item name="colorPrimaryDark">#2C7FE8</item>
        <item name="colorAccent">#5698EC</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>
</resources>

And in the Manifest I add the below given entry.
B4X:
'Manifest Entry for AppCompat Theme available in resource\values\theme.xml as read only
SetApplicationAttribute(android:theme, "@style/MyAppTheme")
'End of lines required for AppCompat

The question is asked just to clear the ambiguity and to make it more clearer.

To use AppCompat in my app, do I still need all the above ie the Manifest entry and the resource folder ?
Short answer: Yes.

Long answer: The only thing you ever needed to do is to extend your activities from AppCompatActivity and set a AppCompat theme in the manifest editor.

The additional theme was only necessary to set the primary, primaryDark and accent colors. And if you use a ToolBar it is better to use a Theme which includes an ActionBar and then disable it in the theme.

With B4A 6 and the latest version of AppCompat, can I choose
  • The Color (backcolor) applicable for the Toolbar,
  • The color of the Text on the ToolBar ie the Title and SubTitle,
  • The background color of the PopUp menu on the ToolBar ie whether it should be white OR DarkGrey etc
  • The Text color of the PopupMenu on the ToolBar
from the Designer itself ?

If the above is possible then I believe that I can have different colors for the ToolBar in different activities in the same App.

All the above settings were possible in the previous version, too. Even different colors for the ToolBar was (and is) still possible with different themes for different Activites. Just set individual themes for your activities in the manifest editor.
 

corwin42

Expert
Licensed User
Longtime User
Hello All,
[RESOLVED] - I just created a new layout that is exactly the same as the one I was using previously and the problem has gone away! I am not a fan of magic happening while developing but I'll accept it over frustrating NPEs.

The answer is simple. It would have been enough to just enter the designer and save your layouts.

The problem was that the new library is trying to access the new custom designer properties. These properties are missing in the old designer files and this is the cause for the NullPointerExceptions. Just saving the layout again will include the properties in the layout files an everything will be fine.
 
Top