5.1: Drawables, Styles, and Themes

Contents:

In this chapter, you will learn how to reduce your code, increase its readability and ease of maintenance by applying common styles to your views, use drawable resources, and apply themes to your application.

What you should already KNOW

From the previous chapters you should be familiar with basic concepts of the Activity lifecycle, and how to:

  • Create and run apps in Android Studio.
  • Create and edit UI elements using the Layout Editor, XML, and code.
  • Add onClick functionality to a button.
  • Update views at runtime.
  • Add menu items with onClick functionality.
  • Pass data between activities using Intents.

What you will LEARN

In this practical, you will learn to:

  • Define a style.
  • Apply a style to a view.
  • Apply a theme to an activity or application both in XML and programmatically.
  • Use drawable resources.

What you will DO

  • Create a new Android app and add buttons and TextView views to the layout.
  • Create drawable resources in XML and use them as backgrounds for your buttons.
  • Apply styles to the UI elements of the application.
  • Add a menu item that changes the theme of the application to a low contrast "night mode."

App Overview

The "Scorekeeper" application consists of two sets of buttons and two text views used to keep track of the score for any point-based game with two players.

Preview for the Scorekeeper app in Day Mode Preview for the Scorekeeper app in Night Mode

Task 1: Create The Scorekeeper App

In this section, you will create your Android Studio project, modify the layout, and add onClick functionality to its buttons.

1.1 Create the "Scorekeeper" Project

  1. Start Android Studio and create a new Android Studio Project.
    • Name your project "Scorekeeper".
    • Accept the defaults for the Company Domain and Project location.
  2. Accept the default Minimum SDK.
  3. Choose the Empty Activity template.
  4. Accept the default name for the activity, make sure Generate Layout File is checked and click Finish.

1.2 Create the layout for the main activity

Define the root view:

  1. Open the layout file for the main activity.
  2. Delete the TextView that says "Hello World."
  3. Change the root view to a LinearLayout and add the following attributes (without removing the existing attributes):
    Attribute Value
    android:orientation "vertical"

Define the score containers:

  1. Inside the LinearLayout, add two RelativeLayout view groups (one to contain the score for each team) with the following attributes:
    Attribute Value
    android:layout_width "match_parent"
    android:layout_height "0dp"
    android:layout_weight "1"
    You may be surprised to see that the layout_height attribute is set to 0dp in these views. This is because we are using the "layout_weight" attribute to determine how much space these views take up in the parent layout. See the LinearLayout Documentation for more information.

Add views to your UI

  1. Add two ImageButton views (one for increasing the score and one for decreasing the score) and a TextView for displaying the score in between the buttons to each RelativeLayout.
  2. Add android:id attributes to the score TextViews and all of the ImageButtons.
  3. Add one more TextView to each RelativeLayout above the score to represent the Team Names. Box Diagram of Scorekeeper Views

Add vector assets

  1. Select File > New > Vector Asset to open the Vector Asset Studio.
  2. Click on the icon to change it to a list of material icon files. Select the Content category.
  3. Choose the plus icon and click OK.
  4. Rename the resource file "ic_plus" and check the Override checkbox next to size options.
  5. Change the size of the icon to 40dp x 40dp.
  6. Click Next and then Finish.
  7. Repeat this process to add a "minus" icon and name the file "ic_minus".

Add attributes to your views

  1. Change the score text views to read "0" and the team text views to read "Team 1" and "Team 2".
  2. Add the following attributes to your left image buttons:
    android:src="@drawable/ic_minus"
    android:contentDescription="Minus Button"
    
  3. Add the following attributes to your right image buttons:
    android:src="@drawable/ic_plus"
    android:contentDescription="Plus Button"
    
  4. Extract all of your string resources. This process removes all of your strings from the Java code and puts them in the string.xml file. This allows for your app to be easily localized into different languages. To learn how to extract string resources, see the Extracting Resources section in the Appendix. Scorekeeper application in progress

Solution Code:

