Android - Building Layouts Programmatically - Forms

In this post I'll be providing a simple example of an Android Activity with a form-like layout that's built dynamically and with no XML. The official Android developer guides will have you building XML layouts for anything View or Activity related but I'm not a fan of XML. I consider it a failed technology. A lot of promise, nice idea, but in reality not really worth the effort. Kinda like Communism.

Don't believe me? Then why the push away from SOAP to alternatives such as JSON? Remember XSLT? Hardly mentioned anymore. XML databases? Again, yesterday's flavour. XML configuration files? Not so popular now that we have attributes and annotations. XML's bloated and complicated text-based structure means it takes far more processing power then should be needed. Especially when there are far more efficient binary-based alternatives.


Original Image Source: SiegfriedSassoonGraveMells(GrahamAllard)May2006" by Graham Allard.
Licensed under CC BY-SA 2.0 via Wikimedia Commons.

Perhaps, in large teams with dedicated UX specialists that don't need to know Java and need a flexible framework with which to express their ideas, there is room for XML as a means to describe UI elements. Otherwise, it's just another file one has to manage. Another file format to learn. Another document to parse. Another less flexible more verbose way to express what I could've more easily been done in code. But I digress.

The Form

Let's get back to the original goal of this post as there's not a lot to explain. I've just provided an example of an Activity with a form-like structure that has been created without any XML layouts. I've included some basic controls but no code or events to process data entered. My goal was just to show how one might nest and use the LinearLayout class. The Activity should look something like the following image. I used a Nexus 7 so the Activity will likely look different on smaller screens.

Some of you might have worked with Microsoft's Windows Forms framework and notice how similar this approach is. Unlike Android, WinForms maintains its window layout information via auto-generated code that changes in real-time as the developer changes and moves controls on a window "form". This approach has been used for years, and still is, so there's no need to fret at the idea that an Activity's layout might be created without the help of XML.

The Code

The core of the work begins in the "onCreate" function (lines 4-27) which creates a few controls (lines 13-16) before creating the master LinearLayout and populating it with all the necessary controls (lines 18-26). I've broken out a few functions ("New_Form_Field", "New_Form_Label", "New_Form_Check", "New_Form_Radio") to make things easier to read and to avoid some duplication of code. Hopefully this will begin to suggest the flexibility afforded by not using XML. We could, for example, build proper classes to represent a form field, its label, and input controls with relative ease and not have to concern ourselves with attached XML files if we were to subclass these.

In a previous post I show a similar programmatic approach to building multi-level tree-like Activities and Views.

1:  public class FormActivity   
2:  extends android.app.Activity  
3:  {  
4:   @Override  
5:   protected void onCreate(android.os.Bundle savedInstanceState)  
6:   {  
7:    android.widget.LinearLayout layout;  
8:    android.widget.EditText text_field1, text_field2, text_field3;  
9:    android.widget.ToggleButton toggle_field;  
10:      
11:    super.onCreate(savedInstanceState);  
12:    
13:    text_field1=new android.widget.EditText(this);  
14:    text_field2=new android.widget.EditText(this);  
15:    text_field3=new android.widget.EditText(this);  
16:    toggle_field=new android.widget.ToggleButton(this);  
17:      
18:    layout = new android.widget.LinearLayout(this);  
19:    layout.setOrientation(android.widget.LinearLayout.VERTICAL);  
20:    layout.addView(this.New_Form_Field("Name", text_field1));  
21:    layout.addView(this.New_Form_Field("Address", text_field2));  
22:    layout.addView(this.New_Form_Field("Phone", text_field3));  
23:    layout.addView(this.New_Form_Field("Languages Spoken", this.New_Form_Check()));  
24:    layout.addView(this.New_Form_Field("Gender", this.New_Form_Radio()));  
25:    layout.addView(this.New_Form_Field("Discount", toggle_field));  
26:    setContentView(layout);  
27:   }  
28:     
29:   public android.view.View New_Form_Field(  
30:    String label, android.view.View input_widget)  
31:   {  
32:    android.widget.LinearLayout form_field;  
33:    android.widget.LinearLayout.LayoutParams params;  
34:      
35:    // layout parameters for whole form field ie label & input widget  
36:    params=new android.widget.LinearLayout.LayoutParams(  
37:     android.widget.LinearLayout.LayoutParams.MATCH_PARENT,   
38:     android.widget.LinearLayout.LayoutParams.WRAP_CONTENT);  
39:    params.rightMargin=20;  
40:    params.leftMargin=20;  
41:    params.topMargin=20;  
42:       
43:    form_field=new android.widget.LinearLayout(this);  
44:    form_field.setLayoutParams(params);  
45:    form_field.setOrientation(android.widget.LinearLayout.HORIZONTAL);  
46:    // label column occupies 25% of available horizontal space  
47:    form_field.addView(this.New_Form_Label(label),  
48:     new android.widget.LinearLayout.LayoutParams(  
49:      0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 25));  
50:    // widget column occupies 75% of available horizontal space  
51:    form_field.addView(input_widget,  
52:     new android.widget.LinearLayout.LayoutParams(  
53:      0, android.widget.LinearLayout.LayoutParams.WRAP_CONTENT, 75));  
54:    return form_field;  
55:   }  
56:     
57:   public android.widget.TextView New_Form_Label(String label)  
58:   {  
59:    android.widget.TextView label_view;  
60:      
61:    label_view=new android.widget.TextView(this);  
62:    label_view.setText(label);  
63:    label_view.setGravity(android.view.Gravity.RIGHT);  
64:    label_view.setPadding(0, 0, 20, 0);  
65:    label_view.setTextSize(20);  
66:    return label_view;  
67:   }  
68:     
69:   public android.widget.LinearLayout New_Form_Check()  
70:   {  
71:    android.widget.LinearLayout layout;  
72:    android.widget.CheckBox c;  
73:      
74:    layout=new android.widget.LinearLayout(this);  
75:    layout.setOrientation(android.widget.LinearLayout.HORIZONTAL);  
76:    
77:    c=new android.widget.CheckBox(this);  
78:    c.setText("Spanish");  
79:    layout.addView(c);  
80:      
81:    c=new android.widget.CheckBox(this);  
82:    c.setText("English");  
83:    layout.addView(c);  
84:      
85:    c=new android.widget.CheckBox(this);  
86:    c.setText("Chinese");  
87:    layout.addView(c);  
88:      
89:    return layout;  
90:   }  
91:     
92:   public android.widget.LinearLayout New_Form_Radio()  
93:   {  
94:    android.widget.RadioButton b;  
95:    android.widget.RadioGroup g;  
96:    
97:    g=new android.widget.RadioGroup(this);  
98:    
99:    b=new android.widget.RadioButton(this);  
100:    b.setText("Female");  
101:    g.addView(b);  
102:    
103:    b=new android.widget.RadioButton(this);  
104:    b.setText("Male");  
105:    g.addView(b);  
106:      
107:    b=new android.widget.RadioButton(this);  
108:    b.setText("Other");  
109:    g.addView(b);  
110:    
111:    return g;  
112:   }  

Popular Posts