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:

corwin42

Expert
Licensed User
Longtime User
Thanks corwin42. That is a LOT of work you had to go through to get the app material ready.

I think it is not that much. You have to set up a theme, set some attributes and use the theme in the manifest editor. That is the main setup for Material design.
Everything else are addons or things you have to do with "normal" apps, too. You can still use the standard ActionBar with AppCompat but a ToolBar has some more features. For example you can place it everywhere you want and (upcoming in next tutorial) you can modify the menu at runtime.
 

Douglas Farias

Expert
Licensed User
Longtime User
very nice man thank you for the tutorial
 

johndb

Active Member
Licensed User
Longtime User
This tutorial is excellent and your work, corwin42, is very much appreciated.
I did notice that the shadow doesn't show on kitkat 4.4.2 or have I missed something?
 

corwin42

Expert
Licensed User
Longtime User
This tutorial is excellent and your work, corwin42, is very much appreciated.
I did notice that the shadow doesn't show on kitkat 4.4.2 or have I missed something?
Yes, as I said in the tutorial, setElevation only shows a shadow on Android 5.0 and above.
 

nadhiras

Member
Licensed User
Longtime User
Hi,
Is it possible to use this toolbar for 2 or more activities ??
because when i use two activities other activities (not Main Activities) can't set this tollbar as actionbar.

its cannot handle "windowActionModeOverlay" at 2nd activies
 

corwin42

Expert
Licensed User
Longtime User
Hi,
Is it possible to use this toolbar for 2 or more activities ??
because when i use two activities other activities (not Main Activities) can't set this tollbar as actionbar.

its cannot handle "windowActionModeOverlay" at 2nd activies
It should work.

What error do you get?
 

nadhiras

Member
Licensed User
Longtime User
if i set toolbar.setasactionbar on 2nd activity i;ve got error like this:

B4X:
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
Menu ready to go!
Unexpected event (missing RaiseSynchronousEvents): cbitemvisible_checkedchange
Check the unfiltered logs for the full stack trace.
** Activity (main) Pause, UserClosed = false **
** Activity (two) Create, isFirst = true **
Error occurred on line: 24 (two)
java.lang.ClassCastException: de.amberhome.appcompat.toolbarmenuexample.two cannot be cast to android.support.v7.app.ActionBarActivity
   at de.amberhome.objects.appcompat.ACToolBarWrapper.SetAsActionBar(ACToolBarWrapper.java:244)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:680)
   at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:308)
   at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:121)
   at de.amberhome.appcompat.toolbarmenuexample.two.afterFirstLayout(two.java:98)
   at de.amberhome.appcompat.toolbarmenuexample.two.access$100(two.java:16)
   at de.amberhome.appcompat.toolbarmenuexample.two$WaitForLayout.run(two.java:76)
   at android.os.Handler.handleCallback(Handler.java:733)
   at android.os.Handler.dispatchMessage(Handler.java:95)
   at android.os.Looper.loop(Looper.java:136)
   at android.app.ActivityThread.main(ActivityThread.java:5001)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:515)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
   at dalvik.system.NativeStart.main(Native Method)
** Activity (two) Resume **

but if not set toolbar.setasactionbar on 2nd activity ive got like this :
b4a.png

"windowActionModeOverlay" dont work on 2nd activity. and look like L theme not working.. look at the checklist still black not like on main activity
 

corwin42

Expert
Licensed User
Longtime User
if i set toolbar.setasactionbar on 2nd activity i;ve got error like this:

Your second Activity is not extended from
android.support.v7.app.ActionBarActivity.

All activities that use any AppCompat features have to extend ActionBarActivity so add the following to your second Activity:

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

nadhiras

Member
Licensed User
Longtime User
Your second Activity is not extended from
android.support.v7.app.ActionBarActivity.

All activities that use any AppCompat features have to extend ActionBarActivity so add the following to your second Activity:

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


It Works!...
Thanks Again Corwin...
 

TheSketchees

Member
Licensed User
Longtime User
For some reason #AdditionalRes: ..\resource doesnt exist accoring to the builder. If i remove this it will just freeze on startup??
 

TheSketchees

Member
Licensed User
Longtime User
You need to make sure that you actually have a folder called resources in your root directory...
Yeah i have its working now. But still freezes at startup with no error in the logs :/ I have all files, themes. Don't know why its not working
 
Last edited:

shashkiranr

Active Member
Licensed User
Longtime User
Hi Corwin,

Somtimes i get the requestfeature error. See below.

B4X:
ActionBar Height: 56


** Activity (test) Resume **


Drawer Opened:


Drawer Closed:


MenuItem Overflow1 selected


MenuItem Refresh selected


MenuItem Plus one selected


** Activity (test) Pause, UserClosed = false **


java.lang.RuntimeException: Unable to start activity ComponentInfo{de.amberhome.appcompat.toolbarexample1/de.amberhome.appcompat.toolbarexample1.addcreditcard}: android.util.AndroidRuntimeException: requestFeature() must be called before adding content


    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2413)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2471)
    at android.app.ActivityThread.access$900(ActivityThread.java:175)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1308)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:146)
    at android.app.ActivityThread.main(ActivityThread.java:5602)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: android.util.AndroidRuntimeException: requestFeature() must be called before adding content
    at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:325)
    at de.amberhome.appcompat.toolbarexample1.addcreditcard.onCreate(addcreditcard.java:50)
    at android.app.Activity.performCreate(Activity.java:5451)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2377)
    ... 11 more

Regards,
SK
 
Top