Working with Text and Buttons

Amongst the user interface elements in Android, text and button elements are probably the most common. In this section, we'll dive into a small sample application that will give us a chance to work with these two elements.

Project details

  • Application name — NumberGuess
  • Activity — Blank
  • package —leave the default
  • Form factor —phone and tablet only

Fig 5-16 View elements for NumberGuess

There were a few cosmetic and aesthetic tweaks on the elements to make them appear a bit more pleasing to the eyes.

  <EditText
    android:id="@+id/editText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="26dp"
    android:ems="10"
    android:gravity="center_vertical|center_horizontal" // <1>
    android:hint="guess a number"                       // <2>
    android:inputType="number"                          // <3>
    app:layout_constraintBottom_toTopOf="@+id/button"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    tools:layout_editor_absoluteX="84dp"
    tools:layout_editor_absoluteY="106dp"/>

<1> This entry aligns the text inside the Plain text view both vertically and horizontally

<2> The hint attribute makes the text "guess a number" appear grayed out, it's good technique to use instead of an actual label, like a text view

<3> This restricts the input to numbers. If you don't add this attribute, the user will be free to type any alphanumeric character in the field, then you might need to handle the validation of the input using some regular expression techniques. This approach is so much easier

NOTE

All the tweaks above can be done also in design mode. You can set these values in the attributes inspector

We are still using a constraint layout, so you need to take care of putting constraints on each of the ui elements. Like in the past projects, this can be managed without much difficulty by positioning all the ui elements by hand, placing them in the approximate location where you want them to appear, then use the tools in the constraint inspector. Use the "pack" tool to distribute them horizontally then use the "infer constraints". That should take care of the layout.

Program file

The basic flow of this application is the following:

  1. When the application starts, a random number between 100 to 150 will be generated
  2. The user will guess what number was generated by inputting that number in the text field
  3. If the user's guess is higher than the random number, we will display "Guess lower" using the static text view
  4. If the user's guess is lower than the random number, we will display "Guess higher" using the static text view
  5. If the user guessed the number correctly, we will display the random number and a congratulatory note in the text field

Listing 5.5 -1 MainActivity Event handling plumbing

public class MainActivity extends AppCompatActivity
  implements View.OnClickListener {

  int numberToGuess = 0;
  EditText e;
  TextView t;

  @Override
  protected void onCreate(Bundle savedInstanceState) { ... }

  @Override
  public void onClick(View view) { ... }

  int initNumberToGuess() { ... } 

}

You may notice that the event handling approach for this project isn't using an anonymous nor an inner class, not that there's anything wrong with those approaches but making MainActivity the listener object provides some convenience for this situation. The main logic of getting the user input and comparing it to the generated random number will reside in the the onClick method. If this method was inside an anonymous or an inner class, then it would have necessitated that the variables holding EditText and TextView be declared final. That's just one of the Java rules about inner classes, it's okay to reference any variable on its outer class, provided it is final. And that would have made the code a bit more complicated than how it is structured as shown in Listing 5.5-1

The following sections shows the codes listing of onCreate, onClick and initNumberToGuess.

Listing 5.5-2 onCreate

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    numberToGuess = initNumberToGuess();             // (1) 

    e = (EditText) findViewById(R.id.editText);      // (2)
    t = (TextView) findViewById(R.id.textView);      // (3)

    Button b = (Button) findViewById(R.id.button);
    b.setOnClickListener(this);

  }
  1. The numberToGuess is initialized during onCreate but it was declared as member variable and not a local variable of onCreate. We need to reference this variable from the onClick method, that's the reason it was declared as a member variable
  2. The variable e is also initialized her but declared as a member variable as well, like numberToGuess, we need to reference this variable from the onClick method
  3. Same case as in the variable t, we also need to reference this from the onClick method

Listing 5.5-3 onClick

  @Override
  public void onClick(View view) {
    int number = Integer.parseInt(e.getText().toString());     // (1)
    if (number == numberToGuess) {
      t.setText(number + " is the right number");
    }
    else if (number < numberToGuess) {
      t.setText("Guess higher");
    }
    else if (number > numberToGuess) {
      t.setText("Guess lower");
    }
    Log.i("Ted", numberToGuess + "");
  }
  1. The getText method of the EditText returns and Editable object type, it's almost like text but it's mutable unlike a String. The Integer.parseInt, however, expects a String parameter, that's why we needed to convert the return value of getText using the toString method

Listing 5.5-4 initNumberToGuess

  int initNumberToGuess() {
    Random r = new Random();                  // (1) 
    numberToGuess = r.nextInt(100) + 50;      // (2) 
    Log.i("Ted", numberToGuess + "");
    return numberToGuess;
  }
  1. The Random class is from java.util. Make sure you import this package. Alternatively, when it turns red on the main editor, hover your mouse around it and use the quick fix (alt + enter for Windows and Linux | opt + enter for macOS)

The following listing shows the full code for MainActivity, for your reference

Listing 5.5-5

package com.ted.numberguess;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Random;

public class MainActivity extends AppCompatActivity
  implements View.OnClickListener {

  int numberToGuess = 0;
  EditText e;
  TextView t;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    numberToGuess = initNumberToGuess();

    e = (EditText) findViewById(R.id.editText);
    t = (TextView) findViewById(R.id.textView);

    Button b = (Button) findViewById(R.id.button);
    b.setOnClickListener(this);

  }

  @Override
  public void onClick(View view) {
    int number = Integer.parseInt(e.getText().toString());
    if (number == numberToGuess) {
      t.setText(number + " is the right number");
    }
    else if (number < numberToGuess) {
      t.setText("Guess higher");
    }
    else if (number > numberToGuess) {
      t.setText("Guess lower");
    }
    Log.i("Ted", numberToGuess + "");
  }

  int initNumberToGuess() {
    Random r = new Random();
    numberToGuess = r.nextInt(100) + 50;
    Log.i("Ted", numberToGuess + "");
    return numberToGuess;
  }

}

results matching ""

    No results matching ""