Basic UI Widgets – TextViews, EditTexts, and Buttons

Hello World! In this post, we’re going to be going in-depth into several of the most common UI elements that we’ll encounter in Android: TextViews, EditTexts, and Buttons. We’ll be looking into their properties and some of Java’s language features like anonymous inner classes.

TextView

The simplest way to show the user text is through the TextView element. Since this is the simplest element, we’ll also be covering some topics that are common to all Views.

Using a TextView is a really simple thing to do. All it requires is a height and width (required by all UI elements) and some text to go inside. The TextView also allows for all sorts of formatting for text as well. In XML, this is what a simple hello world TextView would look like.

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

As a side note, the android: prefix corresponds to the Android XML namespace, where Android will look for of our XML properties. layout_width and layout_height are required for all views and view containers and can only have two possible values: wrap_content and match_parent. Using the former means to make the View as big as the content of that View, whether it be a Button or EditText. However, the latter means that the width or height will be the same as its parent’s width or height.

New UI Elements – 1

Another important property and distinction we should make is between padding and margin. The above figure illustrates the different between the two. Padding is internal to the border of the View. Margin, on the other hand, is external to the border to the View. We use a combination of padding and margin to prevent the content of our views from being flush with the edge of the phone. It makes our content easier to read for the user’s sake and that’s always important! In fact, Google’s Material Design guidelines provide keylines in units of dp’s, which stand for density-independent pixels. For layouts, it’s more common to use padding since the layout contains other views; for single UI elements, it’s more common to use a combination of both.

The most important property, however, is the id property. This is the id that allows us to grab a reference to that view via its id. We also need to tell Android that we’re creating an id for a new UI element and not referring to an existing one. This is why we use “@+id/someView” when creating an id for a particular UI element and “@id/someView” is referring to another View. On a side note, referring to Views is something that we need to do when strategically placing UI elements. Creating ids will let us access them using the findViewById(int)  method. When we save any XML file, Android Studio automatically updates the R.id file.

EditText

If TextViews are the simplest way for users to view text, EditTexts are the simplest way for users to enter text. They are actually a subclass of TextView that is editable. The XML example for an EditText is similar to a TextView:

<EditText
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:hint="Hello World!"
/>

A useful property of EditText for text input is the hint property. It provides us with a transparent overlay that sits on top of the textbox and disappears when the user taps on it to input text. If we had used the text property for this purpose, the user would have to clear out that text before they could input their own. The hint property allows us to tell the user what data is supposed to go into this EditText.

One of the greatest properties of an EditText is that it can bring up a keyboard that’s most relevant to the kind of input we want our user to enter. Take the Contacts app for example. When entering a phone number, you’ll notice that the entire QWERTY keyboard won’t show up, but we’ll just get the numpad instead. This is the inputType property on EditTexts. Below is a list that describes the possible values for the inputType property:

  1. “text” – Brings up the plain text QWERTY keyboard
  2. “textEmailAddress” – Like “text”, except with the @ (at) character
  3. “textUri” – Like “text”, except with the / (forward slash) character
  4. “number” – Brings up standard number input keypad
  5. “phone” – Brings up the dialer keypad

In addition to those values, we can even specify other characters of plain text input. For example, suppose we were entering someone’s name. It would be nice of the keyboard could automatically capitalize the first and last name. Or suppose we were typing an email; then we’d want the keyboard to capitalize each sentence. Luckily, these inputType constants are also very explicitly named: “textCapSentences”, “textCapWords”, “textAutoCorrect”, “textPassword”, “textMultiline”. To be even more explicit, “textPassword” changes all of the characters to • (dots), and “textMultiline” allows the user to use line breaks.

Speaking of line breaks, it may be the case that you’d want multiple lines for text entry for things like emails, for example. To force the EditText to span multiple lines, we can set the minLines property on it to some positive integer. This will for the EditText to be at least that number of lines tall, prompting your user to enter text that’s longer than a single line.

Button

The Button is the most common way for users to begin or end some activity. For example, we might use buttons to allow the user to submit a form, download an in-app purchase, or end the level of a game. Therefore, the most common action associated with buttons is tapping on them! There are several ways for us to detect a button press and to run code on a button click. The first way is the simplest way and that uses the onClick property that Buttons have. We can declare a Button whose onClick property is the name of a method with a very particular method signature in any Activity that sets that XML layout to be its content view:

<Button
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="Submit"
    android:onClick="buttonClicked"
/>

This button is a small UI element defined in a bigger layout view, which in turn is defined in a layout file. Activities can present a view to the user through the setContentView(int)  method and pass in the id of a layout file using the R class. Now, in any Activity that uses the layout file as the main content view will have to implement a method that looks EXACTLY like this:

public void buttonClicked(View view) { 
    ... 
}

The method must be public void and take in a single View parameter. It might be easier to define all of your button click actions first, then associate them with a Button in the layout since the property’s autocomplete will help you find a particular method. As a rule of thumb, if autocomplete can’t find your method, that’s a sign the method signature is incorrect in some way. The reason the method is public void is so Android Studio can see it and because button event listeners don’t generally have return values. The View method parameter corresponds to which View was clicked. This can be helpful because instead of declaring multiple methods for different Buttons, we could wire all of the Buttons to one method and use view.getId() to differentiate between the Buttons using their unique id that we would set.

There is another way to do event handling for Button clicks and that involves a language feature of Java called anonymous inner classes. Instead of setting the listener in the XML layout, we could do it in Java source code. Suppose we have some Button whose id is submitButton. The follow code snippet will grab a reference to that and setup an event handler for the Button’s onClick event:

Button submitButton = (Button) findViewById(R.id.submitButton);
submitButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        ...
    }
});

The more interesting portion of the code snippet is the next line that sets the listener. All listeners in Android are interfaces, meaning we can’t instantiate them. However, we can set them to a new object whose’s class implements that particular interface. Anonymous inner classes is a shorthand way of doing this. Instead of creating an inner class that implements the View.OnClickListener  interface and passing in new SomeClassImplementingTheListener, we can just do that in-place by “instantiating” a new nameless class that automatically implements that interface and provide method bodies on the spot. This works equally well. In fact, there’s a third way we could do this even. We could pass in this  and have the activity in which this code is in implement the View.OnClickListener  interface and force it to have a @Override public void onClick(View)  method. The rule of thumb you can use is “If the method contents are going to have many lines of code, then it looks cleaner to pass in this , make the Activity implement the interface, and give it a method body as a regular method on the same level of the class, rather than to add a lengthy method body to an existing method. It’s just more lines of indentation you have to manage.”

Conclusion

In this post, we looked at TextViews, EditTexts, and Buttons. When looking at TextViews, we also glanced at some of the key properties that are central to all Views. We learned that we can configure the keyboard that EditTexts pull up to suite our data input needs, as well as make them span multiple lines high for longer text input. Buttons are useful for starting or stopping something and we primarily learned about event handling when it came to Buttons. As a bonus, we learned about Java’s anonymous inner classes and how we can use them for event handling.