Android Tutorial Material Design 2 - Using the AppCompat library

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

In the first Material Design tutorial we created a simple app with Material Design for Android 5.0 (Lollipop) devices. But what about older Android versions?
For compatibility with older devices Google created the support libraries which brings new features to older Android releases. For Material Design the most important support library is the AppCompat library. This tutorial will show how to use the AppCompat library with B4A.


Setting up AppCompat library
For this tutorial we need the AppCompat wrapper library. Please set it up as explainded in the first post of the library thread.

First we need to add the AppCompat library to our project. For this check the AppCompat library in the libs tab of the IDE.

Next thing to know is that every Activity which uses AppCompat features has to extend the android.support.v7.app.AppCompatActivity. This can be done with the #Extends attribute in the activity modules.

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

Setting up the theme
If we want to use AppCompat, we must use an AppCompat theme. Because we want to configure some colors in the theme we set up our own theme resource in the Manifest Editor:

B4X:
SetApplicationAttribute(android:theme, "@style/MyAppTheme")

CreateResource(values, theme.xml,
<resources>
    <style name="MyAppTheme" parent="@style/Theme.AppCompat">
        <item name="colorPrimary">#FF9800</item>
        <item name="colorPrimaryDark">#F57C00</item>
        <item name="colorAccent">#FFA726</item>
    </style>
</resources>
)

As you can see we use a parent of Theme.AppCompat for our example. There are also Theme.AppCompat.Light or Theme.AppCompat.Light.DarkActionBar themes like the standard Material Design themes. Additionally to the theme name we set colorPrimary, colorPrimaryDark and colorAccent. See the first Material Design tutorial for an explanation of these colors.

So let's see how our app looks like. For the first example I just added some UI elements like EditText, CheckBox, RadioButton, Spinner, ...

MaterialExample_Lollipop_wrong_scaled.png
MaterialExample_KitKat_wrong_scaled.png


On Lollipop devices this looks nice but there seems to be something wrong with pre Lollipop devices like KitKat, JellyBean or even Gingerbread. The UI elements like EditText, CheckBox and RadioButton just show black and are hard to see on the dark theme.
This is because the way B4A creates its views in the designer is not compatible with the AppCompat library. The AppCompat wrapper library contains some views which are compatible with AppCompat. Instead of EditText, CheckBox or RadioButton just use ACEditText, ACCheckBox and ACRadioButton views. These can be added as CustomViews in the designer or they can be added to the Activity (or to a Panel) manually by code just like the standard views.

Additionally there is a new ACSwitch view which looks like the standard on/off switch.
In the second attached example all these views are used as a CustomView with the designer. The examples should work on all devices with API 7 or above. On GingerBread devices there is not the nice coloring of the views but the app should still work.

MaterialExample_Lollipop_ok_scaled.png
MaterialExample_KitKat_ok_scaled.png
MaterialExample_Ginger_ok_scaled.png


Notice that on Gingerbread devices there is no overflow menu anymore.
 

Attachments

  • AppCompatExample1_2.0.zip
    8.1 KB · Views: 1,825
  • AppCompatExample2_2_0.zip
    8.3 KB · Views: 2,273
Last edited:

corwin42

Expert
Licensed User
Alright, because I am using B4A 5.8 but I am still having that same problem with the radio buttons and checkboxes being in black color when I test it on Android 4.x. Is there currently a fix for this?

Are you using the standard B4A UI elements or the AppCompat CustomViews?
The standard views will show black, the CustomViews should be fine.
 

JohnC

Expert
Licensed User
Corwin42, I am able to run your sample on this page:

https://www.b4x.com/android/forum/t...compatible-with-older-android-versions.48423/

But when I try to run the "AppCompatExample2" example on the first page of this thread I run into trouble:

During Compile:
ERROR: resource directory 'c:\users\stm\dropbox\basic4android\customlibsres\b4a_appcompat' does not exist

I am assuming this should point to the directory where I put all new .JAR and .XML library files, so I changed the path to:
#AdditionalRes: D:\Android\Basic4android\AddLibs\b4a_appcompat, de.amberhome.objects.appcompat

But I then get error:
ERROR: resource directory 'd:\android\basic4android\addlibs\b4a_appcompat' does not exist

I don't have a "b4a_appcompat" directory - so I am assuming this is something that your 2.0 library needed, so I remmed it out.

Then get a bunch of these errors during compile:

\attrs.xml:546: error: Attribute "textAppearanceSearchResultTitle" has already been defined
d:\android\android-sdk\extras\android\support\v7\appcompat\res\values\attrs.xml:548: error: Attribute "textAppearanceSearchResultSubtitle" has already been defined
....
....

So I remmed out the below line because I assume it duplicates resources that are already in/used by your 3.2 version of the library:
'#AdditionalRes: D:\Android\android-sdk\extras\android\support\v7\appcompat\res, android.support.v7.appcompat

It then compiles and copies to device, but when it runs I get this error:

** Activity (main) Create, isFirst = true **
main_activity_create (java line: 333)
java.lang.RuntimeException: java.lang.NullPointerException
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:166)
at anywheresoftware.b4a.objects.ActivityWrapper.LoadLayout(ActivityWrapper.java:209)
at de.amberhome.appcompat.example2.main._activity_create(main.java:333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
at de.amberhome.appcompat.example2.main.afterFirstLayout(main.java:102)
at de.amberhome.appcompat.example2.main.access$000(main.java:17)
at de.amberhome.appcompat.example2.main$WaitForLayout.run(main.java:80)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5293)
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:1102)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at de.amberhome.objects.appcompat.ACEditTextWrapper.DesignerCreateView(ACEditTextWrapper.java:70)
at anywheresoftware.b4a.objects.CustomViewWrapper.AfterDesignerScript(CustomViewWrapper.java:70)
at anywheresoftware.b4a.keywords.LayoutBuilder.loadLayout(LayoutBuilder.java:158)
... 18 more
java.lang.RuntimeException: java.lang.NullPointerException

Any ideas how to fix?
 

JohnC

Expert
Licensed User
Also, I have a Android 4.2.2 device. So, the checkbox and radio circle showed up in dark black as you described.

So, I replaced them with the ACCheckbox and ACRadioButton and they look good now. However, when the app starts, there is the sliding from top left corner animation of the entire activity. But it seems that the ACCheckBox and ACRadioButton controls *immediately* appear in their final position before the animation completes for the activity opening. You mention " Even the new animation functions of B4A 4.0 are supported" - if this was what you where talking about, how can I fix it so the ACxxxx controls also animate onto the screen?
 

corwin42

Expert
Licensed User
Any ideas how to fix?

The example is currently not updated to B4A6.0 and new AppCompat 3.20 library. I hope I find time to update the tutorials in the next days.

Removing all #AdditionalRes lines was correct.

For the error try to open the designer, load the layout file and save it again. This should fix the problem.

Also, I have a Android 4.2.2 device. So, the checkbox and radio circle showed up in dark black as you described.

So, I replaced them with the ACCheckbox and ACRadioButton and they look good now. However, when the app starts, there is the sliding from top left corner animation of the entire activity. But it seems that the ACCheckBox and ACRadioButton controls *immediately* appear in their final position before the animation completes for the activity opening. You mention " Even the new animation functions of B4A 4.0 are supported" - if this was what you where talking about, how can I fix it so the ACxxxx controls also animate onto the screen?

The support for the Activity Layout Animation was removed with AppCompat 3.x library. There were too many hacks and workarounds in the library to support it. Just set the Activity animation time to 0 to disable the animation.
 

JohnC

Expert
Licensed User
Cool. Thanks for the quick response. Even though my donation won't make you rich, I really do appreciate all your efforts in this forum :)
 

Roberto P.

Well-Known Member
Licensed User
Hello
should I enter the Extends in all activity which uses components or is there a way to insert only one point in the entire program?

thank you

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

corwin42

Expert
Licensed User
Hello
should I enter the Extends in all activity which uses components or is there a way to insert only one point in the entire program?

thank you

You need to do it for every activity.
 

trueboss323

Active Member
Licensed User
Corwin how do you use the Add2 method for the ACSpinner? So far I am trying this code but it's not working:

B4X:
Themespn.Add2("Blue",LoadBitmap(File.DirAssets,"spinicon.png"))
 

corwin42

Expert
Licensed User
Corwin how do you use the Add2 method for the ACSpinner? So far I am trying this code but it's not working:

B4X:
Themespn.Add2("Blue",LoadBitmap(File.DirAssets,"spinicon.png"))

The second parameter is a Drawable and not a Bitmap. You can use this:

B4X:
Dim bd As BitmapDrawable
bd.Initialize(LoadBitmap(File.DirAssets, "spinicon.png"))
Spinner.Add2("Itemname", bd)
 

johndb

Active Member
Licensed User
Is it possible to set an ACSpinner as a single line without wrapping if the text is longer than the ACSpinner view?

Thank you,

John
 

johndb

Active Member
Licensed User
@corwin42 Setting the ACSpinner Text Style "Horizontal Alignment" property has no effect and is always Center justified even when the property is set to LEFT or RIGHT alignment. This only applies to text that is wrapped to more that one line if the text is longer than the width of the ACSpinner. Would it be possible to have this corrected?
 
Last edited:

Rubsanpe

Active Member
Licensed User
@corwin42 Setting the ACSpinner Text Style "Horizontal Alignment" property has no effect and is always Center justified even when the property is set to LEFT or RIGHT alignment. This only applies to text that is wrapped to more that one line if the text is longer than the width of the ACSpinner. Would it be possible to have this corrected?

Hi. You can use

B4X:
Dim cs As CSBuilder
cs.Initialize.Alignment("ALIGN_NORMAL").Append("Text").popall

ACSpinner.Add(cs)

Rubén
 
Top