The View Class

Intro

Android code is organized in such a way that code for an application's logic and its user interface are segregated.  This is by design.  It practically begs us to decrease coupling and increase cohesion in our application code...principles we try to attain when writing "good" Object Oriented programs.  Developing an app in this manner makes it possible to apply changes to the GUI and the program logic independently, making it easier to debug, update, and maintain.

Because it's assumed that you already know how to program in Java, you should already have an understanding of how to create the program logic.  It's no different than writing any other Java program.  In order to ensure proper cohesion, each Class should have a well-defined role, having methods directly related to the desired functionality of the class.  What we're going to talk about today is the other part of the equation, the user interface.

** If you get stuck doing something outlined below, you should go back and review what you did in the Hello World lesson **

What is a View?

All Android GUI elements are subclasses of the View object.  User interfaces are composed of  a combination of Views.  A View is a Java Class that inherits directly from the Java Object class, the root of the Java class hierarchy.  Views are the basic building block for all Android GUI elements, and serve as the base class for all GUI widgets.  Links to each View subclass shown in the hierarchy above can be found at the bottom of this page (quick link).

(src: http://developer.android.com/images/viewgroup.png)

A ViewGroup is a special subclass of the View class that serves as a container for multiple Views.  There are several useful widgets that extend the ViewGroup Class.  Most are actually subclasses of another ViewGroup known as a Layout.

Layouts are a special type of ViewGroup that serve as the framework for organizing an app's multiple Views on the device's screen.  There are several Layout types, each having its own properties and/or parameters.  We'll talk about Layouts in more detail in another lesson.  For now, if you want more information on common layouts, read this: Common Layouts

A Closer Look - TextView and EditText

For this course, do not use the Graphical Layout editor!  In order to actually learn the code and gain a better understanding of exactly what's going on, you must edit the XML file directly.

In order to become more familiar with how Views are created, let's take a closer look at a couple of the more common GUI elements.

Once the project is created, open the layout file that was created for you (res > layout > content_main.xml by default) and look at the TextView element (in XML...not in the Graphical Layout!).  

As a reminder, in XML there are two methods for defining an element's opening and closing tags:

We see both of these methods in use in our layout file: the RelativeLayout element uses method 1, and the TextView element uses method 2. 

A user interface is composed of several Views nested inside a Layout element.  All of a View's properties are defined inside the start tag.  They are called Attributes.  At a minimum, a View must have the layout_width and layout_height attribute values assigned.

To get a bit of practice with manipulating Views in XML, do the following:

Have a a look at the display preview to see the results of your hard labor (Hint: there's a little line to the right of the text): 

Not too impressive :-/

 

To explain, by default Linear Layouts arrange their contents on the screen horizontally, from left to right.  By changing the orientation attribute of the layout to vertical, the contents will be arranged on the screen from top to bottom.  This attribute is only applicable to Linear Layouts.  Had it remained a Relative Layout, the process to place the EditText below the TextView would be much different!  

Let's take a minute to see our work in action:

Click the Return/Enter button on the keyboard.  You see that the cursor moves to a new line (as you would expect).  You can change this by adding this attribute to an EditText or TextView: 

android:singleLine="true"

 

A Keyboard for Every Purpose

Have you ever noticed that in some apps there are times when a different keyboard is presented (for example, when entering an email address or phone number)?  That is because the developer has specified a value for the inputType attribute.  By default, an EditText has an inputType value of text.  It also provides a great example of how the attributes in your layout file have a direct affect on the user experience.

text keyboard number keyboard

I'll assume you figured out how to let the IDE tell you the available options.  For a full description of input types, go here: http://developer.android.com/reference/android/widget/TextView.html#attr_android:inputType

Buttons

We now have two of the most common Views under our belts.  In order to demonstrate how your app can respond to user action, let's add some functionality.  We'll need to add another of the most common View types: a Button.

There are many more Views that we could examine (and we will in a later lesson), but I think you get the point for now.  Each View type has attributes unique to it, but all are created in the same manner as above.  When you get a chance, I highly recommend that you take the time to familiarize yourself with all of the Views provided to you in the SDK.  

Of course, since Android is completely open source, and since you know how to extend classes in Object-Oriented code, if you ever get to the point that you need something that just doesn't exist, you can create your own View!

Your Task(s)

Here are your tasks.  If you've paid attention over that last few lessons, you should be able to knock this out in no time:

  1. First, change the Button text attribute so that it references a string resource instead of being hard-coded.
  2. Second, let's modify your MainActivity.java so that whenever the user clicks the Button, the TextView displays whatever text is typed in the EditText following these steps: 
    1. You'll need to create references in your Java code to the Views we just created.
      1. Give each View an id attribute value
      2. use the findViewById() method in MainActivity
    2. In order to capture the button being clicked, we'll need to use a listener.  Specifically, we'll use an OnClickListener.  An OnClickListener is used to capture when the app user clicks on a specific View.  You can register an OnClickListener for any View: 
      button.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  // your code here
              }
      });
    3. Most Views have standard 'getters' and 'setters' for text values.  The one's you'll need for this are setText() and getText().  Add the proper code inside the onClick method such that when the button is clicked, the TextView text is changed to whatever value is inside the EditText.  Also, the EditText value should be cleared when the button is pressed.  See if you can figure it out.

