5.2. Basic components
Basic components inherit from class View. In this section, we will review the characteristics of the most common components by emphasizing some typical design-related issues.
All components have the properties layout_width
and layout_height
, which indicate width and height respectively. Its value can be defined in four different ways:
- Specifying a constant value using any unit:
android:layout_width=”150dp”
android:layout_height=”50dp”
- Using the same size as the GroupView that contains the component:
android:layout_width=”match_parent”
android:layout_height=”match_parent”
- Growing its size until its content fits.
android:layout_height="wrap_content"
- In some layouts, indicating 0dp in the width indicates that it must occupy as much width as is free. The direction of growth (right, left, up, or down) depends on the type of the parent layout.
android:layout_width="0dp"
Moreover, any item that inherits from View can have a background color that is indicated by the background
attribute. All colors can be indicated in two ways:
- An absolute value in hexadecimal (RGB format):
android:background="#ff0000"
- Referring to a style of the theme we are using:
android:background="@color/design_default_color_background"
TextView
The TextView is the component that allows displaying text on the screen. When the text exceeds the width of the TextView, if we have vertical space available, the text jumps to the next line. However, if we have not indicated wrap_content
in the height
property, the text will be cut off when we run out of space.
- Text color:
android:textColor="#ffffff"
- Horizontal text alignment: centered, left, right
android:gravity="center_horizontal" android:gravity="left" android:gravity="right"
- Vertical alignment
android:gravity="center_vertical"
- Assigning horizontal and vertical alignment at the same time
android:gravity="center"
- Justified text:
android:justificationMode="inter_word"
- Font selection:
android:fontFamily="sans-serif-black"
- Font size:
android:textSize="14dp"
- Line size:
android:lineSpacingMultiplier="1.5" android:lineSpacingExtra="10dp"
In Android, the concept of “line size” does not exist as such. The line height can be calculated as: LineSize = android:textSize*android:lineSpacingMultiplier + android:lineSpacingExtra
-
Adding an extra space is most commonly done using only
android:lineSpacingExtra
. -
Adding fonts: To add a typeface, we have to create an Android resource folder within the
res
folder of our project and selectfont
as the type of resource. Then, we can add our fonts by copying them into this folder. - Leaving a margin around the text:
android:padding="10dp"
- Using formatted text: We can include different styles in a text using class SpannableString and other classes like ForegroundColorSpan or BackgroundColorSpan. These classes affect a range of characters within the SpannableString.
val spannablecontent: SpannableString = SpannableString("Hello SpannableString") val foregroundColorSpan = ForegroundColorSpan(Color.GREEN) spannablecontent.setSpan(foregroundColorSpan, 6, 15, Spanned.SPAN_INCLUSIVE_EXCLUSIVE) binding.editTextMultiline.setText(spannablecontent)
In this example, the text would be set to HelloSpannableString
with the characters forming the word Spannable
printed in green).
Learn more: The set of classes that represent the available styles can be found here: https://developer.android.com/reference/kotlin/android/text/style/CharacterStyle
Finally, we can upload text in HTML format using Html.fromHtml
. This method converts from HTML to text with Android styles. Care must be taken because not all HTML tags are transformed:
binding.text1.setText(Html.fromHtml("<h2>Title</h2><br><p>Description here</p>",
Html.FROM_HTML_MODE_COMPACT))
ImageView
ImageView is the class that displays an image. This class can display locally available images on our device but does not know how to download an image located on an external server. To download such external images, additional programming is required.
The scaleType
attribute is one of the most important attributes of this component. It indicates how the image should be scaled within the defined size.
For example:
android:scaleType="fitCenter"
Snaps the image into the defined space and centers it, while
android:scaleType="centerCrop"
Centers the image in the defined space and cuts out what comes out.
fitCenter vs centerCrop
Source: Javier Salvador (Original image) License: CC BY-NC-ND 4.0
A custom scaling matrix can be used to define a scaling that is not supported by the system.
android:scaleType="matrix"
There are two ways to upload an image in gif format:
- Using a library like Glide. To do this, we add a dependency to the library in the Gradle of the app.
implementation ("com.github.bumptech.glide:glide:4.11.0") {
exclude group: "com.android.support"
}
We can now upload the gif using an ImageView that we have defined in the layout and acts as a placeholder.
Glide.with(this).load(R.drawable.arrow1).into(binding.image);
- API 28 and above include native support for loading many new image formats. This support is achieved using the AnimatedImageDrawable class.
GlobalScope.launch {
val drawable = ImageDecoder.decodeDrawable(source, gfgListner)
GlobalScope.launch(Dispatchers.Main) {
binding.image.setImageDrawable(drawable)
if (drawable is AnimatedImageDrawable) {
(drawable as AnimatedImageDrawable).start()
}
}
}
Decoding should be implemented using Kotlin coroutines, because image decoding can be resource intensive and we should not pause the main thread. We will explain how to use coroutines in Section 7.7.
Learn more: If we are using AnimatedImageDrawable and we cannot see a GIF image in the Android Studio emulator, the problem may be the lack of hardware acceleration. In this case, we should add the following attribute to the manifest file of our application in the activity where we are going to use the AnimatedImageDrawable:
android:hardwareAccelerated="false"
A library that is often used extensively to download images from a remote server is Picasso. Using this library, we can download an image from the Internet with a single line of code:
Picasso.with(this).load(“url_image").into(binding.image);
It is important to remember that we must declare that our application should have access to the internet in the manifest file.
<uses-permission android:name="android.permission.INTERNET" />
Button
The Button is the component designed to perform an action when pressed.
<Button
android:id="@+id/btn"
android:text="START"
android:layout_width="150dp"
android:layout_height="150dp"
/>
To know when a user clicks on the button, we assign the value of the code we want to run to the property setOnClickListen
.
binding.btn.setOnClickListener {
Toast.makeText(this, "click.", Toast.LENGTH_SHORT).show()
}
Any item derived from View can be pressed, for example, an image:
binding.image.setOnClickListener {
Toast.makeText(this, "image.", Toast.LENGTH_SHORT).show()
}
The only difference is that the button performs the visual tapping effect. To use a button that implements the tapping effect but with images instead of text, we must use the ImageButton component. To define the images of the different statuses of the button, we should create a new resource file of type Drawable and Root element (selector
).
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/moon" /> <!-- pressed -->
<item android:state_focused="true"
android:drawable="@drawable/sun" /> <!-- focused -->
<item android:drawable="@drawable/sun" /> <!-- default -->
</selector>
Now we assign the selector to our button using the src
attribute:
<ImageButton
android:id="@+id/btn"
android:src="@drawable/selector_btn"
android:layout_width="150dp"
android:layout_height="150dp"/>
Input components
There are many components to allow data entry. In the following, we discuss the most frequently used ones: EditText and Switch.
EditText has a very important attribute called inputType
. This attribute allows you to perform a series of validations automatically. It also controls the keyboard displayed by Android:
android:inputType="number"
With this option, the EditText only allows numeric characters and displays the numeric keypad.
android:inputType="textPassword"
This option hides the characters that the user enters.
android:inputType="textEmailAddress"
This option shows the character “@” on the keyboard.
android:inputType="textMultiLine"
This option allows text that occupies more than one line. If nothing is indicated, the cursor is placed in the middle of the EditText height.
To make the text start at the top of a view, it is necessary to add android:gravity="top"
.
More than one type can be assigned to achieve effects such as auto-complete, … For example, if we indicate
android:inputType="textMultiLine|textAutoCorrect"
the component will allow multi-line inputs and it will correct spelling errors in real time.
It is important to always assign a background to the EditText:
android:background="@android:drawable/edit_text"
Regarding the Switch component, it can be in two states: true or false. It is often used to let the user select it a feature is required. With the isChecked
method we can determine the status of the Switch.
binding.switch1.setOnClickListener {
Toast.makeText(this, binding.switch1.isChecked().toString(), Toast.LENGTH_SHORT)
.show()
}
Shapes
We can create effects on the backgrounds of any View by creating a resource file of type drawable
with root element shape
and creating the required shape. In the example below, we select a color and indicate that the corners will be rounded.
<shape xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="20dp" />
<solid
android:color="#00eeff" />
</shape>
Then we assign this drawable to the background of the item we want:
<View
android:layout_width="0dp"
android:layout_height="50dp"
android:background="@drawable/demo_shape" />