Android Tutorial Material Design 4 - Modifyable and advanced Menu

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

With the ACToolBar(Light|Dark) object we can get access to the Menu object of the activity. This opens the possibility for modifyable menus and some other advanced menu features.

Basics

With the ToolBar.Menu property we have access to the menu of the ToolBar. For a standalone ToolBar (which is not set as the activity ActionBar) we can just access the property everywhere in our code and do what we want to do with it just like adding/removing menu items.

If the ToolBar is our activities ActionBar we have to handle the menu in a special way because if we don't do this, B4As own menu handling will conflict with our handling.

In Android the menu is created and initalized with two methods: onCreateOptionsMenu() and onPrepareOptionsMenu(). I don't want to explain the whole menu system here you just need to know, that B4A uses these methods internally to create it's own menu and they get called "at some time" in the activity initialization process.

With the itroduction of inline Java code in B4A 4.30 we now have the possibility to add our own code to handle the application menu. The idea is to call an event to set up the menu and here is an example how this can be done:

B4X:
#If Java

public boolean _onCreateOptionsMenu(android.view.Menu menu) {
    if (processBA.subExists("activity_createmenu")) {
        processBA.raiseEvent2(null, true, "activity_createmenu", false, new de.amberhome.objects.appcompat.ACMenuWrapper(menu));
        return true;
    }
    else
        return false;
}
#End If

In this code we use the _onCreateOptionsMenu hook to check if a Sub named "Activity_CreateMenu" exists. If yes, then we call it and we provide the activities menu as a parameter. If the sub does not exist, the normal B4A menu-handling is done.

Now we need the implementation of Activity_CreateMenu:

B4X:
Sub Activity_CreateMenu(Menu As ACMenu)
    Menu.Clear

    Dim item As ACMenuItem
    Menu.Add2(10, 1, "Plus one", xml.GetDrawable("ic_plus_one_black_24dp")).ShowAsAction = item.SHOW_AS_ACTION_IF_ROOM
    Menu.Add2(20, 2, "Refresh", xml.GetDrawable("ic_refresh_black_24dp")).ShowAsAction = item.SHOW_AS_ACTION_ALWAYS

    Menu.Add(1, 3, "Overflow1", Null)
    Menu.Add(2, 4, "Overflow2", Null)
    Menu.Add(3, 5, "Overflow3", Null)

    'Sync Checkboxes with the Menu
    SetCheckBoxState(Menu)

End Sub
First we clear the menu to be sure that there are no old entries in it. Then we just use the Menu object to add some additional menus. Easy, isn't it? (For this example we sync the menu with the checkboxes with SetCheckBoxState())

It is good practice to use a Toolbar as your ActionBar. If you do this you can access the menu with ToolBar.Menu everywhere in your code to modify the menu.

Some advanced menu features

With the ACMenu and ACMenuItem objects we have access to some advanced menu features.

When you add a menu item to the menu you can specify a menu ID and a sort order. So with the sort order you can later add menu entries which are displayed above other menu items. With the ID you can access this item later and modify it.

You can create checkable menu itemes. The ACMenu.Add() methods return the added menu item so you can directly modify it and make it checkable or set it as an action item or even make it invisible.

It is even possible to add or remove menu items dynamically.

B4X:
Sub cbItemVisible_CheckedChange(Checked As Boolean)
  ToolBar.Menu.FindItem(1).Visible = Checked
End Sub

Sub cbItemCheckable_CheckedChange(Checked As Boolean)
  ToolBar.Menu.FindItem(2).Checkable = Checked
End Sub

Sub cbItemDisable_CheckedChange(Checked As Boolean)
  ToolBar.Menu.FindItem(3).Enabled = Not(Checked)
End Sub

Look at the example project for better understanding.

overflow_menu.png
 

Attachments

  • ToolBarMenuExample2_0.zip
    18.6 KB · Views: 4,162
Last edited:

corwin42

Expert
Licensed User
Longtime User
Is it possible to create a popup menu and display it when a button on the activity is pressed? And if possible display the menu on top of the button so that the context will be clear for the user.

