B4A Library XmlLayoutBuilder - Load Xml layouts

Edit: this tutorial was written before CreateResouce keyword was available. Simpler usage example:

The standard way to build the UI in Basic4android is with the visual designer / designer script.

You can also create UI elements by code.

This library adds a third option which is to use xml files to define the layout. This is Google's standard method.

This option is especially useful if you want to reuse resources created for an Android Java project.

All three options can be combined together.

This library provides several resources related methods. You can read more about Android resources here: http://developer.android.com/guide/topics/ui/declaring-layout.html

Before we start you should remember that the compiler "cleans" the objects folder during compilation. The compiler will delete the extra resource files if they are not read-only.

The simplest solution is to add the following attribute to force all the res files to be read-only:
B4X:
  #CustomBuildAction: 1, c:\windows\system32\attrib.exe, +r res\*.* /s
You might need to correct the path.

The example code is:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim x As XmlLayoutBuilder
   'load the layout
   x.LoadXmlLayout(Activity, "layout1")
   'load the Animation
   anim = x.LoadAnimation("wave_scale", "anim")
   'get a view based on the id
   button1 = x.GetView("fade_animation")
   'get a drawable object
   Activity.Background = x.GetDrawable("smlnpatch160dpi")

   Panel1 = x.GetView("panel1")
   Panel1.Color = Colors.White
   Dim spinner1 As Spinner
   spinner1.Initialize("")
   spinner1.AddAll(Array As String("1", "2", "3"))
   Panel1.AddView(spinner1, 0, 0, Panel1.Width, Panel1.Height)
End Sub

Folder structure:

SS-2013-10-22_11.11.30.png


Layout file:
B4X:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:paddingLeft="16dp"
  android:paddingRight="16dp"
  android:orientation="vertical" >


   <TextView
  android:layout_width="match_parent" android:layout_height="wrap_content"
  android:layout_weight="0" android:paddingBottom="4dip"
  android:textAppearance="?android:attr/textAppearanceMedium"
  android:text="@string/activity_animation_msg"/>

   <Button android:id="@+id/fade_animation"
  android:layout_width="wrap_content" android:layout_height="wrap_content"
  android:text="@string/activity_animation_fade"
     android:tag="Button1"
     >
  <requestFocus />
  </Button>
   <Panel
     android:id="@+id/panel1"
  android:layout_width="200dp" android:layout_height="80dp">
   </Panel>

  <CheckBox
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
     android:tag="chk1" />
</LinearLayout>

LoadXmlLayout method loads the layout file and adds the views to the activity or panel.
Once the layout is loaded you can use GetView to get a reference to a view based on the view's id attribute.

If you want to handle the view's events then you need to set the "EventName" in android:tag attribute.
You can handle events of the following views:
EditText, Button, CheckBox, RadioButton, Label (TextView), AutoCompleteEditText (AutoCompleteTextView), ToggleButton, ImageView, SeekBar and Panel.

Panel is treated differently as it is not a native view. Panel allows you to add other views (programmatically or with Panel.LoadLayout) to the loaded layout.

LoadAnimation loads an Animation object defined in an xml file. It allows you to create all kinds of animations including a set of animations (not possible with the standard Animations library).
http://developer.android.com/guide/topics/graphics/view-animation.html

The other methods allow you to load drawables and strings from the resource files.

Notes

- When using the rapid debugger, you need to right click on the libraries tab and choose Refresh after you update the resources. Otherwise the device app may not be redeployed and the old resources will be used.
 

Attachments

  • XmlLayoutExample.zip
    26.1 KB · Views: 2,982
  • XmlLayoutBuilder.zip
    5.3 KB · Views: 4,993
Last edited:

warwound

Expert
Licensed User
Longtime User
I have a problem using this library...

I have a CustomListView and am trying to inflate an XML layout for each item in the list view.
Only the very last list view item gets populated.

The problem is the GetView method:

B4X:
 public View GetView(BA ba, String Name){
  return ba.activity.findViewById(GetResourceId("id", Name));
 }

Each item in my list view contains 2 TextViews and an ImageView with unique ids.
But as i have many list view items there are many Views in the Activity with the same id.

What i really need to do is something like:

B4X:
 public View GetView(BA ba, ViewGroup Parent, String Name){
  return Parent.findViewById(GetResourceId("id", Name));
 }

With this the Parent ViewGroup will contain only one View for each id.

Does that make sense?

Martin.
 

warwound

Expert
Licensed User
Longtime User
A solution for my problem is to use the JavaObject library and call the findViewById method of the Panel into which i have loaded the XML layout:

B4X:
   Dim Panel1 As Panel
   Dim XmlLayoutBuilder1 As XmlLayoutBuilder
 
   Panel1.Initialize("")
   XmlLayoutBuilder1.LoadXmlLayout(Panel1, "my_layout")
 
   '   elsewhere in my code Panel1 is added to the Activity's layout
 
   Dim JavaObject1 As JavaObject
   Dim JavaPanel As JavaObject=Panel1
   Dim ResourceId As Int
 
   ResourceId=XmlLayoutBuilder1.GetResourceId("id", "title")
   JavaObject1=JavaPanel.RunMethod("findViewById", Array As Object(ResourceId))
   JavaObject1.RunMethod("setText", Array As Object("my title text"))

So i have multiple instances of a Panel into which i have loaded the same XML layout.
If i have 15 such Panels then the Activity contains 15 TextViews with the same "title" resource id.

Calling the XmlLayoutBuilder GetView("title") method returns the first View found in the Activity with the resource id.

Calling the Panel findViewById method returns the first View found in the Panel with the resource id, there's only one View in the Panel with the resource id.

There's only one View in the Panel with this resource id but there's multiple Views in the Activity with this resource id.

Martin.
 
Last edited:

tipallandgo

Member
Licensed User
Longtime User
Hi, I always get a NullPointerException whenever I try to load an animation. My code is:

B4X:
Dim xmlb As XmlLayoutBuilder
    Dim a As Animation
    a = xmlb.LoadAnimation("wave_scale", "Anim")
    a.Start(c.CardPanel)

I put the wave_scale.xml from the example to the anim folder of my project.
 

tipallandgo

Member
Licensed User
Longtime User
The app is paused at
B4X:
a = xmlb.LoadAnimation("wave_scale", "Anim")

logs:
B4X:
java.lang.NullPointerException
    at anywheresoftware.b4a.object.XmlLayoutBuilder.LoadAnimation(XmlLayoutBuilder.java:81)
    at com.tip.aris_mobile.gradescreen._showinfoscreen(gradescreen.java:1275)
    at com.tip.aris_mobile.main._ab_itemclicked(main.java:548)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:161)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:157)
    at de.amberhome.SimpleActionBar.ActionBar$Action.select(ActionBar.java:1683)
    at de.amberhome.SimpleActionBar.ActionBar$2.onClick(ActionBar.java:262)
    at android.view.View.performClick(View.java:4222)
    at android.view.View$PerformClick.run(View.java:17273)
    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:4895)
    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:994)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
    at dalvik.system.NativeStart.main(Native Method)

EDIT: I just want to add more info. I'm using AHActionBar. The code I posted above is in a sub from a class that is called when the used click an action item from the actionbar.
 

Eme Fibonacci

Well-Known Member
Licensed User
Longtime User
XmlLayoutBuilder v1.00 uploaded to the first post. It should fix this issue.

hi,

I'm not able to catch the event:
Sub check1_CheckedChange(Checked As Boolean)

In XMLLayout file I added an id:
android: id = "@ + id / check1" but
Sub check1_CheckedChange(Checked As Boolean)

does not work. Can help?
Thank you.
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi Erel,

I have the below Custom XML (For checkbox). I need to load it and set it to the checkbox in my activity. this is a selector. i have the drawable with me.how to go about calling it in my activity

B4X:
 <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true"
    android:drawable="@drawable/cbchk_blue"
    android:state_focused="false">
</item>
<item android:state_checked="true"
    android:drawable="@drawable/cbchk_blue"
    android:state_focused="true">
</item>
<item android:state_checked="false"
    android:drawable="@drawable/cbunchk_blue"
    android:state_focused="false">
</item>
<item android:state_checked="false"
    android:drawable="@drawable/cbunchk_blue"
    android:state_focused="true">
</item>

Regards,
SK
 

salvadoro

Member
Licensed User
Longtime User
Hi Erel, im using the next xml.

B4X:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <io.vov.vitamio.widget.VideoView
        android:id="@+id/SurfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:tag="VideoView1">
        </io.vov.vitamio.widget.VideoView>
    
</RelativeLayout>
How can i handle events for this.

Regards,

Salvador.
 

Johan Schoeman

Expert
Licensed User
Longtime User
If for eg a button was created with a XML layout file, being it a RelativeLayout, AbsoluteLayout, LinearLayout, or nested layouts, can the position and size (left, top, width, height) of the button be changed from within B4A code?
 
Top