Index

Android apps - Formatting the screen


TextView - output or display text
EditText - input text
Button - starting up something in the app
ImageView - picture
RadioGroup - radio buttons
Spinner - drop down menu
Gridview - scrollable grid of images
Position on screen
First element on screen
First element on line
Next element on line
Baseline
Centring
Padding
Style of text

Go to app/res/layout/activity_main.xml. You can toggle between design (screen view) and text (code) at bottom of screen.

Code already there:

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:text="Hello World!" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>

Remove the "Hello World" text (your own views will replace it):

<TextView android:text="Hello World!" android:layout_width="wrap_content" android:layout_height="wrap_content" />

By the way, it doesn't matter what order the parameters of a tag are. Also remember that comments here are XML comments <!-- xxx -->




TextView

Use this to show text on the screen. It can also be used to output text (including numbers). Here is an example from Simple text app:

<TextView android:id="@+id/gmVal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/gmName" android:layout_alignBaseline="@id/eq" android:layout_toRightOf="@id/eq" android:layout_toEndOf="@id/eq" />

"android:id" is the name for this particular element on the screen. (The + means that we are defining it as opposed to using an already defined name.) Always have this. It is used by other elements on the screen, to work out their positions. If you are using this element for output, then the Java in MainActivity will also use it. "gmVal" is the actual name, but there will be other stuff connected to it which tells AndroidStudio where to find it.

"android:layout_width" and "android:layout_height" are compulsory for all elements. "wrap_content" means this element should be the size of its content. This seems to be the best bet. "fill_parent" makes it as big as the parent - usually the whole screen. So

"android:layout_width" with "fill_parent" takes the whole line.

"android:text" gives the text shown when you start the app. This is also used in Button and RadioGroup.
This specifies a string defined in app/res/values/strings.xml:

<string name="gmName">"gm"</string>

"android:layout_alignBaseline", "android:layout_toRightOf", "android:layout_toEndOf" - see position on screen.

You can change the text of this element while running the app. This is done in app/java/com.(the project name)/MainActivity in Java, as follows:

TextView gm = (TextView) findViewById(R.id.gmVal); gm.setText(gmOut);

The variable "gmOut" had been set up by MainActivity and is nothing to do with the screen layout. But "gmVal" is defined above. "gm" is tying the "findViewById" to the "setText".

When you code this Java, AndroidStudio gives an error "Cannot resolve symbol TextView". Click on TextView, then do Alt/Enter. The error will go away. This happens for EditText and ImageView "findViewById" as well.

You may want to set it to a string constant, defined in app/res/values/strings.xml. This code uses a string constant called "invalidText" (saying, perhaps, invalid!):

TextView gm = (TextView) findViewById(R.id.gmVal); gm.setText(getString(R.string.invalidText));

You can have an "onClick" in TextView - see Button for more on "onClick".

See style of text to set a different style of text.




EditText

Use this to input text. It can also be used to output text (including numbers). Here is an example from Simple text app:

<EditText android:id="@+id/ozVal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="numberDecimal" android:hint="@string/init" android:onClick="doClear" />

"android:id", "android:layout_width" and "android:layout_height" - see TextView.

I want a number typed in here. So "android:inputType" forces a numeric keyboard, and won't accept anything that isn't a number. Leave it out if you want non-numbers.

"android:hint" - this is similar to "android:text" (see TextView). The string given (which is defined in app/res/values/strings.xml) will be shown when the app starts. It will automatically disappear when the user starts typing something in. If you set the value of this element back to "", then the hint will reappear. It's called a hint because you should put something in here to hint to the user what is supposed to be typed in!

"android:onClick" says what happens if you click on this (or tap on it with a touch screen, of course). This is rather cunning. While it is easy to enter stuff at the start, after that, it can be quite hard to for the user to get rid of what's there and type in something new. So I have set up this onClick. This means that if they tap on the field, the method doClear is actioned. This clears down the screen element, so the user has a nice empty field to type into. (It seems that sometimes the user has to do a double click. I don't know why!) The necessary "doClear" method (in app/java/com.(the project name)/MainActivity in Java) looks like this:

public void doClear(View view) { EditText oz = (EditText) findViewById(R.id.ozVal); oz.setText(""); }

Please note that the "findViewById" uses "EditText" rather than "TextView" - makes sense!

This EditText has no positioing attributes because it happens to be the first element on the screen. See position on screen.




Button