This is exactly what the ACPopupMenu is for.
 

Firpas

Active Member
Licensed User
Longtime User
Hi again corwin42

Im trying to put a second toolbar in other activity but the line

ToolBar.SetAsActionBar

causes this error

** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (export) Create, isFirst = true **
export_activity_create (B4A line: 44)
ToolBar.SetAsActionBar
java.lang.ClassCastException: rutamovilplus.firpas.com.export cannot be cast to android.support.v7.app.ActionBarActivity
at de.amberhome.objects.appcompat.ACToolBarWrapper.SetAsActionBar(ACToolBarWrapper.java:244)
at rutamovilplus.firpas.com.export._activity_create(export.java:349)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
at rutamovilplus.firpas.com.export.afterFirstLayout(export.java:100)
at rutamovilplus.firpas.com.export.access$100(export.java:17)
at rutamovilplus.firpas.com.export$WaitForLayout.run(export.java:78)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
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:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)

This is my code

B4X:
#Region Activity Attributes
#FullScreen: False
#IncludeTitle: True
#End Región



If Java

public boolean _onCreateOptionsMenu(android.view.Menu menu) {
    if (processBA.subExists("activity_createmenu")) {
        processBA.raiseEvent2(null, true, "activity_createmenu", false, new de.amberhome.objects.appcompat.ACMenuWrapper(menu));
        return true;
    }
    else
        return false;
}
#End If

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim ExFormat(3) As String = Array As String("Kmz-Google Earth, Google Maps", "Gpx-Gps Exchange xml", "Plt, Wpt-OziExplorer", "Pdf-Adobe reader", "Json-RutaMovilPlus")
    Dim Pdf As cPdf
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 AC As AppCompat

    Private ToolBar As ACToolBarLight
    Private pContent As Panel
    Private xml As XmlLayoutBuilder
  
    Dim lv As ListView
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("export")
  
    ToolBar.SetAsActionBar
    'ToolBar.Title = "Ruta Movil Plus"
    ToolBar.TitleTextColor = Colors.White
    ToolBar.LogoBitmap = LoadBitmap(File.DirAssets, "logo150.png")
    ToolBar.NavigationIconDrawable = xml.GetDrawable("go_back")
    ToolBar.InitMenuListener
  
    AC.SetElevation(ToolBar, 4dip)
  
    lv.Initialize("lv")
    pContent.AddView(lv, 0, 0, pContent.Width, pContent.Height)
  
    lv.TwoLinesAndBitmap.Label.TextColor = Colors.RGB(0, 102, 51)
  
End Sub

Can you help me ??

Thanks in advance
 

Firpas

Active Member
Licensed User
Longtime User
Thanks for your response.

I've added this line but with the same error result.

Any idea ??
 

corwin42

Expert
Licensed User
Longtime User
Thanks for your response.

I've added this line but with the same error result.

Any idea ??

The ToolBar is in your layout?

Sorry but I never have seen this error so without an example project it is hard to help here.
 

Firpas

Active Member
Licensed User
Longtime User
Yes, the toolbar is in the layout and the layout is the same that your AppCompactExample.

Now i am trying to add a second activity in your example but i have another error message.

Here you have the code

Best regards
 

Attachments

  • AppCompactExample Second Activity.zip
    11.5 KB · Views: 613

corwin42

Expert
Licensed User
Longtime User
After I corrected all errors (Case errors in inline java code in second activity and correct name for StartActivity) it works here without problems.
 

Firpas

Active Member
Licensed User
Longtime User
Sorry my mistake.
I have corrected the error and now everything works fine.

Just one more question ...

I used "TitleTextColor" to change the color of the title, but ...

Is it possible to change the color of the icon indicated in the attached image?

Kind regards
 

Attachments

  • 1.png
    1.png
    9.8 KB · Views: 638

corwin42

Expert
Licensed User
Longtime User
There is no need to change the title color. Use a light or dark theme to change action item icon colors and overflow buttons color. Additionally you can choose between ToolbarLight and ToolBarDark for different a Theme for the ActionBar.
 

