Friday, July 20, 2012

Android Layout - Pt. 1

So I've discovered that the first step in an Android project is to define the layout.  Which, compared to a web page, is about as difficult (or easy), it just has it different difficulties.

When one creates a project using Eclipse, Eclipse helpfully creates the beginning of a layout.  This layout  (I've starting talking like an Android developer; the term 'layout' is used whenever talking about the screen) looks like this:


    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

            android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello" />

Time to try to translate this into something more familiar to a web developer who has minimal experience with Java.

Note that we start out with an xml declaration.  Much of what goes on in an Android application is done in xml. And this is know as 'the mail.xml' file, located in the /res folder.  Main.xml defines the ViewGroup used by the project. 

The ViewGroup contains View groups.  There are five different View groups, but the primary ones are 'Linear Layout' and 'Relative Layout'.  Linear Layout lays out the fields one to a line.  As one seldom wants to have all one's fields one to a line, left justified, there are techniques for doing positioning on a line.

However, if one wants to place multiple items on the same line, or line up items with other items, the way to go is with Relative Layout.  Which is exactly what I have done.

Rather than deconstruct what I came up with, here is my initial layout.  The numbers in square brackets refer to the following notes, and are NOT part of the xml:


    android:layout_width="fill_parent"
    android:layout_height="match_parent"            [1]
    android:background="#A0A000"                    [2]
    android:orientation="vertical" >                [3]

            android:id="@+id/TopLine"                   [4]
        android:layout_width="wrap_content"         [5]
        android:layout_height="wrap_content"
        android:text="@string/TopLineTxt"           [6]
        android:textColor="#FFFFFF"                 [7]
        android:layout_marginTop="20dp"             [8]
        android:layout_centerHorizontal="true"      [9]
        android:textSize="36dp" />

            android:id="@+id/LineOne"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1"                            [10]
        android:textColor="#FFFFFF"
        android:layout_below="@id/TopLine"          [11]
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:textSize="36dp" />
   
                android:id="@+id/LineTwo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/LineTwoTxt"
        android:textColor="#FFFFFF"
        android:layout_below="@+id/LineOne"
        android:layout_marginTop="30dp"
        android:textSize="36dp"
        android:layout_centerHorizontal="true" />

            android:id="@+id/entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/LineTwo"
        android:layout_marginTop="10dp"
        android:layout_centerHorizontal="true"
        android:ems="10" />                          [12]

   

Note that each item on the screen gets its own view definition.  Now to explain the meaning of those parameters, and try to justify the choices I made:

[1]  The Relative Layout item describes the properties of the screen as a whole.  From the XML point-of-view, it also functions as a container for the individual screen fields. In this case, the parent is the entire device, and I want to define via the layout_height and layout_width parameters that this Relative Layout is to fill up the screen.  Fill_parent and match_parent mean exactly the same thing (the original parameter was match_parent; it was renamed fill_parent in the API version 8), and it means, fill up all of the space of the parent (minus any specified padding).

[2]  We want to specifiy the background color, and this is done using the standard hex color codes.

[3]  This specifies that the device is in the vertical orientation.  More on this later.

[4]  As mentioned above, in Android-Talk, each field is called a view.  And each view (for that matter each object) can be given a name, or 'id'.  For a view, the syntax for specifying the name is  "@+id/idname".  Here, the idname is TopLine

[5] We are in the process of defining a Text View named TopLine.  The layout_width parameter specifies how wide the view will try to be.  Match_parent will make it try to be as wide as it's parent container.  Wrap_content will make it try to be just wide enough for whatever content is put inside of it.  Layout_height is similar.

[6]  An Android project can have another XML folder for the constants.  And if you try to use a literal for a string item, Eclipse will scream at you.  So, the text which this Text View is going to contain is defined in /res/strings.xml as the constant TopLineTxt.  Note that these are truely constants.  Should it become necessary to change the text contained in TopLine, one does NOT simply assign a diffferent string to TopLineTxt in the Java code.

[7]  And it is possible to define the color of this text.

[8]  I wanted to put some separation between the first line and this field.  Layout_marginTop specifies some extra space (here 20dp) on the top side of this view (field).  As to what a 'dp' may be:  According to http://developer.android.com/guide/topics/resources/more-resources.html#Dimension a 'dp' is a Density-Independent Pixel.  The idea is that on a 160 dpi screen 1dp = 1px (pixel).  On a screen with more pixels per inch, the number of physical pixels used to draw 1dp increases.  On screens with poorer resolution, the number decreases.  Google deprecates the use of px as a unit, prefering dp, which provides a painless way to make the image scale up or down depending on the device used.

[9]  Makes sure the text is centered in the field.

[10] Not every string on the screen must be defined in strings.xml.  As LineOne is going to constantly change, there is little to gain by defining its starting value in strings.xml, so it is simply entered as the constant "1".

[11]  This positions the top edge of the LineOne field (view) with the bottom edge of the TopLine field.  We are starting to exploit Relative Layout.

[12]  An EditText view is a box into which one can type some text.  Android:ems specifies how wide this box should be, in ems.  And one em is the width of the letter 'M' in the current font.

So, this a picture of what we have.  But there is a problem.  While this would work just fine on my Droid Pro, on a device with a soft keyboard, said keyboard will take up some of the space.  On my emulator, when the keyboard pops up, it hides the Submit button.  So, I need to alter the layout.  My plan is to reduce the line spacing, reduce the size of those lines, and move the button to the right of the text entry box.  The question is:  do I already know how to do all that?

The changes start out simple enough:



    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:background="#A0A000"
    android:orientation="vertical" >

            android:id="@+id/TopLine"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="15dp"
/* Change from 20dp to 15dp  */
        android:text="@string/TopLineTxt"
        android:textColor="#FFFFFF"
        android:textSize="36dp" />

            android:id="@+id/LineOne"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/TopLine"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:text="1"
        android:textColor="#FFFFFF"
        android:textSize="30dp" />
/*  Change from 36 to 30dp */

            android:id="@+id/LineTwo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/LineOne"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:text="@string/LineTwoTxt"
        android:textColor="#FFFFFF"
        android:textSize="30dp" />
/*  Change from 36 to 30dp */

With the EditText box, we have a problem.  We cannot leave it centered, as (a) there isn't enough room for the button to fit on the right of it,  and (b) that would be really ugly if it did work.  So, I'm going to allign it on the left margin.

Now Eclipse is supposed to have some drag-and-drop functionality for layout. And, if I was starting completely fresh, it just might work.  But, when I try to drag the text box to the margin, I can't get it where I want it.  My suspicion is that Eclipse is trying to retain my prior parameters and add what it hopes I want for new ones, and the combination does not make sense.  So, I have to finish the job by hand:

            android:id="@+id/entry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/LineTwo"
        android:layout_alignParentLeft="true"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android:ems="6" >
       
   

   

I did discover the tag in the process of trying to drag-and-drop.  It keeps the focus on the text box, which is something I want.

I have one last issue with my layout. I've been assuming the device has always been held in the portrait orientation.  And this game really needs a different layout if the device is held in the landscape orientation. So, next time we'll look at how to accomplish that.

Sunday, July 8, 2012

This isn't exactly (remotely?) Oracle. But it is related to FizzBuzz.
Here's the deal: Ever since I got my Droid Pro I've had this curiosity about what it would take to program something on it. And, the FizzBuzz puzzle inspired a simple (the kind word) game for it. Since I do not want to be known as a copycat, I decided to name my game 'RatCat'. Very simple game. I imagine the screen having a line reading:



The RAT Says:

Followed by a field which would start out at '1'
Beneath this, there should be a line reading:



But You Say:


Followed by a data entry box, and a button labeled "Submit".

Obviously (?), the player is supposed to respond '2', and the game responds 'RAT'. The successful player will then enter '4' and the game will respond 'CAT'. This back-and-forth continues until the number '50' ('CAT') is reached, which results in a 'You Win' being displayed. To my way of thinking, this is a much more interesting game than Angry Birds. And this game would actually be worth the price.

The first thing I discovered is that writing Android Apps requires a lot of software to be loaded.
In Order:

  1. Eclipse Classic for 64-bit Linux
  2. The Java SDK (I already had an JRE, but that isn't enough here
  3. The Android SDK
  4. The Android Development Toolset plugin for Eclipse
And that is just the beginning. The next steps are to use Eclipse to install an Android platform and create an Android Virtual Device. The steps are outlined in the "Hello World"tutorial , so I won't go into more detail here. Suffice it to say that the troubleshooting guides almost got me through it all.

The one exception was when I tried to compile using Eclipse. I had been doing testing with java from the command line, and I thought I had java installed just fine. But, when I tried to use Eclipse I found myself with some strange java errors. It turned out that I had GCJ installed as my "sort of" java. Getting a propper java installation fixed everything.