1. Welcome
Introduction
Google's Material Design guidelines are a series of best practices for creating visually appealing and intuitive applications. In this practical you learn how to add CardView
and FloatingActionButton
widgets to your app, how to use images efficiently, and how to employ Material Design best practices to make your user's experience delightful.
What you should already know
You should be able to:
- Create and run apps in Android Studio.
- Create and edit UI elements using the layout editor.
- Edit XML layout code, and access elements from your Java code.
- Create a click handler for a
Button
click. - Extract text to a string resource and a dimension to a dimension resource.
- Use drawables, styles, and themes.
- Use a
RecyclerView
to display a list.
What you'll learn
- Recommended use of Material Design widgets such as
FloatingActionButton
andCardView
. - How to efficiently use images in your app.
- Recommended best practices for designing intuitive layouts using bold colors.
What you'll do
- Modify an app to follow Material Design guidelines.
- Add images and styling to a
RecyclerView
list. - Implement an
ItemTouchHelper
to add drag-and-drop functionality to your app.
2. App overview
The MaterialMe app is a mock sports-news app with very poor design implementation. You will fix it up to meet the design guidelines to create a delightful user experience! Below are screenshots of the app before and after the Material Design improvements.
3. Task 1: Download the starter code
The complete starter app project for this practical is available at MaterialMe-Starter. In this task you will load the project into Android Studio and explore some of the app's key features.
1.1 Open and run the MaterialMe project
- Download the MaterialMe-Starter code.
- Open the app in Android Studio.
- Run the app.
The app shows a list of sports names with some placeholder news text for each sport. The current layout and style of the app makes it nearly unusable: each row of data is not clearly separated and there is no imagery or color to engage the user.
1.2 Explore the app
Before making modifications to the app, explore its current structure. It contains the following elements:
Sport.java
This class represents the data model for each row of data in the RecyclerView
. Right now it contains a field for the title of the sport and a field for some information about the sport.
SportsAdapter.java
This is the adapter for the RecyclerView
. It uses an ArrayList
of Sport objects as its data and populates each row with this data.
MainActivity.java
The MainActivity
initializes the RecyclerView and adapter, and creates the data from resource files.
strings.xml
This resource file contains all of the data for the app, including the titles and information for each sport.
list_item.xml
This layout file defines each row of the RecyclerView
. It consists of three TextView
elements, one for each piece of data (the title and the info for each sport) and one used as a label.
4. Task 2: Add a CardView and images
One of the fundamental principles of Material Design is the use of bold imagery to enhance the user experience. Adding images to the RecyclerView
list items is a good start for creating a dynamic and captivating user experience.
When presenting information that has mixed media (like images and text), the Material Design guidelines recommend using a CardView
, which is a FrameLayout
with some extra features (such as elevation and rounded corners) that give it a consistent look and feel across many different applications and platforms. CardView
is a UI component found in the Android Support Libraries.
In this section, you will move each list item into a CardView
and add an Image
to make the app comply with Material guidelines.
2.1 Add the CardView
CardView
is not included in the default Android SDK, so you must add it as a build.gradle
dependency. Do the following:
- Open the build.gradle (Module: app) file, and add the following line to the
dependencies
section:
implementation 'com.android.support:cardview-v7:26.1.0'
The version of the support library may have changed since the writing of this practical. Update the above to the version suggested by Android Studio, and click Sync to sync your build.gradle
files.
- Open the list_item.xml file, and surround the root
LinearLayout
withandroid.support.v7.widget.CardView
. Move the schema declaration (xmlns:android="http://schemas.android.com/apk/res/android
) to theCardView
, and add the following attributes:
Attribute | Value |
|
|
|
|
|
|
The schema declaration needs to move to the CardView
because the CardView
is now the top-level view in your layout file.
- Choose Code > Reformat Code to reformat the XML code, which should now look like this at the beginning and end of the file:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Rest of LinearLayout -->
<!-- TextView elements -->
</LinearLayout>
</android.support.v7.widget.CardView>
- Run the app. Now each row item is contained inside a
CardView
, which is elevated above the bottom layer and casts a shadow.
2.2 Download the images
The CardView
is not intended to be used exclusively with plain text: it is best for displaying a mixture of content. You have a good opportunity to make this app more exciting by adding banner images to every row!
Using images is resource intensive for your app: the Android framework has to load the entire image into memory at full resolution, even if the app only displays a small thumbnail of the image.
In this section you learn how to use the Glide library to load large images efficiently, without draining your resources or even crashing your app due to ‘Out of Memory' exceptions.
- Download the banner images zip file.
- Open the MaterialMe > app > src > main > res directory in your operating system's file explorer, and create a drawable directory, and copy the individual graphics files into the drawable directory.
- You need an array with the path to each image so that you can include it in the
Sports
object. To do this, define an array that contains all of the paths to the drawables as items in yourstring.xml
file. Be sure to that they are in the same order as thesports_titles
array also defined in the same file:
<array name="sports_images">
<item>@drawable/img_baseball</item>
<item>@drawable/img_badminton</item>
<item>@drawable/img_basketball</item>
<item>@drawable/img_bowling</item>
<item>@drawable/img_cycling</item>
<item>@drawable/img_golf</item>
<item>@drawable/img_running</item>
<item>@drawable/img_soccer</item>
<item>@drawable/img_swimming</item>
<item>@drawable/img_tabletennis</item>
<item>@drawable/img_tennis</item>
</array>
2.3 Modify the Sport object
The Sport
object will need to include the Drawable
resource that corresponds to the sport. To achieve that:
- Add an integer member variable to the
Sport
object that will contain theDrawable
resource:
private final int imageResource;
- Modify the constructor so that it takes an integer as a parameter and assigns it to the member variable:
public Sport(String title, String info, int imageResource) {
this.title = title;
this.info = info;
this.imageResource = imageResource;
}
- Create a getter for the resource integer:
public int getImageResource() {
return imageResource;
}
2.4 Fix the initializeData() method
In MainActivity
, the initializeData()
method is now broken, because the constructor for the Sport
object demands the image resource as the third parameter.
A convenient data structure to use would be a TypedArray
. A TypedArray
allows you to store an array of other XML resources. Using a TypedArray
, you can obtain the image resources as well as the sports title and information by using indexing in the same loop.
- In the
initializeData()
method, get theTypedArray
of resource IDs by callinggetResources().obtainTypedArray()
, passing in the name of the array ofDrawable
resources you defined in yourstrings.xml
file:
TypedArray sportsImageResources =
getResources().obtainTypedArray(R.array.sports_images);
You can access an element at index i
in the TypedArray
by using the appropriate "get" method, depending on the type of resource in the array. In this specific case, it contains resource IDs, so you use the getResourceId()
method.
- Fix the code in the loop that creates the
Sport
objects, adding the appropriateDrawable
resource ID as the third parameter by callinggetResourceId()
on theTypedArray
:
for(int i=0;i<sportsList.length;i++){
mSportsData.add(new Sport(sportsList[i],sportsInfo[i],
sportsImageResources.getResourceId(i,0)));
}
- Clean up the data in the typed array once you have created the
Sport
dataArrayList
:
sportsImageResources.recycle();
2.5 Add an ImageView to the list items
- Change the
LinearLayout
inside the list_item.xml file to aRelativeLayout
, and delete theandroid:orientation
attribute. - Add an
ImageView
as the first element within theRelativeLayout
with the following attributes:
Attribute | Value |
|
|
|
|
|
|
|
|
The adjustViewBounds
attribute makes the ImageView
adjust its boundaries to preserve the aspect ratio of the image.
- Add the following attributes to the
title
TextView
element:
Attribute | Value |
|
|
|
|
- Add the following attributes to the
newsTitle
TextView
element:
Attribute | Value |
|
|
|
|
- Add the following attributes to the
subTitle
TextView
element:
Attribute | Value |
|
|
The question mark in the above textColor
attribute ("?android:textColorSecondary"
) means that the framework will apply the value from the currently applied theme. In this case, this attribute is inherited from the "Theme.AppCompat.Light.DarkActionBar"
theme, which defines it as a light gray color, often used for subheadings.
2.6 Load the images using Glide
After downloading the images and setting up the ImageView
, the next step is to modify the SportsAdapter
to load an image into the ImageView
in onBindViewHolder()
. If you take this approach, you will find that your app crashes due to "Out of Memory" errors. The Android framework has to load the image into memory each time at full resolution, no matter what the display size of the ImageView
is.
There are a number of ways to reduce the memory consumption when loading images, but one of the easiest approaches is to use an Image Loading Library like Glide, which you will do in this step. Glide uses background processing, as well some other complex processing, to reduce the memory requirements of loading images. It also includes some useful features like showing placeholder images while the desired images are loaded.
- Open the build.gradle (Module: app) file, and add the following dependency for Glide in the
dependencies
section:
implementation 'com.github.bumptech.glide:glide:3.7.0'
- Open SportsAdapter, and add a variable in the
ViewHolder
class for theImageView
:
private ImageView mSportsImage;
- Initialize the variable in the
ViewHolder
constructor for theViewHolder
class:
mSportsImage = itemView.findViewById(R.id.sportsImage);
- Add the following line of code to the
bindTo()
method in theViewHolder
class to get the image resource from theSport
object and load it into theImageView
using Glide:
Glide.with(mContext).load(currentSport.getImageResource()).into(mSportsImage);
- Run the app, your list items should now have bold graphics that make the user experience dynamic and exciting!
That's all takes to load an image with Glide. Glide also has several additional features that let you resize, transform and load images in a variety of ways. Head over to the Glide GitHub page to learn more.
5. Task 3: Make your CardView swipeable, movable, and clickable
When users see cards in an app, they have expectations about the way the cards behave. Material Design offers the following guidelines:
- A card can be dismissed, usually by swiping it away.
- A list of cards can be reordered by holding down and dragging the cards.
- Tapping on card provides further details.
You now implement these behaviors in your app.
3.1 Implement swipe to dismiss
The Android SDK includes a class called ItemTouchHelper
that is used to define what happens to RecyclerView
list items when the user performs various touch actions, such as swipe, or drag and drop. Some of the common use cases are already implemented in a set of methods in ItemTouchHelper.SimpleCallback
.
ItemTouchHelper.SimpleCallback
lets you define which directions are supported for swiping and moving list items, and implement the swiping and moving behavior.
Do the following:
- Open MainActivity and create a new
ItemTouchHelper
object in theonCreate()
method at the end, below theinitializeData()
method. For its argument, you will create a new instance ofItemTouchHelper.SimpleCallback
. As you enter new ItemTouchHelper, suggestions appear. Select ItemTouchHelper.SimpleCallback{...} from the suggestion menu. Android Studio fills in the required methods:onMove()
andonSwiped()
as shown below.
ItemTouchHelper helper = new ItemTouchHelper(new
ItemTouchHelper.SimpleCallback() {
@Override
public boolean onMove(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder,
int direction) {
}
});
If the required methods were not automatically added, click on the red bulb in the left margin, and select Implement methods.
The SimpleCallback
constructor will be underlined in red because you have not yet provided the required parameters: the direction that you plan to support for moving and swiping list items, respectively.
- Because we are only implementing swipe to dismiss at the moment, you should pass in
0
for the supported move directions andItemTouchHelper.LEFT | ItemTouchHelper.RIGHT
for the supported swipe directions:
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper
.SimpleCallback(0, ItemTouchHelper.LEFT |
ItemTouchHelper.RIGHT) {
- You must now implement the desired behavior in
onSwiped()
. In this case, swiping the card left or right should delete it from the list. Callremove()
on the data set, passing in the appropriate index by getting the position from theViewHolder
:
mSportsData.remove(viewHolder.getAdapterPosition());
- To allow the
RecyclerView
to animate the deletion properly, you must also callnotifyItemRemoved()
, again passing in the appropriate index by getting the position from the ViewHolder:
mAdapter.notifyItemRemoved(viewHolder.getAdapterPosition());
- Below the new
ItemTouchHelper
object in theonCreate()
method forMainActivity
, callattachToRecyclerView()
on theItemTouchHelper
instance to add it to yourRecyclerView
:
helper.attachToRecyclerView(mRecyclerView);
- Run your app, you can now swipe list items left and right to delete them!
3.2 Implement drag and drop
You can also implement drag and drop functionality using the same SimpleCallback
. The first argument of the SimpleCallback
determines which directions the ItemTouchHelper
supports for moving the objects around. Do the following:
- Change the first argument of the SimpleCallback from 0 to include every direction, since we want to be able to drag and drop anywhere:
ItemTouchHelper helper = new ItemTouchHelper(new ItemTouchHelper
.SimpleCallback(ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT |
ItemTouchHelper.DOWN | ItemTouchHelper.UP, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
- In the
onMove()
method, get the original and target index from the second and third argument passed in (corresponding to the original and target view holders).
int from = viewHolder.getAdapterPosition();
int to = target.getAdapterPosition();
- Swap the items in the dataset by calling
Collections.swap()
and pass in the dataset, and the initial and final indexes:
Collections.swap(mSportsData, from, to);
- Notify the adapter that the item was moved, passing in the old and new indexes, and change the
return
statement totrue
:
mAdapter.notifyItemMoved(from, to);
return true;
- Run your app. You can now delete your list items by swiping them left or right, or reorder them using a long press to activate Drag and Drop mode.
3.3 Implement the DetailActivity layout
According to Material Design guidelines, a card is used to provide an entry point to more detailed information. You may find yourself tapping on the cards to see more information about the sports, because that is how you expect cards to behave.
In this section, you will add a detail Activity
that will be launched when any list item is pressed. For this practical, the detail Activity
will contain the name and image of the list item you clicked, but will contain only generic placeholder detail text, so you don't have to create custom detail for each list item.
- Create a new
Activity
by going to File > New > Activity > Empty Activity. - Call it DetailActivity, and accept all of the defaults.
- Open the newly created activity_detail.xml layout file and change the root
ViewGroup
toRelativeLayout
, as you've done in previous exercises. - Remove the
xmlns:app="http://schemas.android.com/apk/res-auto"
statement from theRelativeLayout
. - Copy all of the
TextView
andImageView
elements from the list_item.xml file to the activity_detail.xml file. - Add the word "Detail" to the reference in each
android:id
attribute in order to differentiate it fromlist_item.xml
IDs. For example, change theImageView
ID from sportsImage to sportsImageDetail. - In all
TextView
andImageView
elements, change all references to the IDs for relative placement suchlayout_below
to use the "Detail" ID. - For the
subTitleDetail
TextView
, remove the placeholder text string and paste a paragraph of generic text to substitute detail text (For example, a few paragraphs of Lorem Ipsum). Extract the text to a string resource. - Change the padding on the
TextView
elements to 16dp. - Wrap the entire
RelativeLayout
with aScrollView
. Add the requiredlayout_height
andlayout_width
attributes, and append thexmlns:android="http://schemas.android.com/apk/res/android"
attribute to the end of theScrollView
. - Change the
layout_height
attribute of theRelativeLayout
to"wrap_content"
.
The first two elements of the activity_detail.xml
layout should now look as follows:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.example.android.materialme.DetailActivity">
3.4 Implement the detail view and click listener
Follow these steps to implement the detail view and click listener:
- Open SportsAdapter and change the
ViewHolder
inner class, which already extendsRecyclerView.ViewHolder
, to also implementView.OnClickListener,
and implement the required method (onClick()
).
class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener{
// Rest of ViewHolder code.
//
@Override
public void onClick(View view) {
}
}
- Set the
OnClickListener
to theitemView
in theViewHolder
constructor. The entire constructor should now look like this:
ViewHolder(View itemView) {
super(itemView);
//Initialize the views
mTitleText = itemView.findViewById(R.id.title);
mInfoText = itemView.findViewById(R.id.subTitle);
mSportsImage = itemView.findViewById(R.id.sportsImage);
// Set the OnClickListener to the entire view.
itemView.setOnClickListener(this);
}
- In the
onClick()
method, get theSport
object for the item that was clicked usinggetAdapterPosition()
:
Sport currentSport = mSportsData.get(getAdapterPosition());
- In the same method, add an
Intent
that launchesDetailActivity
, put thetitle
andimage_resource
as extras in theIntent
, and callstartActivity()
on themContext
variable, passing in the newIntent
.
Intent detailIntent = new Intent(mContext, DetailActivity.class);
detailIntent.putExtra("title", currentSport.getTitle());
detailIntent.putExtra("image_resource",
currentSport.getImageResource());
mContext.startActivity(detailIntent);
- Open DetailActivity and initialize the
ImageView
andtitle
TextView
inonCreate()
:
TextView sportsTitle = findViewById(R.id.titleDetail);
ImageView sportsImage = findViewById(R.id.sportsImageDetail);
- Get the
title
from the incomingIntent
and set it to theTextView
:
sportsTitle.setText(getIntent().getStringExtra("title"));
- Use Glide to load the image into the
ImageView
:
Glide.with(this).load(getIntent().getIntExtra("image_resource",0))
.into(sportsImage);
- Run the app. Tapping on a list item now launches
DetailActivity
.
6. Task 4: Add the FAB and choose a Material Design color palette
One of the principles behind Material Design is using consistent elements across applications and platforms so that users recognize patterns and know how to use them. You have already used one such element: the Floating Action Button (FAB). The FAB is a circular button that floats above the rest of the UI. It is used to promote a particular action to the user, one that is very likely to be used in a given activity. In this task, you will create a FAB that resets the dataset to its original state.
4.1 Add the FAB
The Floating Action Button is part of the Design Support Library.
- Open the build.gradle (Module: app) file and add the following line of code for the design support library in the
dependencies
section:
implementation 'com.android.support:design:26.1.0'
- Add an icon for the FAB by right-clicking (or Control-clicking) the res folder in the Project > Android pane, and choosing New > Vector Asset. The FAB will reset the contents of the
RecyclerView
, so therefresh
icon should do:Change the name to ic_reset, click Next, and click Finish.
- Open activity_main.xml and add a
FloatingActionButton
with the following attributes:
Attribute | Value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- Open MainActivity and add the
resetSports()
method with a statement to callinitializeData()
to reset the data. - Run the app. You can now reset the data by tapping the FAB.
Because the Activity
is destroyed and recreated when the configuration changes, rotating the device resets the data in this implementation. In order for the changes to be persistent (as in the case of reordering or removing data), you would have to implement onSaveInstanceState()
or write the changes to a persistent source (like a database or SharedPreferences, which are described in other lessons).
4.2 Choose a Material Design palette
Material Design recommends picking at least these three colors for your app:
- A primary color. This one is automatically used to color your app bar (the bar that contains the title of your app).
- A primary dark color. A darker shade of the same color. This is used for the status bar above the app bar, among other things.
- An accent color. A color that contrasts well with the primary color. This is used for various highlights, but it is also the default color of the FAB.
When you ran your app, you may have noticed that the FAB color and app bar color are already set. In this task you will learn where these colors are set. You can use the Material Color Guide to pick some colors to experiment with.
- In the Project > Android pane, navigate to your styles.xml file (located in the values directory). The
AppTheme
style defines three colors by default:colorPrimary
,colorPrimaryDark
, andcolorAccent
. These styles are defined by values from thecolors.xml
file. - Pick a color from the Material Color Guide to use as your primary color, such as
#607D8B
(in the Blue Grey color swatch). It should be within the 300-700 range of the color swatch so that you can still pick a proper accent and dark color. - Open the colors.xml file, and modify the
colorPrimary
hex value to match the color you picked. - Pick a darker shade of the same color to use as your primary dark color, such as
#37474F
. Again, modify the colors.xml hex value forcolorPrimaryDark
to match. - Pick an accent color for your FAB from the colors whose values start with an A, and whose color contrasts well with the primary color (like Deep Orange A200). Change the
colorAccent
value in colors.xml to match. - Run the app. The app bar and FAB have now changed to reflect the new color palette!
If you want to change the color of the FAB to something other than theme colors, use the app:backgroundTint
attribute. Note that this uses the app:
namespace and Android Studio will prompt you to add a statement to define the namespace.
7. Solution code
Android Studio project: MaterialMe
8. Coding challenges
Coding challenge 1
This challenge consists of two small improvements to the MaterialMe app:
- Add real details to the
Sport
object and pass the details to theDetailActivity
. - Implement a way to ensure that the state of the app is persistent across orientation changes.
Coding challenge 2
Create an app with four images arranged in a grid in the center of your layout. Make the first three solid colored backgrounds with different shapes (square, circle, line), and the fourth the Android Material Design Icon. Make each of these images respond to clicks as follows:
- One of the colored blocks relaunches the
Activity
using theExplode
animation for both the enter and exit transitions. - Relaunch the
Activity
from another colored block, this time using theFade
transition. - Touching the third colored block starts an in-place animation of the
View
(such as a rotation). - Finally, touching the Android icon starts a secondary
Activity
with a Shared Element Transition swapping the Android block with one of the other blocks.
Challenge 2 solution code
Android Studio project: TransitionsandAnimations
9. Summary
- A
CardView
is a good layout to use for presenting information that has mixed media (such as images and text). CardView
is a UI component found in the Android Support Library.CardView
was not designed just for text childView
elements.- Loading images directly into an
ImageView
is memory intensive, because images are loaded at full resolution. To efficiently load images into your app, use an image loading library such as Glide. - The Android SDK has a class called
ItemTouchHelper
that helps your app get information about tap, swipe, and drag-and-drop events in your UI. - A
FloatingActionButton
(FAB) focuses the user on a particular action and "floats" in your UI. - Material Design is a set of guiding principles for creating consistent, intuitive, and playful applications.
- According to Material Design, it's good practice to choose three colors for your app: a primary color, a primary dark color, and an accent color.
- Material Design promotes the use of bold imagery and colors to enhance user experience. It also promotes consistent elements across platforms, for example by using
CardView
and FAB widgets. - Use Material Design to create meaningful, intuitive motion for UI elements such as cards that can be dismissed or rearranged.
10. Related concept
The related concept documentation is in 5.2: Material Design.
11. Learn more
Android Studio documentation:
- Android Studio User Guide
- Add multi-density vector graphics
- Create app icons with Image Asset Studio
Android developer documentation:
- User Interface & Navigation
- Linear Layout
FloatingActionButton
- Drawable Resources
- View Animation
- Support Library
- Animate Drawable Graphics
- Loading Large Bitmaps Efficiently
Material Design:
- Material Design for Android
- Material Design palette generator
- Create a List with RecyclerView
- App Bar
- Defining Custom Animations
Android Developers Blog: Android Design Support Library
Other:
12. Homework
This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:
- Assign homework if required.
- Communicate to students how to submit homework assignments.
- Grade the homework assignments.
Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.
If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.
Build and run an app
Open the MaterialMe app.
- Create a shared element transition between the
MainActivity
and theDetailActivity
, with the banner image for the sport as the shared element. - Clicking on a list item in the MaterialMe app triggers the transition. The banner image from the card moves to the top of the screen in the detail view.
Answer these questions
Question 1
Which color attribute in your style defines the color of the status bar above the app bar? Choose one:
colorPrimary
colorPrimaryDark
colorAccent
colorAccentDark
Question 2
Which support library does the FloatingActionButton
belong to? Choose one:
v4 Support Library
v7 Support Library
Design Support Library
Custom Button Support Library
Question 3
In the Material Design color palette, which shade of a color should you use as the primary color for your brand in your app? Choose one:
- Any color shade that starts with
A
. - Any color shade labeled
200
. - Any color shade labeled
500
. - Any color shade labeled
900
.
Submit your app for grading
Guidance for graders
Check that the app has the following features:
- Window-content transitions are enabled in the app theme.
- A shared element transition is specified in the app style.
- The transition is defined as an XML resource.
- A common name is assigned to the shared elements in both layouts with the
android:transitionName
attribute. - The code uses the
ActivityOptions.makeSceneTransitionAnimation()
method.
13. Next codelab
To find the next practical codelab in the Android Developer Fundamentals (V2) course, see Codelabs for Android Developer Fundamentals (V2).
For an overview of the course, including links to the concept chapters, apps, and slides, see Android Developer Fundamentals (Version 2).