10.1A: Creating a custom view from a View subclass
Contents:
- What you should already KNOW
- What you will LEARN
- What you will DO
- App overview
- Task 1. Customize an EditText view
- Solution code
- Summary
- Related concept
- Learn more
Android offers a large set of View subclasses, such as Button, TextView, EditText, ImageView, CheckBox, or RadioButton. You can use these subclasses to construct a UI that enables user interaction and displays information in your app. If the View subclasses don't meet your needs, you can create a custom view that does.
After you create a custom view, you can add it to different layouts in the same way you would add a TextView or Button. This lesson shows you how to create and use custom views based on View subclasses.
What you should already KNOW
You should be able to:
- Create and run apps in Android Studio.
- Use the Layout Editor to create a UI.
- Edit a layout in XML.
- Use touch, text, and click listeners in your code.
What you will LEARN
You will learn how to:
- Extend the
ViewsubclassEditTextto create a custom text-editing view. - Use listeners to handle user interaction with the custom view.
- Use a custom view in a layout.
What you will DO
- Add a new class that extends the
EditTextclass to create a custom view. - Use listeners to provide the custom view's behavior.
- Add the custom view to a layout.
App overview
The CustomEditText app demonstrates how to extend EditText to make a custom text-editing view. The custom view includes a clear (X) button for clearing text. After the custom view is created, you can use multiple versions of it in layouts, applying different EditText attributes as needed.

