В ходе разработки одного приложения, захотелось добавить кнопку очистки текста к компоненту EditText. Решение было найдено достаточно быстро и заключалось в том, чтобы отлавливать координаты касания и если касание произошло над правым фоновым изображением (drawableRight), то обрабатывать как нажатие кнопки (очищать текст), иначе — стандартным для данного компонента способом.
Решение получилось достаточно лаконичным и надёжно работающим. Но затем захотелось пойти дальше и сделать 2-3 кнопки, мало ли какой ещё функционал можно навесить на них, например выбор из списка, который открывается в отдельном окне или включение/отключение режима редактирования, чтобы защитить поле от случайных изменений.
Итак, начнём:
1. Создаём новый проект с пустой activity (среда разработки Android Studio 1.5.1).
2. Добавляем новый класс и называем его MyCustomEditText, полный листинг:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;
public class MyCustomEditText extends EditText {
Bitmap drawableRight; //стандартный drawable справа
Bitmap drawableRight2; //то, ЧТО будем рисовать
Bitmap drawableRight3; //то, ЧТО будем рисовать
Paint paint; //то, ЧЕМ будем рисовать
public MyCustomEditText(Context context) {
super(context);
init();
}
public MyCustomEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initDrawables(attrs);
init();
}
public MyCustomEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initDrawables(attrs);
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (drawableRight != null) {
//рисуем drawableRight2 только при наличии drawableRight
if (drawableRight2 != null) {
canvas.drawBitmap(drawableRight2, getWidth() + getScrollX() - drawableRight.getWidth() * 2, (getHeight() - drawableRight2.getHeight()) / 2, paint);
//рисуем drawableRight3 только при наличии drawableRight2
if (drawableRight3 != null) {
canvas.drawBitmap(drawableRight3, getWidth() + getScrollX() - drawableRight.getWidth() * 3, (getHeight() - drawableRight3.getHeight()) / 2, paint);
}
}
}
}
/**
* Returns the right padding of the view, plus space for the right
* Drawable if any.
*/
@Override
public int getCompoundPaddingRight() {
//здесь мы устанавливаем отступ справа, чтобы каретка не наезжала на наши кнопки
int paddingRight = super.getCompoundPaddingRight();
if (drawableRight2 != null) {
paddingRight = paddingRight + drawableRight2.getWidth();
}
if (drawableRight3 != null) {
paddingRight = paddingRight + drawableRight3.getWidth();
}
return paddingRight;
}
private void initDrawables(AttributeSet attrs) {
//инициализируем наши drawables, если были заполнены соответствующие атрибуты
for (int i = 0; i < attrs.getAttributeCount(); i++) {
if (attrs.getAttributeName(i).equals("drawableRight")) {
drawableRight = BitmapFactory.decodeResource(getResources(), attrs.getAttributeResourceValue(i, 0));
}
if (attrs.getAttributeName(i).equals("drawableRight2")) {
drawableRight2 = BitmapFactory.decodeResource(getResources(), attrs.getAttributeResourceValue(i, 0));
}
if (attrs.getAttributeName(i).equals("drawableRight3")) {
drawableRight3 = BitmapFactory.decodeResource(getResources(), attrs.getAttributeResourceValue(i, 0));
}
}
}
private void init() {
paint = new Paint();
}
}
3. Чтобы у нашего компонента были нужные нам свойства, необходимо создать attrs.xml следующего содержания:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomEditText">
<attr name="drawableRight2" format="reference"/>
<attr name="drawableRight3" format="reference"/>
</declare-styleable>
</resources>
4. После чего можно установить значения этих свойств в файле-разметки:
<ru.vlsoft.mycustomedittext.MyCustomEditText
android:id="@+id/customEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:drawableEnd="@drawable/one"
android:drawableRight="@drawable/one"
android:textAppearance="?android:attr/textAppearanceLarge"
app:drawableRight2="@drawable/two"
android:singleLine="true"
app:drawableRight3="@drawable/three"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
5. Ну и последним шагом будет добавление обработчика события onTouchListener в главной activity, полный листинг которой ниже:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyCustomEditText customEditText = (MyCustomEditText) findViewById(R.id.customEditText);
customEditText.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
MyCustomEditText editText = (MyCustomEditText) v;
//подразумеваем, что все 3 изображения справа указаны
//и т.к. все изображения у нас одного размера, то будем отталкиваться от размера самого правого
int drawableSize = editText.getCompoundDrawables()[2].getBounds().width();
if (event.getRawX() >= editText.getRight() - drawableSize) {
Log.i("sdf", "one");
return true;
} else if (event.getRawX() >= editText.getRight() - drawableSize * 2) {
Log.i("sdf", "two");
return true;
} else if (event.getRawX() >= editText.getRight() - drawableSize * 3) {
Log.i("sdf", "three");
return true;
} else {
return false;
}
} else {
return false;
}
}
});
}
}
Весь проект можно скачать — здесь. Надеюсь, кому-нибудь пригодится, спасибо за внимание.
Автор: VladC