This codelab is part of the Android Kotlin Fundamentals course. You'll get the most value out of this course if you work through the codelabs in sequence. All the course codelabs are listed on the Android Kotlin Fundamentals codelabs landing page.
You should be familiar with:
LinearLayout
in your app.ConstraintLayout
in your app to arrange views.The ColorMyViews app is inspired by the Dutch artist, Piet Mondrian. He invented a style of painting style called neoplasticism, which uses only vertical and horizontal lines and rectangular shapes in black, white, gray, and primary colors.
Although paintings are static, your app will be interactive! The app consists of clickable text views that change color when tapped, and button views in a constraintLayout
.
A ConstraintLayout
is a ViewGroup
that allows you to position and size child views in a flexible way. A constraint layout allows you to create large, complex layouts with flat view hierarchies (no nested view groups). To build a constraint layout, you can use the Layout Editor to add constraints, and to drag-and-drop views. You don't need to edit the XML.
A constraint is a connection or alignment between two UI elements. Each constraint connects or aligns one view to another view, to the parent layout, or to an invisible guideline. In a constraint layout, you position a view by defining at least one horizontal and one vertical constraint.
Horizontal constraint: B is constrained to stay to the right of A. (In a finished app, B would need at least one vertical constraint in addition to this horizontal constraint.)
Vertical constraint: C is constrained to stay below A. (In a finished app, C would need at least one horizontal constraint in addition to this vertical constraint.)
Attribute | Value |
Template | Empty Activity in the Phone and Tablet tab |
Application Name | ColorMyViews |
Company Name android |
|
Language | Kotlin |
Minimum API level | API 19: Android 4.4 (KitKat) |
This project will support instant apps | (Leave this box cleared) |
Use AndroidX artifacts | Select this box. |
The Empty Activity template creates a single empty activity in the Mainactivity.kt
file. The template also creates a layout file called activity_main.xml
. The layout uses ConstraintLayout
as its root view group, with a single TextView
as the layout's content.
In this task, you use the Android Studio Layout Editor to build a constraint layout for your app.
activity_main.xml
file and click the Design tab.Autoconnect is on. | |
Autoconnect is off—this is what you want for this codelab. |
16dp
. (The default is 8dp
.)16dp
, new constraints are created with this margin, so you don't have to add the margin each time you add a constraint. The view inspector, shown in the screenshot below, is a part of the Attributes pane. The view inspector includes controls for layout attributes such as constraints, constraint types, constraint bias, and view margins.
Constraint bias positions the view element along the horizontal and vertical axes. By default, the view is centered between the two constraints with a bias of 50%.
To adjust the bias, you can drag the bias sliders in the view inspector. Dragging a bias slider changes the view's position along the axis.
0
. The default margin was not automatically added, because this view was created before you changed the default margin.16dp
from the drop-down menu in the view inspector. For example, in the following screenshot you are adding layout_marginEnd
(layout_marginRight
).In the view inspector, the arrows inside the square represents the type of the constraint:
layout_marginStart
, and set the Resource name to margin_wide
.@dimen/margin_wide
, for the top and end margins.android:layout_marginStart="@dimen/margin_wide"
android:layout_marginTop="@dimen/margin_wide"
android:layout_marginEnd="@dimen/margin_wide"
fontFamily
and select the drop-down arrow roboto
.This adds a res/font
folder that contains a roboto.ttf
font file. Also, the @font/roboto
attribute is set for your text view.
res/values/dimens.xml
, and add the following dimension resource for the font size.<dimen name="box_text_size">24sp</dimen>
res/values/styles.xml
and add the following style, which you will use for the text view.<style name="whiteBox">
<item name="android:background">@android:color/holo_green_light</item>
<item name="android:textAlignment">center</item>
<item name="android:textSize">@dimen/box_text_size</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:fontFamily">@font/roboto</item>
</style>
In this style, the background color and the text color are set to default Android color resources. The font is set to Roboto. The text is center aligned and bolded, and the text size is set to box_text_size
.
box_one
, and set the value to Box One
.id
of the text view to box_one_text
. style
to @style/whiteBox
.android:fontFamily="@font/roboto"
attribute, because this font is present in the whiteBox
style.TextView
adapts to the different screen configurations.In this task, you add another text view below the box_one_text
. You constrain the new text view to box_one_text
and the layout's parent element.
activity_main.xml
file and switch to the Design tab. TextView
from the Palette pane directly into the design editor preview, as shown below. Place the text view below the box_one_text
, aligned with the left margin.Notice that when you hold the pointer over the constraint handle, the handle turns green and blinks.
Create a constraint that connects the top of the new text view to the bottom of the Box One text view:
Now create a left constraint:
res/values/strings.xml
. Add a new string resource with the following code:<string name="box_two">Box Two</string>
activity_main.xml
and click the Design tab. Use the Attributes pane to set the following attributes on the new text view: Attribute | value |
|
|
|
|
|
|
|
|
|
|
In this case, you're assigning fixed sizes for the height and width of the text view. Assign fixed sizes for height and width only if your view should always have a fixed size on all devices and layouts.
TextView
views, one above the other, similar to the following screenshot:In this task, you add three TextView
views. The text views are vertically aligned with each other, and horizontally aligned with the Box Two text view. The views will be in a chain.
A chain is a group of views that are linked to each other with bidirectional constraints. The views within a chain can be distributed either vertically or horizontally. For example, the following diagram shows two views that are constrained to each other, which creates a horizontal chain.
The first view in a chain is called the head of the chain. The attributes that are set on the head of the chain control, position, and distribute all the views in the chain. For horizontal chains, the head is the left-most view. For vertical chains, the head is the top-most view. In each of the two diagrams below, "A" is the head of the chain.
Chain styles define the way the chained views are spread out and aligned. You style a chain by assigning a chain style attribute, adding weight, or setting bias on the views.
There are three chains styles:
layout_constraintHorizontal_weight
or layout_constraintVertical_weight
attributes. For example, imagine a chain containing three views, A, B, and C. View A uses a weight of 1. Views B and C each use a weight of 2. The space occupied by views B and C is twice that of view A, as shown below.To add a chain style to a chain, set the layout_constraintHorizontal_chainStyle
or the layout_constraintVertical_chainStyle
attribute for the head of the chain. You can add chain styles in the Layout Editor, which you learn in this task.
Alternatively, you can add chain styles in the XML code. For example:
// Horizontal spread chain
app:layout_constraintHorizontal_chainStyle="spread"
// Vertical spread inside chain
app:layout_constraintVertical_chainStyle="spread_inside"
// Horizontal packed chain
app:layout_constraintHorizontal_chainStyle="packed"
activity_main.xml
file in the Design tab. Drag three TextView
views from the Palette pane into the design editor. Put all three new text views to the right of the Box Two text view, as shown below.strings.xml
file, add the following string resources for the names of the new text views:<string name="box_three">Box Three</string>
<string name="box_four">Box Four</string>
<string name="box_five">Box Five</string>
Attribute | Top text view | Middle text view | Bottom text view |
|
|
|
|
|
|
|
|
|
|
|
|
In the Component Tree, you see errors about missing constraints. You fix these errors later.
layout_width
attribute 0dp
, which is equivalent to changing the constraint type to Match Constraints.Use the Attributes pane to set Layout_margin attributes on the three text views to add spacing between them.
@dimen/margin_wide
for the start and end margins. Remove the other margins.@dimen/margin_wide
for the start, end, top, and bottom margins. Remove the other margins.@dimen/margin_wide
for the start and end margins. Remove the other margins.TextView
views. To see how the constraints behave on a wider screen, try running the app on a larger device or emulator, such as a Nexus 10.In this task, you make the ColorMyViews app a little more colorful. First you change the color of all the text views to white. Then you add a click handler that changes the view's color and the layout background color when the user taps it.
styles.xml
, inside the whiteBox
style, change the background color to white. The text views will start out white with white font, then change colors when the user taps them. <item name="android:background">@android:color/white</item>
MainActivity.kt
, after the onCreate()
function, add a function called makeColored()
. Use View
as the function's parameter. This view is the one whose color will change. private fun makeColored(view: View) {
}
Every view has a resource ID. The resource ID is the value assigned to the view's id
attribute in the layout file, activity_main.xml
. To set a color, the code will switch using a when
statement on the view's resource ID. It's a common pattern to use one click-handler function for many views when the click action is the same.
makeColored()
function: Add a when
block to check the view's resource ID. Call the setBackgroundColor()
function on each view's id
to change the view's background color using the Color
class constants.private fun makeColored(view: View) {
when (view.id) {
// Boxes using Color class colors for the background
R.id.box_one_text -> view.setBackgroundColor(Color.DKGRAY)
R.id.box_two_text -> view.setBackgroundColor(Color.GRAY)
R.id.box_three_text -> view.setBackgroundColor(Color.BLUE)
R.id.box_four_text -> view.setBackgroundColor(Color.MAGENTA)
R.id.box_five_text -> view.setBackgroundColor(Color.BLUE)
}
}
android.graphics.Color
library. If Android Studio hasn't imported this library automatically, use an import
statement to add the library before the MainActivity
class definition.id
doesn't match any of the views, you know that the user has tapped the background. At the end of the when
statement, add an else
statement. Inside the else
, set the background color to light gray.else -> view.setBackgroundColor(Color.LTGRAY)
activity_main.xml
, add an id
to the root constraint layout. The Android system needs an identifier in order to change its color.android:id="@+id/constraint_layout"
MainActivity.kt
, add a function called setListeners()
to set the click-listener function, makeColored()
, on each view. Use findViewByID
to get a reference for each text view, and for the root layout. Assign each reference to a variable.private fun setListeners() {
val boxOneText = findViewById<TextView>(R.id.box_one_text)
val boxTwoText = findViewById<TextView>(R.id.box_two_text)
val boxThreeText = findViewById<TextView>(R.id.box_three_text)
val boxFourText = findViewById<TextView>(R.id.box_four_text)
val boxFiveText = findViewById<TextView>(R.id.box_five_text)
val rootConstraintLayout = findViewById<View>(R.id.constraint_layout)
}
For this code to run, it needs the android.widget.TextView
library. If Android Studio doesn't import this library automatically, use an import
statement to add the library before the MainActivity
class definition.
setListeners()
function, define a List
of views. Name the list clickableViews
and add all the view instances to the list.fun setListeners() {
...
val clickableViews: List<View> =
listOf(boxOneText, boxTwoText, boxThreeText,
boxFourText, boxFiveText, rootConstraintLayout)
}
setListeners()
function, set the listener for each view. Use a for
loop and the setOnClickListener()
function. for (item in clickableViews) {
item.setOnClickListener { makeColored(it) }
MainActivity.kt
, at the end of the onCreate()
function, make a call to setListeners()
.override fun onCreate(savedInstanceState: Bundle?) {
...
setListeners()
}
Use images instead of colors and text as backgrounds for all the views. The app should reveal the images when the user taps the text views.
Hint: Add images to the app as drawable resources. Use the setBackgroundResource()
function to set an image as a view's background.
Example:
R.id.box_two_text -> view.setBackgroundResource(R.drawable.image_two)
The baseline constraint aligns the baseline of a view's text with the baseline of another view's text. Aligning views that contain text can be a challenge, especially if the fonts are differently sized. Baseline constraint does the alignment work for you.
You can create baseline constraints in the Layout Editor by using the Edit Baseline icon, which is displayed below the view when you hold the pointer over it. The equivalent XML code for the baseline constraint has the constraint layout attribute,
layout_constraintBaseline_toBaselineOf
.
Sample XML code for the baseline constraint:
<Button
android:id="@+id/buttonB"
...
android:text="B"
app:layout_constraintBaseline_toBaselineOf="@+id/buttonA" />
In this task, you add instructions that tell the user how to use the app. You create two TextView
views, one for a label and one for the instructions information. The text views have different font sizes, and you align their baselines.
activity_main.xml
in Design tab and drag a text view from the Palette pane into the design editor. Put the text view below Box Two. This text view will hold the text that labels the instructions.strings.xml
, create a string resource for the label TextView
view.<string name="how_to_play">How to play:</string>
TextView
:Attribute | Value |
|
|
|
|
|
|
|
|
| B (bold) |
16dp
.label_text
view's left side to the layout's parent element. activity_main.xml
file, the Layout Editor adds the layout_marginStart
attribute with a hard-coded value of 16dp
. Replace 16dp
with @dimen/margin_wide
. The XML code now looks similar to this:<TextView
android:id="@+id/label_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_wide"
android:fontFamily="@font/roboto"
android:text="@string/how_to_play"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="287dp"/> <!--Designtime attribute-->
Design-time attributes are used and applied only during the layout design, not at runtime. When you run the app, the design-time attributes are ignored.
Design-time attributes are prefixed with the tools
namespace, for example, tools:layout_editor_absoluteY
in the generated code snippet shown above. This line of code is added because you haven't yet added a vertical constraint.
All views in a ConstraintLayout
need to be constrained horizontally and vertically, or else the views jump to an edge of the parent when you run the app. This is why the Layout Editor adds tools:layout_editor_absoluteX
if the view is not horizontally constrained. Layout Editor gives the design-time attribute the value of the view's current position in the layout, to keep the views in place during design. You can safely ignore these tools
attributes, because Android Studio removes them after you create the constraints.
Using design-time attributes, you can also add sample preview data to a text view or image view from within the Layout Editor.
Try experimenting with sample data:
label_text
text view, as shown below. This new text view is for the help info that the user will see. Make sure that the new view is vertically offset from the label_text
view, so that you can see what happens when you create the baseline constraint.strings.xml
, create a string resource for the new text view.<string name="tap_the_boxes_and_buttons">Tap the screen and buttons.</string>
Attribute | Value |
|
|
|
|
|
|
|
|
info_text
to the right edge of the parent element. Constrain the left side of the info_text
to the right (end) of the label_text
.label_text
. The Edit Baseline icon Without vertical constraints, views go to the top of the screen (vertical 0) at runtime. Adding vertical constraints will keep the two text views in place when you run the app.
info_text
to the bottom of the layout. info_text
to the bottom of the box_two_text
. info_text
view up or down. Notice that the label_text
view follows, and stays aligned at the baseline.info_text
view to 0
. This keeps the text views closer to the top constrained view, Box Two. (If the view inspector isn't visible in the Attributes pane when you click on the view in the design editor, close and reopen Android Studio.)<TextView
android:id="@+id/label_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_wide"
android:text="@string/how_to_play"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBaseline_toBaselineOf="@+id/info_text"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/info_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_wide"
android:layout_marginTop="@dimen/margin_wide"
android:layout_marginEnd="@dimen/margin_wide"
android:layout_marginBottom="@dimen/margin_wide"
android:text="@string/tap_the_boxes_and_buttons"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/label_text"
app:layout_constraintTop_toBottomOf="@+id/box_two_text"
app:layout_constraintVertical_bias="0.0" />
In this task, you add three Button
views and chain them together.
activity_main.xml
file in the Design tab. Drag three buttons from the Palette pane onto the bottom of the layout.strings.xml
file, add the following string resources for the Button
views:<string name="button_red">RED</string>
<string name="button_yellow">YELLOW</string>
<string name="button_green">GREEN</string>
Attribute | Left button | Middle button | Right button |
|
|
|
|
|
|
|
|
red_button
and green_button
to the baseline of the yellow_button
. (To add a baseline constraint to a view, click on the view and use the Edit Baseline icon 16dp
for the yellow_button
, if these margins aren't already set.red_button
to 16dp
. Set the right margin of the green_button
to 16dp
.yellow_button
to the bottom of the info_text
.yellow_button
to the bottom of the layout.yellow_button
to 100
, to drop down the buttons to the bottom of the layout. Button
views will be similar to the following:<Button
android:id="@+id/red_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_wide"
android:text="@string/button_red"
android:visibility="visible"
app:layout_constraintBaseline_toBaselineOf="@+id/yellow_button"
app:layout_constraintEnd_toStartOf="@+id/yellow_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/yellow_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/margin_wide"
android:layout_marginTop="@dimen/margin_wide"
android:layout_marginBottom="@dimen/margin_wide"
android:text="@string/button_yellow"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/green_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/red_button"
app:layout_constraintTop_toBottomOf="@+id/info_text"
app:layout_constraintVertical_bias="1.0" />
<Button
android:id="@+id/green_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:text="@string/button_green"
app:layout_constraintBaseline_toBaselineOf="@+id/yellow_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/yellow_button" />
In this task, you add a click handler to each Button
view. The click handler changes the color of the TextView
views.
res/values/colors.xml
file: <color name="my_green">#12C700</color>
<color name="my_red">#E54304</color>
<color name="my_yellow">#FFC107</color>
MainActivity.kt
, use findViewById
to get references for the button views. To do this, put the following code inside the setListeners()
click-handler function, above the clickableViews
declaration: val redButton = findViewById<TextView>(R.id.red_button)
val greenButton = findViewById<TextView>(R.id.green_button)
val yellowButton = findViewById<TextView>(R.id.yellow_button)
setListeners()
, add the references of the Button
views to the list of clickable views.private fun setListeners() {
...
val clickableViews: List<View> =
listOf(boxOneText, boxTwoText, boxThreeText,
boxFourText, boxFiveText, rootConstraintLayout,
redButton, greenButton, yellowButton
)
...
}
makeColored()
function, add code to change the text views' colors when the user taps the buttons. Add the new code above the else
statement, as shown:private fun makeColored(view: View) {
when (view.id) {
...
// Boxes using custom colors for background
R.id.red_button -> box_three_text.setBackgroundResource(R.color.my_red)
R.id.yellow_button -> box_four_text.setBackgroundResource(R.color.my_yellow)
R.id.green_button -> box_five_text.setBackgroundResource(R.color.my_green)
else -> view.setBackgroundColor(Color.LTGRAY)
}
}
Remove the text and buttons from your app and fill the entire layout with color boxes (TextView
views). Your app should toggle or change the colors when the user taps on the screen.
Android Studio project: ColorMyViews
ConstraintLayout
is a ViewGroup
that allows you to position and size the layout's child views in a flexible way. Advantages of using ConstraintLayout
:
ConstraintLayout
usually results in a flatter view hierarchy than LinearLayout
.Chains:
Design-time attributes:
tools
namespace. For example, the tools:layout_editor_absoluteY
and tools:text
attributes are design-time attributes.Baseline constraints:
Udacity course:
Android developer documentation:
ConstraintLayout
Videos:
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:
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.
In a constraint layout, which of the following choices describes the constraints needed to keep a view in place during runtime?
Which of the following constraint types expands a view only as much as needed to fit its contents?
The baseline constraint aligns the text baseline of a view to the text baseline of another view. True or false?
The view inspector is available only for views in _______ .
ConstraintLayout
ConstraintLayout
or a LinearLayout
ViewGroup
LinearLayout
A chain is a group of views that are linked to each other with ________ .
Start the next lesson:
For links to other codelabs in this course, see the Android Kotlin Fundamentals codelabs landing page.