Task 1. Customize an EditText view
In this task, you create an app with a customized EditText view that includes a clear (X) button on the right side of the EditText. The user can tap the X to clear the text. Specifically, you will:
- Create an app with an
EditTextview as a placeholder. - Add layout attributes to position the view, and to support right-to-left (RTL) languages for text input.
- Extend the
EditTextclass to create a custom view. - Initialize the custom view with a
drawablethat appears at the end of theEditText. - Use a text listener to show the
drawableonly when text is entered into theEditText. - Use a touch listener to clear the text if the user taps the drawable.
- Replace the placeholder
EditTextwith the custom view in the layout.
1.1 Create an app with an EditText view
In this step, you add two drawables for the clear (X) button:
An opaque version
that appears when the user enters text.A black version
that appears while the user is tapping the X.
You also change a TextView to an EditText with attributes for controlling its appearance. If the layout direction is set to a right-to-left (RTL) language, these attributes change the direction in which the user enters text. (For more about supporting RTL languages, see the lesson on localization.)
- Create an app named
CustomEditTextusing the Empty Activity template. Make sure that Generate Layout File is selected so that theactivity_main.xmllayout file is generated. - Edit the
build.gradle (Module: app)file. Change the minimum SDK version to 17, so that you can support RTL languages and placedrawablesin either the left or right position inEditTextviews:minSdkVersion 17 - Right-click the
drawable/folder and choose New > Vector Asset. Click the Android icon and choose the clear (X) icon. Its name changes toic_clear_black_24dp. Click Next and Finish. Repeat step 3, choosing the clear (X) icon again, but this time drag the Opacity slider to 50% as shown below. Change the icon's name to
ic_clear_opaque_24dp.
In
activity_main.xml, change the "Hello World"TextViewto anEditTextwith the following attributes:Attribute Value android:id"@+id/my_edit_text"android:layout_width"wrap_content"android:layout_height"wrap_content"android:textAppearance"@style/Base.TextAppearance.AppCompat.Display1"android:inputType"textCapSentences"android:layout_gravity"start"android:textAlignment"viewStart"app:layout_constraintBottom_toBottomOf"parent"app:layout_constraintLeft_toLeftOf"parent"app:layout_constraintRight_toRightOf"parent"app:layout_constraintTop_toTopOf"parent"android:hint"Last name"Extract the string resource for "Last name" to
last_name.- Run the app. It displays an
EditTextfield for entering text (a last name), and uses thetextCapSentencesattribute to capitalize the first letter.
1.2 Add a subclass that extends EditText
- Create a new Java class called
EditTextWithClearwith the superclass set toandroid.support.v7.widget.AppCompatEditText.AppCompatEditTextis anEditTextsubclass that supports compatible features on older version of the Android platform. - The editor opens
EditTextWithClear.java. A red bulb appears a few moments after you click the class definition because the class is not complete—it needs constructors. - Click the red bulb and select Create constructor matching super. Select all three constructors in the popup menu, and click OK.
The three constructors are:
- AppCompatEditText(context:Context): Required for creating an instance of a view programmatically.
- AppCompatEditText(context:Context, attrs:AttributeSet): Required to inflate the view from an XML layout and apply XML attributes.
- AppCompatEditText(context:Context, attrs:AttributeSet, defStyleAttr:int): Required to apply a default style to all UI elements without having to specify it in each layout file.
1.3 Initialize the custom view
Create a helper method that initializes the view, and call that method from each constructor. That way, you don't have to repeat the same code in each constructor.
- Define a member variable for the drawable (the X button image).
Drawable mClearButtonImage; Create a
privatemethod calledinit(), with no parameters, that initializes the member variable to thedrawableresourceic_clear_opaque_24dp.private void init() { mClearButtonImage = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_clear_opaque_24dp, null); // TODO: If the clear (X) button is tapped, clear the text. // TODO: If the text changes, show or hide the clear (X) button. }The code includes two
TODOcomments for upcoming steps of this task.Add the
init()method call to each constructor:public EditTextWithClear(Context context) { super(context); init(); } public EditTextWithClear(Context context, AttributeSet attrs) { super(context, attrs); init(); } public EditTextWithClear(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); }
1.4 Show or hide the X button
If the user enters text, the EditTextWithClear custom view shows the clear (X) button. If there is no text in the field, the EditTextWithClear custom view hides the clear (X) button.
To show or hide the button, use the TextWatcher interface, whose methods are called if the text changes. Follow these steps:
Open
EditTextWithClearand create twoprivatemethods with no parameters,showClearButton()andhideClearButton(). In these methods, usesetCompoundDrawablesRelativeWithIntrinsicBounds()to show or hide the clear (X) button./** * Shows the clear (X) button. */ private void showClearButton() { setCompoundDrawablesRelativeWithIntrinsicBounds (null, // Start of text. null, // Above text. mClearButtonImage, // End of text. null); // Below text. } /** * Hides the clear button. */ private void hideClearButton() { setCompoundDrawablesRelativeWithIntrinsicBounds (null, // Start of text. null, // Above text. null, // End of text. null); // Below text. }In
showClearButton(), thesetCompoundDrawablesRelativeWithIntrinsicBounds()method sets thedrawablemClearButtonImageto the end of the text. The method accommodates right-to-left (RTL) languages by using the arguments as "start" and "end" positions rather than "left" and "right" positions. For more about supporting RTL languages, see the lesson on localization.Use
nullfor positions that should not show adrawable. InhideClearButton(), thesetCompoundDrawablesRelativeWithIntrinsicBounds()method replaces thedrawablewithnullin the end position.The
setCompoundDrawablesRelativeWithIntrinsicBounds()method returns the exact size of thedrawable. This method requires a minimum Android API level 17 or newer. Be sure to edit yourbuild.gradle (Module: app)file to useminSdkVersion 17.In
EditTextWithClear, add aTextWatcher()inside theinit()method, replacing the secondTODOcomment (TODO: If the text changes, show or hide the clear (X) button). Let Android Studio do the work for you: start by entering addText:// If the text changes, show or hide the clear (X) button. addText- After entering addText, choose the suggestion that appears for addTextChangedListener(TextWatcher watcher). The code changes to the following, and a red bulb appears as a warning.
addTextChangedListener() - In the code shown above, enter new T inside the parentheses:
addTextChangedListener(new T) Choose the TextWatcher{...} suggestion that appears. Android Studio creates the
beforeTextChanged(),onTextChanged(), andafterTextChanged()methods inside theaddTextChangedListener()method, as shown in the code below:addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { } });- In the
onTextChanged()method, call theshowClearButton()method for showing the clear (X) button. You implement onlyonTextChanged()in this practical, so leavebeforeTextChanged()andafterTextChanged()alone, or just add comments to them.public void onTextChanged(CharSequence s, int start, int before, int count) { showClearButton(); }
1.5 Add touch and text listeners
Other behaviors of the EditTextWithClear custom view are to:
- Clear the text from the field if the user taps the clear (X) button.
- Render the clear (X) button as opaque before the user taps it, and black while the user is tapping it.
To detect the tap and clear the text, use the View.OnTouchListener interface. The interface's onTouch() method is called when a touch event occurs with the button.
Tip: To learn more about event listeners, see Input Events.
You should design the EditTextWithClear class to be useful in both left-to-right (LTR) and right-to-left (RTL) language layouts. However, the button is on the right side in an LTR layout, and on the left side of an RTL layout. The code needs to detect whether the touch occurred on the button itself. It checks to see if the touch occurred after the start location of the button. The start location of the button is different in an RTL layout than it is in an LTR layout, as shown in the figure.