Note: Your code may be a little different as there are multiple ways to achieve the same layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   tools:context="com.example.android.scorekeeper.MainActivity">

   <RelativeLayout
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1">

       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentTop="true"
           android:layout_centerHorizontal="true"
           android:text="@string/team_1"/>

       <ImageButton
         android:id="@+id/decreaseTeam1"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentLeft="true"
           android:layout_alignParentStart="true"
           android:layout_centerVertical="true"
           android:contentDescription="@string/minus_button"
           android:src="@drawable/ic_minus" />

       <TextView
           android:id="@+id/score_1"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_centerHorizontal="true"
           android:layout_centerVertical="true"
           android:text="@string/initial_count"/>

       <ImageButton
           android:id="@+id/increaseTeam1"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentEnd="true"
           android:layout_alignParentRight="true"
           android:layout_centerVertical="true"
           android:contentDescription="@string/plus_button"
           android:src="@drawable/ic_plus"/>
   </RelativeLayout>

   <RelativeLayout
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1">

       <TextView
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentTop="true"
           android:layout_centerHorizontal="true"
           android:text="@string/team_2"/>

       <ImageButton
           android:id="@+id/decreaseTeam2"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentLeft="true"
           android:layout_alignParentStart="true"
           android:layout_centerVertical="true"
           android:contentDescription="@string/minus_button"
           android:src="@drawable/ic_minus"/>

       <TextView
           android:id="@+id/score_2"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_centerHorizontal="true"
           android:layout_centerVertical="true"
           android:text="@string/initial_count"/>

       <ImageButton
           android:id="@+id/increaseTeam2"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_alignParentEnd="true"
           android:layout_alignParentRight="true"
           android:layout_centerVertical="true"
           android:contentDescription="@string/plus_button"
           android:src="@drawable/ic_plus"/>
   </RelativeLayout>
</LinearLayout>

1.3 Initialize your TextViews and score count variables

In order to keep track of the scores, you will need two things:

  • Integer variables so you can keep track of the scores.
  • A reference to your score TextViews in MainActivity so you can update the scores.
  • In the onCreate() method of MainActivity, find your score TextViews by id and assign them to member variables.
  • Create two integer member variables, representing the score of each team, and initialize them to 0.

1.4 Implement the onClick functionality for your buttons

  1. In your MainActivity implement two onClick methods: increaseScore() and decreaseScore().

    Note: onClick methods all have the same signature - they return void and take a View as an argument.
  2. The left buttons should decrement the score TextView, while the right ones should increment it.

Solution Code:

Note: You must also add the android:onClick attribute to every button in the activity_main.xml file. You can identify which button was clicked by calling view.getId() in the onClick methods.
/**
* Method that handles the onClick of both the decrement buttons
* @param view The button view that was clicked
*/
public void decreaseScore(View view) {
   //Get the ID of the button that was clicked
   int viewID = view.getId();
   switch (viewID){
       //If it was on Team 1
       case R.id.decreaseTeam1:
           //Decrement the score and update the TextView
           mScore1--;
           mScoreText1.setText(String.valueOf(mScore1));
           break;
       //If it was Team 2
       case R.id.decreaseTeam2:
           //Decrement the score and update the TextView
           mScore2--;
           mScoreText2.setText(String.valueOf(mScore2));
   }
}

/**
* Method that handles the onClick of both the increment buttons
* @param view The button view that was clicked
*/
public void increaseScore(View view) {
   //Get the ID of the button that was clicked
   int viewID = view.getId();
   switch (viewID){
       //If it was on Team 1
       case R.id.increaseTeam1:
           //Increment the score and update the TextView
           mScore1++;
           mScoreText1.setText(String.valueOf(mScore1));
           break;
       //If it was Team 2
       case R.id.increaseTeam2:
           //Increment the score and update the TextView
           mScore2++;
           mScoreText2.setText(String.valueOf(mScore2));
   }
}

Task 2: Create a Drawable resource

You now have a functioning scorekeeper application! However, the layout is dull and does not communicate the function of the buttons. In order to make it more clear, the standard grey background of the buttons can be changed.

In Android, graphics are often handled by a resource called a Drawable. In the following exercise you will learn how to create a certain type of drawable called a ShapeDrawable, and apply it to your buttons as a background.

For more information on Drawables, see Drawable Resource Documentation.

2.1 Create a Shape Drawable

