Skip to content

Instantly share code, notes, and snippets.

@MohammadSamandari
Created April 9, 2020 18:32
Show Gist options
  • Save MohammadSamandari/d78ec2c1477fe9683314a51b0200da76 to your computer and use it in GitHub Desktop.
Save MohammadSamandari/d78ec2c1477fe9683314a51b0200da76 to your computer and use it in GitHub Desktop.
Android-CustomView
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<mohammad.samandari.learncustomview.EditTextWithClear
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Custom View

Steps for creating the custom view

Create a custom view class

this extends View or another subclass of the view like button or textview

  1. Add the new class and extend it with edittext. (notice it is the appcompat text view)
  2. adding the 3 constructor for the class
  3. Adding the behavior to the custom view.
  • add 2 drawable for the clear(X) buttton for the textview
  • adding the init() method inside the new class and then calling it from all constructors.
 private void init() {
     mClearButtonImage = ResourcesCompat.getDrawable(getResources(),
                              R.drawable.ic_clear_opaque_24dp, null);
     // TODO: If the X (clear) button is tapped, clear the text.
     // TODO: If the text changes, show or hide the X (clear) button.
 }
  1. Drawing the custom view
  • If your class is extending a View subclass, such as EditText, you don't need to draw the entire view—you can override some of its methods to customize the view. This is described in Customizing a View subclass, below.
  • If your class is extending View, you must override the onDraw() method to draw the view. This is described in Drawing an extended View, below.

Extending and customizing a View subclass

When you extend a View subclass such as EditText, you are using that subclass to define the view's appearance and attributes. Consequently, you don't have to write code to draw the view. You can override methods of the parent to customize your view.

For example, if you extend an EditText view, which is itself a subclass of TextView, you can use the getCompoundDrawables() and setCompoundDrawables() methods inherited from TextView to get and set drawables for the borders of the view.

setCompoundDrawablesRelativeWithIntrinsicBounds
                (null,                      // Start of text.
                        null,               // Above text.
                        mClearButtonImage,  // End of text.
                        null);              // Below text.
// ...
  1. Add on text change listener
  2. add on touch listener
package mohammad.samandari.learncustomview;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.core.content.res.ResourcesCompat;
public class EditTextWithClear extends AppCompatEditText {
Drawable mClearButtonImage;
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();
}
private void init () {
// Initialize Drawable member variable.
mClearButtonImage =
ResourcesCompat.getDrawable(getResources(),
R.drawable.ic_clear_opaque_24dp, null);
//cheak to see if there is context already? to show the button.
if (getText().toString().length() > 0) {
showClearButton();
}
// If the X (clear) button is tapped, clear the text.
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// Use the getCompoundDrawables()[2] expression to check
// if the drawable is on the "end" of text [2].
if ((getCompoundDrawablesRelative()[2] != null)) {
float clearButtonStart; // Used for LTR languages
float clearButtonEnd; // Used for RTL languages
boolean isClearButtonClicked = false;
// 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 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;
}
}
return false;
}
});
// If the text changes, show or hide the X (clear) button.
addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s,
int start, int count, int after) {
// Do nothing.
}
@Override
public void onTextChanged(CharSequence s,
int start, int before, int count) {
showClearButton();
}
@Override
public void afterTextChanged(Editable s) {
// Do nothing.
}
});
}
/**
* Shows the clear (X) button.
*/
private void showClearButton() {
// Sets the Drawables (if any) to appear to the left of,
// above, to the right of, and below the text.
setCompoundDrawablesRelativeWithIntrinsicBounds
(null, // Start of text.
null, // Top of text.
mClearButtonImage, // End of text.
null); // Below text.
}
/**
* Hides the clear button.
*/
private void hideClearButton() {
setCompoundDrawablesRelativeWithIntrinsicBounds
(null, // Start of text.
null, // Top of text.
null, // End of text.
null); // Below text.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment