Lesson Monday

Up until this point, we've built user interfaces with activities and adapters primarily, before getting some exposure to Fragments with the lesson on creating a Dialog Fragment. To review, we can consider Fragments the Components of the Android world -- they function similarly to how a component would inside a JS framework such as Angular, for example.

This allows us to move some of our design and functionality out of our activities and into smaller, more modular and reusable pieces. Fragments seem daunting at first, as they are definitely trickier to work with than Activities, but the effort in learning and utilizing how to craft and employ custom fragments is the key to an efficient, responsive application that is in line with current development standards!

In this lesson we'll add a RestaurantDetailActivity fragment and corresponding layout to our ongoing MyRestaurants application. This fragment will be responsible for displaying details about a restaurant when the user clicks one in our ListView. Let's get started.

Required Reading

Before we begin, read Code Path's article Creating and Using Fragments for a brief overview of the functionality fragments offer, and how they may be implemented.

Fragments in MyRestaurants

Refactoring Activity Names

First, we'll refactor RestaurantsActivity to RestaurantListActivity so that we can easily distinguish it from our detail activity. Right click on RestaurantsActivity and select Refactor > Rename....

Creating a Detail Activity

Next, let's create an Empty activity in our ui package called RestaurantDetailActivity. Select the option to generate a layout file. In the corresponding layout, add the following:

activity_restaurant_detail.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.epicodus.myrestaurants.ui.RestaurantDetailActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v4.view.PagerTabStrip
            android:id="@+id/pagerHeader"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingBottom="4dp"
            android:paddingTop="4dp" />

    </android.support.v4.view.ViewPager>

</RelativeLayout>
  • The ViewPager will act as a container to hold our fragment.

  • The PagerTabStrip will create a header at the top of our ViewPager which will eventually display the current restaurant's name.

Creating Fragments

Let’s create our fragment now. We can right click on our ui sub-package, and select New > Fragment(Blank). We'll call it RestaurantDetailFragment. Leave Create layout XML? option checked, but be sure to uncheck Include fragment factory methods? and Include interface callbacks? as these options will create unnecessary boilerplate code.

create-blank-fragment

create-blank-fragment-options

Detail View Layout

In the corresponding layout, let's design our detail view. Our layout will integrate icons next to restaurant phone numbers, addresses, and websites.

Downloading and Adding Icons

Download the Google Material icons listed below. Or, feel free to browse the entire collection here. For each icon, select the white, 24dp PNG file.

Each of these downloads will provide a folder containing several subdirectories. In the Android sub-directory you'll see five additional sub-directories: drawable-hdpi, drawable-mhdpi, drawable-xhdpi, drawable-xxhdpi and drawable-xxxhdpi. hdpi stands for "high dot per inch". Each of these represents a different size icon.

In upcoming lessons, we'll learn about Alternative Resources and implement them into our project. Alternative resources support different device configurations, like screen size, or orientation. We'll need multiple icon sizes for our Alternative Resources, so we'll include each size of all three icons in our project now.

Copy/paste or drag/drop the drawable-hdpi, drawable-mhdpi, drawable-xhdpi, drawable-xxhdpi and drawable-xxxhdpi directories from one of the icon folder's into our project's res directory. Then, also place the individual .PNG files of the other two icons in the sub-directories corresponding to their size. Once completed, res should be organized like this:

icons-organized-by-size

We can now implement these icons into our layout. The finished product will look like this:

fragment_restaurant_detail.xml
<FrameLayout 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"
    tools:context="com.epicodus.myrestaurants.ui.RestaurantDetailFragment">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorPrimary">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="180dp"
            android:id="@+id/restaurantImageView"
            android:src="@drawable/waffles"
            android:scaleType="centerCrop" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white"
            android:paddingTop="20dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingBottom="20dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Restaurant Name"
                android:id="@+id/restaurantNameTextView"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:textSize="20sp"
                android:textColor="@color/colorPrimaryDark"
                android:textStyle="bold" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="4.5/5"
                android:id="@+id/ratingTextView"
                android:layout_alignTop="@+id/restaurantNameTextView"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true"
                android:textColor="@color/colorAccent"
                android:textStyle="bold" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Brunch, American"
                android:id="@+id/cuisineTextView"
                android:layout_below="@+id/restaurantNameTextView"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:textColor="@color/colorSecondaryText"
                android:textStyle="italic" />
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <LinearLayout
                android:orientation="vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_above="@+id/saveRestaurantButton"
                android:paddingLeft="30dp"
                android:paddingTop="20dp"
                android:paddingRight="30dp">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="View Online"
                    android:id="@+id/websiteTextView"
                    android:drawableLeft="@drawable/ic_exit_to_app_white_24dp"
                    android:drawablePadding="4dp"
                    android:textColor="@color/colorTextIcons"
                    android:textSize="15sp"
                    android:textStyle="bold"
                    android:layout_marginBottom="10dp"
                    android:gravity="center" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="(503) 223-1282"
                    android:id="@+id/phoneTextView"
                    android:drawableLeft="@drawable/ic_local_phone_white_24dp"
                    android:drawablePadding="4dp"
                    android:textColor="@color/colorTextIcons"
                    android:textSize="15sp"
                    android:textStyle="bold"
                    android:layout_marginBottom="10dp"
                    android:gravity="center"/>

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="123 SW Best Ever Ave. Portland, Oregon, 97222"
                    android:drawableLeft="@drawable/ic_map_white_24dp"
                    android:drawablePadding="4dp"
                    android:id="@+id/addressTextView"
                    android:textColor="@color/colorTextIcons"
                    android:textSize="15sp"
                    android:textStyle="bold"
                    android:layout_marginBottom="10dp"
                    android:gravity="center_vertical"/>

            </LinearLayout>

            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Save Restaurant"
                android:id="@+id/saveRestaurantButton"
                android:layout_alignParentBottom="true"
                android:background="@color/colorAccent"
                android:textColor="@color/colorTextIcons"
                android:textSize="15sp" />
        </RelativeLayout>
    </LinearLayout>
</FrameLayout>

A few additional notes about this layout:

  • Feel free to use a placeholder image in the ImageView.

  • android:gravity="center" is used inside the information TextViews to vertically center-align text next to its corresponding icon.

  • For the time being, the hard-coded fields you see above (such as android:text="123 SW Best Ever Ave. Portland, Oregon, 97222") will act as placeholders for our actual restaurant data.

In the next lesson, we'll use a tool called Parceler to fill these placeholders with the dynamic data we're collecting from Yelp's API.


Example GitHub Repo for MyRestaurants

Terminology


  • Fragments: Small pieces of user interfaces that can be embedded in activities or displayed by adapters.

  • hdpi: "dpi" stands for "dot per inch", and the "h" stands for "high". Essentially, higher-quality resolution.

Examples


Additional Resources