In the figure above:
- The start location of the button in an LTR layout. Moving to the right, the touch must occur after this location on the screen and before the right edge.
- The start location of the button in an RTL layout. Moving to the left, the touch must occur after this location on the screen and before the left edge.
Tip: To learn more about reporting finger movement events, see MotionEvent.
Follow these steps to use the View.OnTouchListener interface:
- In the
init()method, replace the firstTODOcomment (TODO: If the clear (X) button is tapped, clear the text) with the following code. If the clear (X) button is visible, this code sets a touch listener that responds to events inside the bounds of the button.// If the clear (X) button is tapped, clear the text. setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return false; } }); In the
onTouch()method, replace the singlereturn falsestatement with the following:if ((getCompoundDrawablesRelative()[2] != null)) { float clearButtonStart; // Used for LTR languages float clearButtonEnd; // Used for RTL languages boolean isClearButtonClicked = false; // TODO: Detect the touch in RTL or LTR layout direction. // TODO: Check for actions if the button is tapped. } return false;In the previous step, you set the location of the clear (X) button using
setCompoundDrawablesRelativeWithIntrinsicBounds():- Location 0: Start of text (set to
null). - Location 1: Top of text (set to
null). - Location 2: End of text (set to
mClearButtonImage). - Location 3: Bottom of text (set to
null).
In the above step, you use the
getCompoundDrawablesRelative()[2]expression, which usesgetCompoundDrawablesRelative()to return thedrawableat the end of the text[2]. If nodrawableis present, the expression returnsnull. The code executes only if that location is notnull—which means that the clear (X) button is in that location. Otherwise, the code returnsfalse.- Location 0: Start of text (set to
1.6 Recognize the user's tap
To recognize the user's tap on the clear (X) button, you need to get the intrinsic bounds of the button and compare it with the touch event.
- For an LTR language, the clear (X) button starts on the right side of the field. Any touch occurring after the start point is a touch on the button itself.
- For an RTL language, the clear (X) button ends on the left side of the field. Any touch occurring before the endpoint is a touch on the button itself.
Follow these steps:
- Use
getLayoutDirection()to get the current layout direction. Use theMotionEventgetX()method to determine whether the touch occurred after the start of the button in an LTR layout, or before the end of the button in an RTL layout. In theonTouch()method, replace the firstTODOcomment (TODO: Detect the touch in RTL or LTR layout direction):// Detect the touch in RTL or LTR layout direction. if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { // If RTL, get the end of the button on the left side. clearButtonEnd = mClearButtonImage .getIntrinsicWidth() + getPaddingStart(); // If the touch occurred before the end of the button, // set isClearButtonClicked to true. if (event.getX() < clearButtonEnd) { isClearButtonClicked = true; } } else { // Layout is LTR. // Get the start of the button on the right side. clearButtonStart = (getWidth() - getPaddingEnd() - mClearButtonImage.getIntrinsicWidth()); // If the touch occurred after the start of the button, // set isClearButtonClicked to true. if (event.getX() > clearButtonStart) { isClearButtonClicked = true; } } Check for actions if the clear (X) button is tapped. On
ACTION_DOWN, you want to show the black version of the button as a highlight. OnACTION_UP, you want to switch back to the default version of the button, clear the text, and hide the button. In theonTouch()method, replace the secondTODOcomment (TODO: Check for actions if the button is tapped):// Check for actions if the button is tapped. if (isClearButtonClicked) { // Check for ACTION_DOWN (always occurs before ACTION_UP). if (event.getAction() == MotionEvent.ACTION_DOWN) { // Switch to the black version of clear button. mClearButtonImage = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_clear_black_24dp, null); showClearButton(); } // Check for ACTION_UP. if (event.getAction() == MotionEvent.ACTION_UP) { // Switch to the opaque version of clear button. mClearButtonImage = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_clear_opaque_24dp, null); // Clear the text and hide the clear button. getText().clear(); hideClearButton(); return true; } } else { return false; }The first touch event is
ACTION_DOWN. Use it to check if the clear (X) button is touched (ACTION_DOWN). If it is, switch the clear button to the black version.The second touch event,
ACTION_UPoccurs when the gesture is finished. Your code can then clear the text, hide the clear (X) button, and returntrue. Otherwise the code returnsfalse.
1.7 Change the EditText view to the custom view
The EditTextWithClear class is now ready to be used in place of the EditText view in the layout:
In
activity_main.xml, change theEditTexttag for themy_edit_textelement tocom.example.android.customedittext.EditTextWithClear.The
EditTextWithClearclass inherits the attributes defined for the originalEditText, so there is no need to change any of them for this step.If you see the message "classes missing" in the preview, click the link to rebuild the project.
Run the app. Enter text, and then tap the clear (X) button to clear the text.

1.8 Run the app with an RTL language
To test an RTL language, you can add Hebrew in the Translations Editor, switch the device or emulator to Hebrew, and run the app. Follow these steps:
- Open the
strings.xmlfile, and click the Open editor link in the top right corner to open the Translations Editor. Click the globe button in the top left corner of the Translations Editor pane, and select Hebrew (iw) in Israel (IL) in the dropdown menu.
After you choose a language, a new column with blank entries appears in the Translations Editor for that language, and the keys that have not yet been translated appear in red.
Enter the Hebrew translation of "Last name" for the
last_namekey by selecting the key's cell in the column for the language (Hebrew), and entering the translation in the Translation field at the bottom of the pane. (For instructions on using the Translations Editor, see the chapter on localization.) When finished, close the Translations Editor.On your device or emulator, find the Languages & input settings in the Settings app. For devices using Android Oreo (8) or newer, the Languages & input choice is under System.
Be sure to remember the globe icon for the Languages & input choice, so that you can find it again if you switch to a language you do not understand.

Choose Languages (or Language on Android 6 or older), which is easy to find because it is the first choice on the Languages & input screen.
- For devices and emulators running Android 6 or older, select עִברִית for Hebrew. For devices and emulators running Android 7 or newer, click Add a language, select עִברִית, select ( עברית (ישראל for the locale, and then use the move icon on the right side of the Language preferences screen to drag the language to the top of the list.
- Run the app. The
EditTextWithClearelement should be reversed for an RTL language, with the clear (X) button on the left side, as shown below. Put a finger on the clear (X) button, or if you're using a mouse, click and hold on the clear button. Then drag away from the clear button. The button changes from gray to black, indicating that it is still touched.

To change back from Hebrew to English, repeat Steps 4-6 above with the selection English for language and United States for locale.
Solution code
Android Studio project: CustomEditText
Summary
- To create a custom view that inherits the look and behavior of a
Viewsubclass such asEditText, add a new class that extends the subclass (such asEditText), and make adjustments by overriding some of the subclass methods. - Add listeners such as
View.OnClickListenerto the custom view to define the view's interactive behavior. - Add the custom view to an XML layout file with attributes to define the view's appearance, as you would with other UI elements.
Tip: View the different methods of the View subclasses, such as TextView, Button, and ImageView, to see how you can modify a View subclass by overriding these methods. For example, you can override the setCompoundDrawablesRelativeWithIntrinsicBounds() method of a TextView (or an EditText, which is a subclass of TextView) to set a drawable to appear to the start of, above, to the end of, and below the text.
Related concept
The related concept documentation is Custom views.
Learn more
Android developer documentation:
- Creating Custom Views
- Custom Components
View- Input Events
onDraw()CanvasdrawCircle()drawText()Paint
Video: