Custom EditText с тремя кнопками справа

в 9:11, , рубрики: 3 кнопки, android, custom view, edittext, Разработка под android

В ходе разработки одного приложения, захотелось добавить кнопку очистки текста к компоненту 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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js