Typing something into an EditText doesn't communicate with the app. After all, it's hard for the app to detect when the user has finished! So an EditText will usually have a button associated with it. The user enters the text, then clicks on the relevant button. That processes the data. It may well cause output to be shown elsewhere on the screen, as well. Here is an example from Simple text app:

<Button android:id="@+id/convertButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/convert" android:onClick="doCalc" android:layout_below="@id/ozVal" />

"android:id", "android:layout_width" and "android:layout_height" - see TextView.

"android:text" - see TextView.

"android:onClick" gives the method that will actually process the input data and produce some output on the screen. Here the method is called "doCalc". Please note that while methods menioned in Java must ALWAYS have brackets after them (even if they don't have parameters), these onClick methods do NOT have brackets after them. This is because they do, indeed, have a parameter, but it is sorted out by AndroidStudio. The "doCalc" method in this app (in MainActivity, in Java) is

public void doCalc(View view) { EditText oz = (EditText) findViewById(R.id.ozVal); TextView gm = (TextView) findViewById(R.id.gmVal); ozAmt = convNum(oz.getText().toString()); gmAmt = Math.round(ozAmt * 28.35); String gmOut = format(gmAmt)+getString(R.string.gmName); gm.setText(gmOut); }

You can see that the Java has set up communication with both ozVal and gmVal (both defined in the screen layout). It picks up the text from ozVal with "oz.getText().toString()" and it outputs text to gmVal with "gm.setText(gmOut);" The bit in the middle will be explained later, in strings.

"android:layout_below" - this element is the first element on a line - see position on screen.

"paddingTop", "paddingBottom", "paddingLeft" and "paddingRight" pad inside the button, not outside. Sigh...

Button text is all capitals (sigh...) To stop this, code this in the onCreate method in MainActivity, in Java.

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button buttonV = (Button) findViewById(R.id.newButton); buttonV.setTransformationMethod(null); }

"newButton" is the id of the button. This seems to override other stuff, so you may need to specify it explicitly. But at least you get rid of those horrible capitals...




ImageView

Use this to show a picture on the screen. It can be changed to a different picture, or used as a button. Here is an example from Simple picture app:

<ImageView android:id="@+id/starPix" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star" android:onClick="changePix" android:contentDescription="@string/descStar" android:layout_below="@id/instr" android:layout_centerHorizontal="true" />

"android:id", "android:layout_width" and "android:layout_height" - see TextView. But please note, if ImageViews are packed together on the screen, they seem to want "android:layout_below" as well, to get them in the right place.

"android:src" gives the picture shown when you start the app. Pictures will be described later.

"android:onClick" gives the method that will be actioned when you click on the picture. The method (in MainActivity, in Java) is

public void changePix(View view) { ImageView star = (ImageView) findViewById(R.id.starPix); if (toggle == 0) {star.setImageResource(R.drawable.empty);} else {star.setImageResource(R.drawable.star);} toggle = 1 - toggle; }

The "findViewById" uses "ImageView" this time, and it uses "star.setImageResource(R.drawable.empty)" rather the SetText. "star" is defined by the previous "findViewById". "R.drawable.empty" picks up a picture "empty" which is in your "drawable" folder. See Pictures for more information.

"android:contentDescription" is like the ALT in HTML. It describes the picture for people who can't see it for some reason. AndroidStudio wants you to have this. Again, who am I to argue? It's just a string, defined like the other strings.

"android:layout_below", "android:layout_centerHorizontal" - see position on screen.




RadioGroup

This is a type of multiple button. All options show on screen. Only one is selcted at a time. When you select a different one, it calls a method within Main Activity (in Java). Here is an example in the Convert Weights app.

<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/acc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_below="@id/eq9" > <RadioButton android:id="@+id/acc0" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/acc0" android:onClick="clickAcc0" /> <RadioButton android:id="@+id/acc1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/acc1" android:onClick="clickAcc1" /> </RadioGroup>

"android:id", "android:layout_width" and "android:layout_height" - see TextView.

"android:orientation" - this says how the options are listed. Another option is "vertical" of course.

"android:layout_below" - see position on screen.

"android:text" - see TextView.

"android:onClick" - see Button. There are two different methods depending which button you click on.

This doesn't set up an initial option, which I think it ought to! You have to set it up yourself in MainActivity (in Java). Since you want this set up when you start the project, it goes in the (existing) method "onCreate". Here is the whole of that method, with the necessary RadioGroup code in it.

int accType = 0; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); RadioButton acc = (RadioButton) findViewById(R.id.acc0); acc.setChecked(true); accType = 0; }

Yet another "findViewById" (and yet another rude message, requiring Alt/Enter). I pick up "acc0" rather than "acc1", so that's the button which will be checked. "accType" is merely a switch internal to my code so I know which button HAS been checked! It has been defined outside all methods, at the start of the class, so it is a glocal variable, and accessible by all methods.

You also need to code the methods for when the user clicks on the button:

public void clickAcc0(View view) { accType = 0; redo(); } public void clickAcc1(View view) { accType = 1; redo(); }

In this example, the internal switch gets changed, and the screen gets recalculated (since the radio button is controlling whether an exact or an approximate value is given). That uses the method "redo", which will look at the switch "accType" and change the calculation accordingly.




Spinner

This is a drop down menu, where only one can be selected at a time. It is shown as the first element in the list, with a little triangle to the right (which hints that it IS a drop down menu).

In app/res/layout/activity_main.xml, code
<Spinner android:id="@+id/mapDistrict" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/brum14" />

"android:id", "android:layout_width" and "android:layout_height" - see TextView.
"android:layout_below" - see position on screen.

This doesn't actually seem to set up anything, although it does position it on the screen and give it an "id". The actual set-up work is done elsewhere.