Once you're finished, feel free to compare your results against my sample solution at the bottom of the page.

For more information on techniques for handling use input events, read this: Input Events

View Hierarchy Links

Here's a semi-complete, hierarchical listing of some of the most used Views:

View

For a more complete listing of View options, methods and parameters, look here: http://developer.android.com/reference/android/view/View.html

Sample Solution

In order to complete the tasks above, you'll need to modify three files:  content_main.xml, strings.xml and MainActivity.java.

 

Task 1: Change the Button text attribute so that it references a string resource instead of being hard-coded

To accomplish this, you need to create a new string resource in the res > values > strings.xml file:

<string name="button_text">Click Me!</string>

Once you've created the string resource, modify your content_main.xml so that the Button's text attribute points to the new resource:

android:text="@string/button_text"

 

Task 2: Add button click functionality

So that we can reference them in our java code, define id attributes in the TextView, EditText , and Button views in content_main.xml:

android:id="@+id/myViewName"

Then, write the logic code in MainActivity.java.  There are a couple of ways to accomplish this:

Option 1: This is probably the one you did.  Create Java class objects for each of our views, set an OnClickListener to the Button, and instantiate a new OnClickListener...all in the onCreate() method of MainActivity.java, like so:

protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
	
	final TextView textview1 = (TextView) findViewById(R.id.textView1);
	final EditText edittext1 = (EditText) findViewById(R.id.editText1);
	Button button1 = (Button) findViewById(R.id.button1);
	
	button1.setOnClickListener(new OnClickListener(){
		
		@Override
		public void onClick(View v) {
			textview1.setText(edittext1.getText());
			edittext1.setText("");
		}
	});  
}

Option 2: This is what I did.  I'll explain the benefits in a minute.  First, have a look at the code:

public class MainActivity extends Activity implements OnClickListener {

    TextView textview1;
    EditText edittext1;
    Button button1;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textview1 = (TextView) findViewById(R.id.textView1);
        edittext1 = (EditText) findViewById(R.id.editText1);
        button1 = (Button) findViewById(R.id.button1);
        
        button1.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v == button1){
            textview1.setText(edittext1.getText());
            edittext1.setText("");
        } 
    }
    
}

There are two major differences between the two options given:

  1. In Option 2, I defined the View objects as class variables so that they could be referenced outside the onCreate() method.
  2. Instead of having the Button create a new OnClickListener, I had the MainActivity implement the OnClickListener interface.  Then I set the Button to use the Activity as its OnClickListener.  By doing it this way:
    1. I can react to OnClick events from multiple Views using the same listener, so I've minimized code redundancy
    2. I can define different behaviors based on which was clicked.  For example, I could set an OnClickListener on the TextView: 
  3. textview1.setOnClickListener(this);
    Then modify onClick() so that it reacts differently depending on whether the Button or the TextView was clicked:
    public void onClick(View v) {
    	if(v == button1){
    		textview1.setText(edittext1.getText());
    		edittext1.setText("");
    	} else if(v == textview1){
    		// do something else
    	}
    	
    }

    Notice that when checking to see which View was clicked, I compared the View argument to the class variables I defined above.