Button c обведенным(stroke) шрифтом на Android

в 19:29, , рубрики: android, interface, Программирование, Разработка под android, метки: , ,

image
Понадобился мне для проекта один специфический элемент — кнопка с обведенным шрифтом. Казалось бы, что тут такого — google точно должен был это предусмотреть. Но, как оказалось, стандартными способами это сделать нельзя и нужно покопаться под капотом Button. Начал я свои поиски с тени для шрифта.
Но попытка сделать stroke шрифт таким способом провалится —
во-первых, линия вокруг букв будет размытой тем больше, чем больше вы укажете число в shadowRadius;
во-вторых, нельзя изменить ширину линии.
Немного поразмыслив, я реализовал класс, который делает все что требуется. Кого заинтересовало — прошу под кат.

Поискал везде решение и не смог найти, поэтому решил показать свое решение и, возможно, кому-то оно пригодится. Из требований было — возможность установки цвета шрифта и ширины обводки из XML. Теперь переходим к коду.

Для начала в файле res/values/attrs.xml опишем параметры, которые будет принимать наша кнопка ButtonStrokeText (назовем ее так).

<?xmlversion="1.0" encoding="utf-8"?>
<resources>
 
    <declare-styleable name="ButtonStrokeText">
        <attr name="textStrokeColor" format="color"/>
        <attr name="textStrokeWidth" format="dimension"/>
    </declare-styleable>
 
</resources>

Цвет обводки textStrokeColor мы будем принимать в формате color(также как и цвет текста в обычной кнопке), ширину обводки сделаем как и положено в dimensions(sp, dp и все такое). Напомню, что google рекомендует использовать sp для размера текста.

Так, параметры для XML описали, переходим дальше к самому классу ButtonStrokeText. Создаем класс с таким названием и наследуем его от Button. Переписываем пару конструкторов и один метод onDraw. Вот и сам код:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.Button;
 
 
public class ButtonStrokeText extends Button
{
         private int strokeColor=Color.TRANSPARENT;
         private int strokeWidth=2;
         public ButtonStrokeText(Context context)
         {
                 super(context);
         }
         public ButtonStrokeText(Context context, AttributeSet attrs) 
         {
                 super(context, attrs);
                 TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ButtonStrokeText);
                 strokeColor=a.getColor(R.styleable.ButtonStrokeText_textStrokeColor, strokeColor);
                 strokeWidth=a.getDimensionPixelSize(R.styleable.ButtonStrokeText_textStrokeWidth, strokeWidth);
                 a.recycle();
         }
         Override
         public void onDraw(Canvas canvas)
         {
                 final ColorStateList textColor = getTextColors();
 
                 TextPaint paint = this.getPaint();
 
                 paint.setStyle(Style.STROKE);
                 paint.setStrokeJoin(Join.ROUND);
                 paint.setStrokeMiter(10);
                 this.setTextColor(strokeColor);
                 paint.setStrokeWidth(strokeWidth);
 
                 super.onDraw(canvas);
                 paint.setStyle(Style.FILL);
 
                 setTextColor(textColor);
                 super.onDraw(canvas);
         }
}

Код довольно простой — в конструкторе ButtonStrokeText(Context context, AttributeSet attrs) мы обрабатываем параметры и сохраняем их. Последний параметр в методах getColor и getDimensionPixelSize означает тип по умолчанию, если забудем или не будем указывать его в XML.
Самое интересное у нас происходит в методе, которые отвечает за отрисовку. В нем мы как раз рисуем обводку и последней строкой вызываем родительский метод. Упомяну еще, что setStrokeJoin влияет на тип обводки, я выбрал закругленный. На картинке показаны варианты обводки, в зависимости от параметров(внимательно смотрите на края и углы обводки). Все варианты можете посмотреть на картинке.

Вот, собственно, и все. Теперь можете использовать этот класс в своих XML. Пример использования ниже.

  1. <com.unlim.components.ButtonStrokeText android:text="@string/menu_quit"

  • android:textColor=«android:color/white»
  • app:textStrokeWidth=«5sp» app:textStrokeColor=«android:color/black»
  • android:textSize=«20sp» android:layout_width=«220dip»
  • android:layout_height=«40dip» android:layout_gravity=«center_horizontal» />
  • Ну и как обычно, камнями кидаться не большими — писал первый раз. С надеждой на понимание.

    Автор: sagus

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


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