A ShapeDrawable is a primitive geometric shape defined in an xml file by a number of attributes including color, shape, padding and more. It defines a vector graphic, which can scale up and down without losing any definition.

  1. Right click on the drawable folder in your resources directory.
  2. Choose New > Drawable resource file.
  3. Name the file "button_background" and click OK.
  4. Remove all of the code except:
    <?xml version="1.0" encoding="utf-8"?>
    
  5. Add the following code which creates an oval shape with an outline:
    <shape
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
            <stroke
                android:width="2dp"
                android:color="@color/colorPrimary"/>
    </shape>
    

2.2 Apply the shape drawable as a background

  1. Open the layout file for your main activity.
  2. For all of the buttons, add the drawable as the background: android:background="@drawable/button_background". Note that the background automatically scales to fit the size of the view.
  3. The size of the buttons needs to be such that it renders properly on all devices. Change the "layout_height" and "layout_width" attributes for each button to 70dp, which is a good size on most devices. It is not best practice to use hard-coded dimensions, but using weights with nested linear layouts to achieve the desired size is too much detail for this practical.
    android:layout_width="70dp"
    android:layout_height="70dp"
    
  4. Extract the dimension resource so you can access it in one location. For information on how to do this, see the Appendix.
  5. Run your app.

Task 3: Style your views

As you continue to add views and attributes to your layout, your code will start to become large and repetitive, especially when you apply the same attributes to many similar elements. A style can specify common properties such as padding, font color, font size, and background color. Attributes that are layout-oriented such as height, width and relative location should remain in the layout resource file.

In the following exercise, you will learn how to create styles and apply them to multiple views and layouts, allowing common attributes to be updated simultaneously from one location.

Note: Styles are meant for attributes that modify the look of the view. Layout parameters such as height, weight and relative location should stay in the layout file.

3.1 Create button styles

In Android, styles can inherit properties from other styles. You can declare a parent for your style using an optional "parent" parameter and has the following properties:

  • Any style attributes defined by the parent style are automatically included in the child style.
  • A style attribute defined in both the parent and child style uses the child style's definition (the child overrides the parent).
  • A child style can include additional attributes that the parent does not define.

For example, all four buttons in this example share a common background drawable but with different icons for plus and minus. Furthermore, the two increment buttons share the same icon, as do the two decrement buttons. You can therefore create 3 styles:

  1. A score button style for all of the buttons, which includes the default properties of an ImageButton view and also the drawable background.
  2. A minus button style for the decrement buttons, which inherits the attributes of the previous style and also includes the minus icon.
  3. A plus button style for the decrement buttons, again inheriting from the score button style and also includes the plus icon.

These styles are represented in the figure below. Diagram of Common Styles

Do the following:

  1. In your resources directory, locate and open the "values/styles.xml" file. This is where all of your style code will be located. The "AppTheme" style is always automatically added, and you can see that it extends from "Theme.AppCompat.Light.DarkActionBar".
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    
    Note the "parent" attribute, which is how you specify your parent style using XML. The name attribute, in this case "AppTheme", defines the name of the style. The parent attribute, in this case "Theme.AppCompat.Light.DarkActionBar", declares the parent style attributes which "AppTheme" inherits. In this case it is the Android default theme, with a light background and a dark action bar. A theme is a style that is applied to an entire activity or application, instead of a single view. This allows for a consistent style throughout an entire activity or application (such as a consistent look and feel for the App Bar in every part of your application).
  2. In between the <resources> tags, add a new style with the following attributes to create a common style for all buttons:
    • Set the parent style to "Widget.AppCompat.Button" to retain the default attributes of a button.
    • Add an attribute that changes the background of the drawable to the one you created in the previous task.
      <style name="ScoreButtons" parent="Widget.AppCompat.Button">
          <item name="android:background">@drawable/button_background</item>
      </style>
      
  3. Create the style for the plus buttons by extending the "ScoreButtons" style:

    <style name="PlusButtons" parent="ScoreButtons">
        <item name="android:src">@drawable/ic_plus</item>
        <item name="android:contentDescription">@string/plus_button</item>
    </style>
    
    Note: The contentDescription attribute is for visually impaired users. It acts as a label that certain accessibility devices use to read out loud to provide some context about the meaning of the UI element.
  4. Create the style for the minus buttons:

    <style name="MinusButtons" parent="ScoreButtons">
        <item name="android:src">@drawable/ic_minus</item>
        <item name="android:contentDescription">@string/minus_button</item>
    </style>
    
  5. In the layout file for the main activity, remove all of the attributes that you defined in the styles for each button and replace them with the appropriate style:
    style="@style/MinusButtons"
    style="@style/PlusButtons"
    
    Note: The style attribute does not use the "android:" namespace, because it is part of the default XML attributes.

3.2 Create TextView styles

The team name and score display text views can also be styled since they have common colors and fonts. Do the following:

  1. Add the following attribute to all TextViews:
    android:textAppearance="@style/TextAppearance.AppCompat.Headline"
    
  2. Right-click anywhere in the first score TextView attributes and choose Refactor > Extract > Style…
  3. Name the style "ScoreText" and check the textAppearance box (the attribute you just added) as well as the Launch 'Use Styles Where Possible' refactoring after the style is extracted (using the checkboxes). This will scan the layout file for views with the same attributes and apply the style for you. Do not extract the attributes that are related to the layout.
  4. Choose OK.
  5. Make sure the scope is set to the activity_main.xml layout file and click OK.
  6. A pane at the bottom of Android Studio will open if the same style is found in other views. Select Do Refactor to apply the new style to the views with the same attributes.
  7. Run your app. There should be no change except that all of your styling code is now in your resources file and your layout file is shorter.

Solution Code:

styles.xml

<resources>
   <!-- Base application theme. -->
   <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
       <!-- Customize your theme here. -->
       <item name="colorPrimary">@color/colorPrimary</item>
       <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
       <item name="colorAccent">@color/colorAccent</item>
   </style>

   <style name="ScoreButtons" parent="AppTheme">
       <item name="android:background">@drawable/button_background</item>
   </style>

   <style name="PlusButtons" parent="ScoreButtons">
       <item name="android:src">@drawable/ic_plus</item>
       <item name="android:contentDescription">@string/plus_button</item>
   </style>

   <style name="MinusButtons" parent="ScoreButtons">
       <item name="android:src">@drawable/ic_minus</item>
       <item name="android:contentDescription">@string/minus_button</item>
   </style>

   <style name="ScoreText">
       <item name="android:textAppearance">@style/TextAppearance.AppCompat.Headline</item>
   </style>
</resources>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
   android:paddingBottom="@dimen/activity_vertical_margin"
   android:paddingLeft="@dimen/activity_horizontal_margin"
   android:paddingRight="@dimen/activity_horizontal_margin"
   android:paddingTop="@dimen/activity_vertical_margin"
   android:weightSum="2"
   tools:context="com.example.android.scorekeeper.MainActivity">

   <RelativeLayout
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1">

       <TextView
           android:layout_height="wrap_content"
           android:layout_width="wrap_content"
           android:layout_alignParentTop="true"
           android:layout_centerHorizontal="true"
           android:text="@string/team_1"
           style="@style/ScoreText" />

       <ImageButton
           android:id="@+id/decreaseTeam1"
           android:layout_height="@dimen/button_size"
           android:layout_width="@dimen/button_size"
           android:layout_alignParentLeft="true"
           android:layout_alignParentStart="true"
           android:layout_centerVertical="true"
           android:onClick="decreaseScore"
           style="@style/MinusButtons"/>

       <TextView
           android:layout_height="wrap_content"
           android:layout_width="wrap_content"
           android:layout_centerVertical="true"
           android:layout_centerHorizontal="true"
           android:id="@+id/score_1"
           android:text="@string/initial_count"
           style="@style/ScoreText" />

       <ImageButton
           android:id="@+id/increaseTeam1"
           android:layout_height="@dimen/button_size"
           android:layout_width="@dimen/button_size"
           android:layout_alignParentRight="true"
           android:layout_alignParentEnd="true"
           android:layout_centerVertical="true"
           android:onClick="increaseScore"
           style="@style/PlusButtons"/>

   </RelativeLayout>

   <RelativeLayout
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1">

       <TextView
           android:layout_height="wrap_content"
           android:layout_width="wrap_content"
           android:layout_alignParentTop="true"
           android:layout_centerHorizontal="true"
           android:text="@string/team_2"
           style="@style/ScoreText" />

       <ImageButton
           android:id="@+id/decreaseTeam2"
           android:layout_height="@dimen/button_size"
           android:layout_width="@dimen/button_size"
           android:layout_alignParentLeft="true"
           android:layout_alignParentStart="true"
           android:layout_centerVertical="true"
           android:onClick="decreaseScore"
           style="@style/MinusButtons"/>

       <TextView
           android:layout_height="wrap_content"
           android:layout_width="wrap_content"
           android:layout_centerVertical="true"
           android:layout_centerHorizontal="true"
           android:id="@+id/score_2"
           android:text="@string/initial_count"
           style="@style/ScoreText" />

       <ImageButton
           android:id="@+id/increaseTeam2"
           android:layout_height="@dimen/button_size"
           android:layout_width="@dimen/button_size"
           android:layout_alignParentRight="true"
           android:layout_alignParentEnd="true"
           android:layout_centerVertical="true"
           android:onClick="increaseScore"
           style="@style/PlusButtons"/>
   </RelativeLayout>
