Понадобился мне для проекта один специфический элемент — кнопка с обведенным шрифтом. Казалось бы, что тут такого — 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. Пример использования ниже.
- <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» />
Ну и как обычно, камнями кидаться не большими — писал первый раз. С надеждой на понимание.