Hangman Tutorial Lesson 3 – Beginning the UI

Now that we have our phrases being loaded, it’s time to work on the UI. In Android, the UI is separated from the code by placing the UI components in XML files, caled “layouts”. While you can create your layouts just by editing the XML file, it’s a lot easier to use Eclipse’s Graphical Layout window to edit your layout visually. In the Package Explorer, find the “res” folder and expand it, then expand the “layout” folder. Any layouts that you define for your app will be found in this folder. Now double click on “main.xml” to open up the file.

Image

On to bottom left of the editor window that opens up, you can choose to edit the layout through the “Graphical Layout”, or edit the XML through “main.xml”. Click on “Graphical Layout”. You should see the “Palette” on the left of the editor window, with all the widgets you can add. You can drag and drop any of these widgets onto your layout.

Besides the “main.xml” file in the layout folder, you could also see another file called “fragment_main.xml”. Because devices are all different shapes and sizes, fragments allow you to customize your layout based on the device. So for example, for a tablet, you might want to show more widgets than if you were using a phone. Fragments are a more advanced feature, so for this tutorial we are going to delete the fragment and just deal with the “main.xml” layout. Right click on fragment_main.xml and click delete.

Image

By deleting the fragment, you should see that your project now has errors. To remove all the references to the deleted fragment, open the MainActivity.java and modify the code. Remove the PlaceholderFragment class and the “if (savedInstanceState == null)” block of code in the onCreate() method.

Delete the following block of code:

public static class PlaceholderFragment extends Fragment
{
    public PlaceholderFragment()
    {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);
        return rootView;
    }
}

And delete this block of code too.

if (savedInstanceState == null)
{
    getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();
}

Your code should now look like this and should build successfully now:

package com.famlinkup.hangman;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        PhraseGenerator phraseGenerator = new PhraseGenerator(this);
        Toast.makeText(this, phraseGenerator.nextPhrase(), Toast.LENGTH_LONG).show();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings)
        {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Now we can customize the “main.xml” layout. Open the Graphical Layout again. On the right hand side, you should see an “Outline” window and a “Properties” window.

2014-03-25 22_20_36-Java - Hangman_res_layout_main.xml - Eclipse

If you can’t find them, you should be able to open them  by clicking on Windows -> Show View.

The outline shows you the hierarchy of how your widgets are laid out and how they are nested. This is a simple outline of what the XML file looks like and how the elements are nested. The Properties view lets you view and set any properties having to do with the selected widget.

Right now, our Layout should have defaulted to the FrameLayout. This is useful if you want to place a single child in your layout. For now however, we want to change that Layout to a ScrollView. Because each screen is a different size, we want to guarentee that if all the content doesn’t fit on their screen, they can still scroll down to see the rest of the content. Without a ScrollView, it would cut off your layout and there would be no way for the user to access it. To change the layout, goto the Outline window and right-click on the only element, called container.

2014-03-25 22_28_15-Java - Hangman_res_layout_main.xml - Eclipse

Now select “Change Layout…” and change it to ScrollView.

Good, now we can start adding widgets. For our game, we’ll want to display the phrase they are guessing, a picture of a hangman, maybe say how many wrong guesses they have, and a set of letters that they can click on to choose a letter. All the widgets need to somehow be added to our layout in an orderly fashion. So inside of our ScrollView, we’ll want to add another layout. One of the most common layouts that I like to use when adding multiple widgets is a LinearLayout. You can choose to have your LinearLayout flow horizontally or vertically. We want all our widgets to flow vertically, where each widget is placed in its own row.

Go to your pallete, expand Layouts, and select LinearLayout (Vertical) and drag it onto the ScrollView layout.

2014-03-25 22_34_32-Java - Hangman_res_layout_main.xml - Eclipse

Good, now the first thing we want to add to our LinearLayout is the phrase they want to guess. We’ll use a TextView for that, which is basically just a label. Expand “Form Widgets”, select “Large Text” and drag it onto your LinearLayout.

2014-03-25 22_39_05-Java - Hangman_res_layout_main.xml - Eclipse

Android will give you a default id for your newly created TextField (which will be called something like textView1). This ID is what you use to reference any widgets in your code, so it’d be good to name it something you can remember. Let’s rename the Id to something that makes sense: “txtPhrase”. To do so, select your TextField, go to Properties, and change the Id from “@+id/textView1” to “@+id/textPhrase”.

2014-03-25 22_41_08-Java - Hangman_res_layout_main.xml - Eclipse

Also, let’s set the Typeface to monospace. Later, as the user guesses a letter, we’ll be changing the text as we reveal letters. If we don’t do monospace, then the letter widths can change as we reveal the letter, which could cause a weird growing and shrinking effect as they update.

2014-03-29 12_27_23-Java - hangman_first_res_layout_activity_main.xml - Eclipse

Now that we have a TextView defined, it would be nice to have it update to the randomly chosen Hangman phrase from last lesson. Let’s open up the MainActivity.java file again. In the onCreate() method, right now we display the phrase using Toast. Let’s change that line:

PhraseGenerator phraseGenerator = new PhraseGenerator(this);
TextView txtPhrase = (TextView)findViewById(R.id.txtPhrase);
txtPhrase.setText(phraseGenerator.nextPhrase());

To get a hold of that widget inside of our MainActivity, we need to call findViewById() method. This method takes an id, and is the id we renamed previously. This is a very common method that’ll we’ll use any time we want to access a layout widget that we’ve created in the Graphical Layout. Once we find the widget, we cast it to a TextView because we know that is what it is, and then set the text.

Let’s deploy the app and see what it looks like now:

device-2014-03-26-070408

Now instead of seeing the Hangman phrase as a Toast message, you should see the phrase at the top of your app.

Last of all, it would be nice to have the ability to skip to the next phrase in Hangman. This would be useful for testing as we develop the game, and would also be a nice feature for users to skip over phrases they don’t want to do. Let’s add a button to our layout. For now we’ll just place it in the LinearLayout right below the txtPhrase. In the Pallete under Form Widgets, select and drag  Button onto your LinearLayout. Change the Id to “btnNext”. Lastly, we want to change the text inside the button. Find the Property (in the Properties Window) called “Text” and change it to “Next”. It should look something like this now:

2014-03-27 21_02_01-Java - Hangman_res_layout_main.xml - Eclipse

Right now, clicking on the button won’t do anything. To add a click handler to the button, you have to go to the MainActivity.java file. Let’s create a new method called attachNextButton().

private void attachNextButton()
{
    Button btnNext = (Button)findViewById(R.id.btnNext);
    btnNext.setOnClickListener(new OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
             newGame();
        }
    });
}

This code simply looks up the button (using the id “btnNext” that we just defined), and sets a clickListener, which then calls newGame, which we’ll define in a second. Then in the onCreate() method, we want to call attachNextButton().

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

    phraseGenerator = new PhraseGenerator(this);
    TextView txtPhrase = (TextView)findViewById(R.id.txtPhrase);
    txtPhrase.setText(phraseGenerator.nextPhrase());
}

Let’s now define the method “newGame()”. This will be called when a user clicks on the “Next” button, but will also be called in a later lesson when the user completes (or loses) the current phrase.

private void newGame()
{
    TextView txtPhrase = (TextView)findViewById(R.id.txtPhrase);
    txtPhrase.setText(phraseGenerator.nextPhrase());
}

To make sure we got everything, I’ve listed the whole file for MainActivity below:

package com.famlinkup.hangman;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity
{
    PhraseGenerator phraseGenerator;

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

        phraseGenerator = new PhraseGenerator(this);
        TextView txtPhrase = (TextView)findViewById(R.id.txtPhrase);
        txtPhrase.setText(phraseGenerator.nextPhrase());
    }

    private void attachNextButton()
    {
        Button btnNext = (Button)findViewById(R.id.btnNext);
        btnNext.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                newGame();
            }
        });
    }

    private void newGame()
    {
        TextView txtPhrase = (TextView)findViewById(R.id.txtPhrase);
        txtPhrase.setText(phraseGenerator.nextPhrase());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        int id = item.getItemId();
        if (id == R.id.action_settings)
        {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Now you can deploy it and test out the button to make sure it works. In the next lesson, we will work on hiding the letters like real hangman and showing a “_” for all the letters.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s