You now need to create a new file. Right click on app/res/values/, select New, then "Values resource file" (top). Give it any file name you want ending in .xml (see string arrays). In this example I called it "districts.xml", but the name is never used (sigh...) I've also given the "string-array name" as "districts". This WILL be used, later.
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="districts"> <item>Birmingham</item> <item>Dudley</item> </string-array> </resources>
In app/java/com.(the project name)/MainActivity (in Java), you need to change several things. First, (rather terrifyingly), you need to change the class definition (right at the top, after the imports, like this
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
Then, in the "onCreate" method, you code Spinner spinner = (Spinner) findViewById(R.id.mapDistrict); ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.districts, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(this);
In the first line, "R.id.mapDistrict" is the "id" of the Spinner in app/res/layout/activity_main.xml.
In the third line, "R.array.districts" is the "string-array name" in the new file you created. This is where you're setting up the format of the drop down menu.
The last line, on its own, is where you set up the necessary stuff so the app will notice when the drop down menu is used.

Add two more methods at the end:
// Select a district public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { if (pos==0) { xmax = 24; ymax = 24; x = 9; y = 6; district = 0; } else if (pos==1) { xmax = 23; ymax = 11; x = 7; y = 1; district = 1; } redo(); } // This code is needed, but not used public void onNothingSelected(AdapterView<?> parent) { }
"pos" is 0 for the first item in the drop down list, 1 for the second, and so on. (These computer people always start counting from zero!)
The example above sets up various counters and switches which will be actioned by the rest of the app.

AndroidStudio says that you can retrieve the selected item using "parent.getItemAtPosition(pos)". I haven't tried that.



GridView

Use this for a scrollable (downwards only) grid of images. Here is an example from Make a mosaic app (the app has two grids):

<GridView android:id="@+id/mosaicView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:numColumns="16" android:layout_below="@id/clearButton" />

"android:id", "android:layout_width" and "android:layout_height" - see TextView.

"android:layout_below" - see position on screen.

"android:numColumn" gives number of columns across the screen.

Everything else about the grid gets coded in app/java/com.(the project name)/MainActivity (in Java). See Grids.




Position on screen

Use the "design" tab (bottom of screen) to check things are in the right place.

This is all "RelativeLayout" (see top of page). Another way to position stuff is to use Group Views, with Views inside them. But AndroidStudio seems to prefer RelativeLayout, as it is quicker to resolve at runtime.

RelativeLayout starts in the top left-hand corner. You position the rest of the elements on that line by saying they come after the one before. To start the next line, you say it comes below the first element of the line above, and so on. A bit crude, but it seems to work. I suspect that doing it this way means that it is very robust for different screen sizes, orientation, etc. If the line is too long to fit on the screen, then it seems to cope, by putting it onto the next line, or possibly in other ways.

By the way, as you type in their attributes, AndroidStudio offers you possibilities at each stage. I must confess that I sometims type in "android:layout" and then chose a likely looking one! However, some attributes throw up a warning that the stuff might overlap on the screen.

The following positioning elements give the "android:id" of the element that this element is relative to, i.e. the one to the left, or the one above.


First element on screen

Use nothing - it will get positioned top left:

<TextView android:id="@+id/firstLine" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/textContent" />

First element on line

Use "android:layout_below":

<TextView android:id="@+id/nextLine" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/textContent" android:layout_below="@id/firstLine" />

Next element on line

Use "android:layout_below", "android:layout_toRightOf" and "android:layout_toEndOf".

<TextView android:id="@+id/midLine" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/textContent" android:layout_below="@id/firstLine" android:layout_toRightOf="@id/nextLine" android:layout_toEndOf="@id/nextLine" />

If you use "android:layout_toRightOf", AndroidStudio seems to want "android:layout_toEndOf" as well - who am I to disagree?


Baseline

"android:layout_alignBaseline" is used if you mix things of different height on the same line, e.g. EditView and TextView. It makes everything sit on the same line rather than floating above it.

<TextView android:id="@+id/midLine" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/textContent" android:layout_below="@id/firstLine" android:layout_toRightOf="@id/nextLine" android:layout_toEndOf="@id/nextLine" android:layout_alignBaseline="@id/nextLine" />

Centring

"android:layout_centerHorizontal" is another positioning attribute. This centres something (such as a picture) on the line, which looks nicer.

<ImageView android:id="@+id/starPix" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star" android:onClick="changePix" android:contentDescription="@string/descStar" android:layout_below="@id/instr" android:layout_centerHorizontal="true" />

That's fine if there is only one thing on a line. But you may wish to centre the first element, then position stuff either side. There is also "android:layout_toLeftOf" (and AndroidStudio will also want "android:layout_toStartOf" as well - sigh!) You might use this if you centred the first element on the line, and positioned other things either side. "android:layout_toRightOf" and "android:layout_toEndOf" puts things to the left, but if you want to put stuff to the right, use "android:layout_toLeftOf" (and it insists on "android:layout_toStartOf" as well). This means that you can centre something, and then position other stuff to left and right.

There is an oddity - if you have a 'forward reference' - that is, if you have a "android:layout_toLeftOf" BEFORE the item you are referring to, then app/res/layout/activity_main.xml doesn't seem to mind, but app/java/com.(the project name)/MainActivity has a nervous breakdown! So don't... That may seem a stupid thing to do, but if you are defining things in rows, then it's tempting to put them in the order they are in the screen, and you can't do that if the first one is defined as left of the second one.

Please note, if ImageViews are packed together on the screen, they seem to want "android:layout_below" as well as line attributes, to get them in the right place. That's why I put it in above.


Padding

At the top of app/res/layout/activity_main.xml, you will see:

android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"

You can use these inside the various views as well, to space things out. You can use the screen default ("@dimen/activity_horizontal_margin", etc.) or an explicit amount, such as "10dp" - these are a type of pixel.

<TextView android:id="@+id/sp1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" android:layout_alignBaseline="@id/kgDesc" android:layout_toRightOf="@id/kgDesc" android:layout_toEndOf="@id/kgDesc" />

If you use "android:paddingLeft", Android seems to want "android:paddingRight". It says it's to space things out nicely... This doesn't seem to happen with "android:paddingTop" and "android:paddingBottom".

If you use these padding attributes for a button, it pads INSIDE the button. Grr!!!

There can be a problem if you start with a TextView (which isn't tall) and then have an EditText on the same line (which is taller). This can cause the EditText to overlap the line above. Padding can shove stuff where you want them. Remember you can pad either the line below or the line above.

<TextView android:id="@+id/eq3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="10dp" android:text="@string/eq" android:layout_below="@id/stVal" />


Style of text

In app/java/res/values/styles.xml, there is already a "style" defined. Add another one, like this:

<TextView <style name="MenuTheme"> <item name="android:textColor">#600</item> <item name="android:textSize">20sp</item> <item name="android:textStyle">bold</item> </style>

"MenuTheme" is the name that you will use in the layout.

"android:textColor" gives colour as combination of red/green/blue, so "#000" is black.

"android:textSize" is given in scaled pixels. "20sp" is quite big.

"android:textStyle" can be "bold", "normal" or "italic".

In app/java/res/layout/activity_main.xml, in the TextView, add as an attribute:

<TextView android:id="@+id/maze1" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/MenuTheme" android:text="@string/maze1Text" android:onClick="doMaze1" android:layout_below="@id/howTo1" />

The following style gives a black background to the view.

<style name="BlackBack"> <item name="android:background">#000</item> </style>

© Jo Edkins 2016 - Index to Android app index