</LinearLayout>

3.3 Updating the styles

The power of using styles becomes apparent when you want to make changes to several elements of the same style. You can make the text bigger, bolder and brighter, and change the icons to the color of the button backgrounds.

Make the following changes in your styles.xml file:

  1. Add or modify each of the following attributes in the specified style block:

    Attribute Style Block
    @color/colorPrimary ScoreButtons
    @style/TextAppearance.AppCompat.Display3 ScoreText

    Note: The colorPrimary value is automatically generated by Android Studio when you create the project and can be found in the values/colors.xml file. The TextAppearance.AppCompat.Display3 attribute is a predefined text style supplied by Android.
  2. Create a new style called "TeamText" with the following attribute:

    <item name="android:textAppearance">@style/TextAppearance.AppCompat.Display1</item>
    
  3. Change the style attribute of the team name TextViews to the newly created TeamText style in activity_main.xml.
  4. Run your app. With only these adjustments to the style.xml file, all of the views updated to reflect the changes.

Task 4: Themes and Final Touches

You've seen that views with similar characteristics can be styled together in the "styles.xml" file. But what if you want to define styles for an entire activity, or even application? It's possible to accomplish this by using "Themes". To set a theme for an Activity or set of Activities, you need to modify the AndroidManifest.xml file.

In this task, you will add the "night mode" theme to your app, which will allow the users to use a low contrast version of your app that is easier on the eyes at night time, as well as make a few polishing touches to the User Interface.

4.1 Explore themes

  1. In the Android manifest file, find the <application> tag and change the android:themeattribute to:

    android:theme="@style/Theme.AppCompat.Light.NoActionBar"
    

    This is a predefined theme that removes the action bar from your activity.

  2. Run your app. The toolbar disappears!

  3. Change the theme of the application back to AppTheme, which is a child of the Theme.Appcompat.Light.DarkActionBar theme as can be seen in styles.xml.

To apply a theme to an activity instead of the entire application, place the theme attribute in the activity tag instead of the application tag. For more information on Themes and Styles, see the Style and Theme Guide.

4.2 Add theme button to the menu

One use for setting a theme for your application is to provide an alternate visual experience for browsing at night. In such conditions, it is often better to have a low contrast, dark layout. The Android framework provides a theme that is designed exactly for this: The DayNight theme. This theme has several built in options that allow you to control the colors in your app programmatically: either by setting it to change automatically by time, or by user command.
In this exercise you will add a menu button that will toggle the application between the regular theme and a "night-mode" theme.

  1. Right click on the "res" directory and choose New > Android resource file.
  2. Name the file "main_menu", change the Resource Type to Menu, and click OK.
  3. Add a menu item with the following attributes:
    <item
        android:id="@+id/night_mode"
        android:title="@string/night_mode"/>
    
  4. Navigate to "strings.xml" and create two string resources:
    <string name="night_mode">Night Mode</string>
    <string name="day_mode">Day Mode</string>
    
  5. Press Ctrl - O to open the Override Method menu in your main activity Java file, and select the onCreateOptionsMenu method located under the "android.app.Activity" category. Click OK.
  6. Inflate the menu you just created within the onCreateOptionsMenu() method:
    getMenuInflater().inflate(R.menu.main_menu, menu);
    

4.3 Change the theme from the menu

