An Alternative to Generating Android Layout XML
Note: A "Dark Theme" is now available in the latest source and .exe; choosing that will make the background Black, TextView text Yellow, Button text White, and EditText "innards" white.
In the olden days of Eclipse, creating the GUI/View part of a Java app was/is unconscionably difficult. Along came Droidio (AKA "Android Studio") that makes creating an Android layout much easier. You simply open a layout (XML) file in Design mode and drag widgets onto the design surface:
However, there is still a lot of tweaking that needs to be done to get the layout to look the way you want - adding containers (which then oftentimes have to be cut-and-pasted above or below certain widgets, then you have to cut-and-paste the widgets inside the container, then there are properties to set, such as width and height, etc. etc. ad infinitum ad nauseum).
So, once I determined what I pretty much usually wanted for a typical layout (YMMV, of course!), namely to use an outer vertical LinearLayout
with multiple inner horizontal LinearLayout
s, I decided to create a utility (in C#) that I could use to easily create a mockup of the Android Layout I had in mind that would generate at least a good starting point for the XML I would need.
Regression Session
For the correct Layout XML to be generated, though, you first need to add some ancillary XML files to your drawables folder. Of course, you only need to do this once, so it is not generated when you select the "Generate XML for Layout..." button; instead, prior to that, when you start the utility, you can copy-and-paste what you need from the "Generated XML" tab to the appropriate location:
Note: This ancillary XML is overwritten once you select the "Generate XML..." button, so if you want it, you have to grab it prior to that point (any time you start the utility).
Other "Helper" XML Vals
In keeping with the SOC (Separation of Concerns) and DRY (Don't Repeat Yourself) Principles, string
s are also put in their proper place (not directly in widget properties as raw values). So, these also are generated as part of the XML-generation process of the utility, and must be copied-and-pasted to the appropriate location before your layout will look right and do right. But I'm getting ahead of myself a little here - we'll come to that in due time. Let's just step through the process of creating an Android Layout file using my utility.
An Admission of Guilt, Made with Hung Head and a Hangdog Expression
Before showing you the utility, I must confess: it is, if not "9X Uglier than a Bag of Butts,*" certainly no candidate for any beauty prize. It is plain, a bit kludgy, and not at all meant as a precise rendition of what you will actually see in Android. IOW, it is not quite a "reasonable facsmilie"; perhaps a semi-reasonable facsimile of a smudged facsimile - if you squint and are gracious in your evaluation of its sartorial actualization.
* Apologies/Kudos to Eddie J. Nelson, who, AFAIK, originated that descriptive saying.
The Inauspicious First Impression
Behold then, brave reader, the austere and spartan appearance presented by the utility when it starts up:
The Intended Outcome
Before you begin to create your mockup, you need to know what you want the end result to look like. Whether it be drawn on a piece of paper, a screenshot of an existing "layout," or even just "in your mind's eye," you need to have a goal toward which you are pressing. In this example case, we are going to try to replicate (mas o menos) this wonder of artistic design:
The Ground Rules
Since I use the LinearLayout
, I "see" this form as a series of rows, to wit:
- First, second, and third rows (Rows 0..2) ==
Label
and TextBox
("TextView
" and "EditText
" in AndroidSpeak) - Fourth and Fifth Rows (Rows 3,4) ==
TextView
and ComboBox
("Spinner
" in AndroidSpeak) - Sixth and Eighth Rows (Rows 5,7) ==
TextView
- Seventh and Ninth Rows (Rows 6,8) ==
RadioGroup
with three RadioButtons
within - Tenth Row (Row 9) ==
Checkbox
and Two Buttons
Understanding The Util's WorldView
Each row of your layout is created on a separate tab on the utility. You can add up to six widgets for each row, although normally it will just be one or two, presumably. The "six" is an "extreme" case but you can change that if you want, since I'm making the code available. It is similar with the number of rows - I have an upper limit of 12, but you could change that (in either direction, in fact), too.
Each time you finish a row, you should select the "Show Mockup of Current Row" button; this will show you, in the FlowLayoutPanel
at the bottom (just above the row of buttons at the bottom of the utility), the "Windows" versions of the widgets you have selected, with a (very) general idea of what they will look like on your Android Layout.
At any time, you can make changes and re-select the button. The same is true of the "Show Mockup of All Rows" button which, when you select it, will make the "Mockup" tab active, and you will see what you have so far. The "Mockup" tab shows you images (not real controls) from all the FlowLayoutPanels
at the bottom of each of the "Row" tabs.
Note! You must select the "Show Mockup of Current Row" buttons for each row you have designed before selecting the "Generate XML for Layout and Java for Activity" button, as the row mockups on the FlowLayoutPanels
at the bottom of each "Row" tab are "screen shotted" for display on the "Mockup" tab.
If you want a Mulligan/Do-Over, mash the "Clear All" button, and the row mockups will be disposed.
Now Let's Get Down To It
So, for the first row, I select a TextView
and give it the value "Invoice #":
...and then an EditText
, giving it an appropriate name:
Note that I chose an orange frame for it, too (see "Regression Session" above).
Champing at the Bits
I know you're waiting with bated (not baited, as if you are out to catch fish) breath, so let's now mash the "Show Mockup of Current Row" button. This is the rapturous vision that presents itself:
Back to the Drawing Board
Now I add the values for the next two rows ("Date
" and "Total Amt $
"); as they are very similar to the first one, I won't show that; just consider it done (remember to move to the appropriate tab for each row). Note, though (here is an area for improvement) that Android has a "Date
" Text Field and a "Number
(Decimal)" field that are more specific than the general EditText
that my utility generates XML for. Either the utility could be enhanced to generate these more specific widgets, or you can tweak the XML after the fact, in the Droidio editor, via the EditText
's inputType
property (which has a virtual googleplex of different options, including email address, password, phone, and many others.
For row3
, we need a TextView
and a Spinner
. Here is what you see when you select a Spinner
as the second widget on the row:
...and then after selecting "Show Mockup of Current Row" button and dropping down the combobox on the FlowLayoutPanel
:
Row 4 ("Site #") is very similar. Consider it done.
Row 5 is a Label
/TextView
("Edit List"). Consider it done.
Row 6 is a RadioGroup
with three Radio Buttons. For this select "Radio Group" from the first comboBox
on the "Row 6" tab and enter these values:
Row 7 is a Label
/TextView
("Redemptions"). Consider it done.
Row 8 is similar to Row 6. Consider it done.
For the final row, row 9, add a CheckBox
:
...followed by two buttons:
(Only the first one being added is shown.)
How Good Is Your Imagination?
Now that we've added all the rows for the Layout
, we can mash the "Show Mockup of All Rows" button. This is what we see (Van Gogh, eat your heart out):
As you can see, this doesn't really give you much of an idea of what your layout is going to look like. It is a very rough idea of that. It's more of a "sanity check" so that you can verify all the pieces you intend to be there are there, and that they are on the appropriate row. You can always "redo" any row at any time before generating the XML and Java.
Cue the Fanfare, the Drum Roll[s], and the Anticipatory Pause
Now, once you are fairly certain you're ready for the generated code, you can mash the "Generate XML for Layout and Java for Activity" button. You will see something like:
Just follow the directions in the "comments" (copy strings to strings.xml, copy arrays of strings to arrays.xml, and then copy the Layout XML into the appropriate layout XML file in Droidio). You must do it in this order (top down), or the layout XML will complain about the missing string
s.
Note: If you indirectly create a string value that already exists in the strings.xml file (which will happen if you have two "OK" buttons, for instance), you will already have that entry in strings.xml, and duplicates are not allowed. So, if you copy-and-paste a duplicate, you must delete one of them (unless you enjoy the sublime peace that accompanies a non-compiling project).
The same is true for string-arrays in arrays.xml - you cannot have multiple string-arrays with the same name. If you end up with that, either delete one of them or, if they have different sets of values, change the name of one of them (and make sure to update the reference in the Layout XML for the widget that uses those values).
I Wanna Hold Your Hand
So, just to be overtly plain about it all, follow these steps (after you've done it once, it should come as second nature and seem obvious):
Copy the strings (below "// Add these strings to [appName]\app\src\main\res\values\strings.xml ") and append them to your Strings.xml file.
Copy the string arrays (below "// Add these strings to [appName]\app\src\main\res\values\arrays.xml ") and append them to your arrays.xml file.
Copy everything below "// Add the rest to the appropriate layout file ([appName]\app\src\main\res\layout\?.xml) " to your Layout XML file, overwriting whatever is there (you might want to back it up first, or at least copy it to a text file).
If you need to know how to add a Layout file to Droidio, read my article here.
If all has gone relatively well, you should now see something like:
As you can see, the last row only shows partially; in cases like this (where there will be a lot vertically on the screen), you can check the "Enclose Layout in ScrollViewer
element (you will want this if your Layout
may overflow the screen)" checkbox
, which will wrap the Layout
XML in a ScrollView
element, allowing you to scroll down at "run-time" (really "emulate time") and view the rest of the Layout
like so:
...and then after scrolling down:
In the current version of Droidio (0.59 at time of scribbling), at least, when you add ScrollView
to a Layout
, it no longer shows you the device, but simply the design surface:
The good thing about that is now you can see all of the widgets.
Note, too, that there is optional Java code that has been generated. Go to the "Generated Java" tab to access this. You should see something like:
EditText _edttxtInvoiceNum = (EditText) findViewById(R.id.edttxtInvoiceNum);
EditText _edttxtDate = (EditText) findViewById(R.id.edttxtDate);
EditText _edttxtTotalAmt = (EditText) findViewById(R.id.edttxtTotalAmt);
Spinner _spnrspinnerVendorID = (Spinner) findViewById(R.id.spnrspinnerVendorID);
Spinner _spnrspinnerSiteNum = (Spinner) findViewById(R.id.spnrspinnerSiteNum);
CheckBox _ckbxAllow_New_Items = (CheckBox) findViewById(R.id.ckbxAllow_New_Items);
Button _btnOK = (Button) findViewById(R.id.btnOK);
_btnOK.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
Button _btnCancel = (Button) findViewById(R.id.btnCancel);
_btnCancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
}
});
If you copy this Java to the corresponding Activity's onCreate()
event, you will already have references to the appropriate widgets, and on"Click" (probably more likely on "Tap") event handler[s] hooked up for any buttons you've added. To see how to add Toasts to the event handlers as "sanity checks,", see this tip.
Sometimes an Article is Just a Particle
Remember that this utility is a "work-in-progress" and is very limited in functionality. It only creates LinearLayout
types of layouts, it doesn't take into consideration different orientations, nor does it seem to comprehend that there are various sizes of devices. IOW, it's a "quick-and-dirty" tool, not a whiz-bang, feature-rich, Nth wonder of the world. That having been said, it may be of some value to you, anyway - or maybe you can enhance it to make it "more better."
Thanks to all who helped with the coding; if you look at the source, you will see several links to StackOverflow answers that helped bring this utility to fruition.