Firpas

Active Member
Licensed User
Longtime User
I can see the constnts THENE_DARK and THEME:LIGHT, but ...
what is the property or method?

Thanks?
 

corwin42

Expert
Licensed User
Longtime User
The constants are for the Popup Menu. There are two different Toolbars: ToolBarLight and ToolBarDark. If I remember correctly you have to use ToolBarDark for white icons.
 

fishwolf

Well-Known Member
Licensed User
Longtime User
Second activity example return this error

B4X:
B4A version: 5.50
Parsing code.    (0.00s)
Compiling code.    (0.08s)
Compiling layouts code.    (0.00s)
Generating R file.    (0.36s)
Compiling generated Java code.    Error
B4A line: 90
End Sub
javac 1.8.0
src\b4a\example\material7\second.java:489: error: <identifier> expected
Public boolean _onCreateOptionsMenu(android.view.Menu menu) {
      ^
1 error
 

fishwolf

Well-Known Member
Licensed User
Longtime User
Second activity example return this error

B4X:
B4A version: 5.50
Parsing code.    (0.00s)
Compiling code.    (0.08s)
Compiling layouts code.    (0.00s)
Generating R file.    (0.36s)
Compiling generated Java code.    Error
B4A line: 90
End Sub
javac 1.8.0
src\b4a\example\material7\second.java:489: error: <identifier> expected
Public boolean _onCreateOptionsMenu(android.view.Menu menu) {
      ^
1 error

Any suggest?
 

marcel

Active Member
Licensed User
Longtime User
Hi,

Thanks for this great support!! I am a beginner in this and I am using the AcToolbarDark. But now my overflow menu turns black on background. How can I change this?

I found the same issue here, but I do not understand to fix this in B4A.
http://stackoverflow.com/questions/25130418/styling-action-bar-overflow-menu-background-color

Try this but it does not work.Overflow menu has still a black background.

B4X:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">#8BC5EB</item>
        <item name="colorPrimaryDark">#2A90D3</item>
        <item name="colorAccent">#80D8FF</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="android:colorBackground">#FFFFFF</item>
        <item name="android:textColor">#0077FF</item>  
        <item name="android:actionBarWidgetTheme">@style/YourActionBarWidget</item>
    </style>
  
<!-- This helps the PopupMenu stick with Light theme while the ActionBar is in Dark theme -->
    <style name="YourActionBarWidget" parent="android:Theme.Holo.Light">
        <item name="android:popupMenuStyle">@android:style/Widget.Holo.Light.PopupMenu</item>
        <item name="android:dropDownListViewStyle">@android:style/Widget.Holo.Light.ListView.DropDown</item>
    </style>

This seems to work but how can I change the colors with xml.

B4X:
    ToolBar.PopupTheme=ToolBar.THEME_LIGHT
 
Last edited:

corwin42

Expert
Licensed User
Longtime User
Any suggest?

There is no second activity in the example.

Hi,

Thanks for this great support!! I am a beginner in this and I am using the AcToolbarDark. But now my overflow menu turns black on background. How can I change this?

I found the same issue here, but I do not understand to fix this in B4A.
http://stackoverflow.com/questions/25130418/styling-action-bar-overflow-menu-background-color

If I remember correctly the Popup theme is always set to the light or dark theme so changing the color is not supported.
 

corwin42

Expert
Licensed User
Longtime User

fishwolf

Well-Known Member
Licensed User
Longtime User
And in post #70 I answered that this example project has several errors.

can you show me please the right code?

i have try with this, but go to in crash

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
   
    Dim AC As AppCompat
   
    Private ToolBar As ACToolBarLight
    Private pContent As Panel
   
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("second")
   
   
    ToolBar.SetAsActionBar
    ToolBar.Title = "Second"
    ToolBar.InitMenuListener
   
    AC.SetElevation(ToolBar, 4dip)
   
    pContent.LoadLayout("content")

End Sub
 
Top