The DayNight theme uses the AppCompatDelegate class to set the night mode options in your activity. To learn more about this theme, visit this blog post.

  1. In your styles.xml file, modify the parent of AppTheme to "Theme.AppCompat.DayNight.DarkActionBar.
  2. Override the onOptionsItemSelected() method in MainActivity, and check which menu item was clicked:
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
       //Check if the correct item was clicked
       if(item.getItemId()==R.id.night_mode){}
    }
    
  3. In response to a click on the menu button, you can verify the current night mode setting by calling AppCompatDelegate.getDefaultNightMode().
  4. If the night mode is enabled, change it to the disabled state:
    //Get the night mode state of the app
    int nightMode = AppCompatDelegate.getDefaultNightMode();
    //Set the theme mode for the restarted activity
    if(nightMode == AppCompatDelegate.MODE_NIGHT_YES) {
       AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
    }
    
  5. Otherwise, enable it:
    else {
       AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
    }
    
  6. The theme can only change while the activity is being created, so call recreate() for the theme change to take effect.
  7. Your onOptionsItemSelected() method should return true, since the item click was handled.
  8. Run your app. The "Night Mode" menu item should now toggle the theme of your activity. You may notice that the label for your menu item always reads "Night Mode", which may be confusing to your user if the app is already in the dark theme.
  9. Add the following code in the onCreateOptionsMenu method:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       //Inflate the menu from XML
       getMenuInflater().inflate(R.menu.main_menu, menu);
    
       //Change the label of the menu based on the state of the app
       int nightMode = AppCompatDelegate.getDefaultNightMode();
       if(nightMode == AppCompatDelegate.MODE_NIGHT_YES){
           menu.findItem(R.id.night_mode).setTitle(R.string.day_mode);
       } else{
           menu.findItem(R.id.night_mode).setTitle(R.string.night_mode);
       }
       return true;
    }
    
  10. Run your app. The menu button label now changes with the theme.

4.4 SaveInstanceState

You learned in previous lessons that you must be prepared for your activity to be destroyed and recreated at unexpected times, for example when your screen is rotated. In this application, the TextViews containing the scores are reset to the initial value of 0 when the device is rotated. To fix this, Do the following:

  1. Override the onSaveInstanceState() method in MainActivity to preserve the values of the two score TextViews:
    @Override
    protected void onSaveInstanceState(Bundle outState) {
       //Save the scores
       outState.putInt(STATE_SCORE_1, mScore1);
       outState.putInt(STATE_SCORE_2, mScore2);
       super.onSaveInstanceState(outState);
    }
    
  2. In the onCreate() method of MainActivity.java, check if there is a savedInstanceState. If there is, restore the scores to the text views:

    if (savedInstanceState != null) {
        mScore1 = savedInstanceState.getInt(STATE_SCORE_1);
        mScore2 = savedInstanceState.getInt(STATE_SCORE_2);
    
        //Set the score text views
        mScoreText1.setText(String.valueOf(mScore1));
        mScoreText2.setText(String.valueOf(mScore2));
    }
    

That's it! Congratulations, you now have a styled Scorekeeper Application.

Solution code

Android Studio project: Scorekeeper

Coding challenge

Note: All coding challenges are optional and are not prerequisites for later lessons.

Challenge: Right now, your buttons do not behave intuitively because they do not change their appearance when they are pressed. Android has another type of drawable called StateListDrawable which allows for a different graphic to be used depending on the state of the object.

For this challenge problem, create a drawable resource that changes the background of the button to the same color as the border when the state of the button is "pressed". You should also set the color of the text inside the buttons to a selector that makes it white when the button is "pressed".

Summary

  • A ShapeDrawable is a primitive geometric shape defined in an xml file by a number of attributes including color, shape, padding and more.
    • Drawables enhance the look of an application.
  • A Style can specify common properties such as height, padding, font color, font size, background color, et al.
    • Using styles can reduce the amount of common code for your UI components.
    • Style should not include layout-related information.
    • Styles can be applied to View, Activities or Applications.
      • Style applied to Activities or Applications must be defined in the Android Manifest XML file.
      • Styles can be inherited by identifying the parent style using XML.
  • When you apply a style to a collection of Views in an Activity or in your entire application, that is known as a Theme
    • Android:theme is the attribute you need to set a style on a collection of Views in an Activity or Application.
    • The Android platform supplies a large collection of styles and themes.

The related concept documentation is in Android Developer Fundamentals: Concepts.

Learn more

Developer Documentation:

Videos

results matching ""

    No results matching ""