例えばTextViewの一部をリンクにしたり、一部を強調したい、などの時にTextViewの一部に装飾したいときってありますよね?
実はTextViewはSpannableStringを使うことにより、一部を装飾したり、リンクにしたりといったことは簡単にできます。
詳しい内容は @wasabeef_jp さんの投稿 [Android Advanced TextView](Android Advanced TextView) にまとまっているのでそちらを参照してください。
今回は、その中で ReplacementSpan
を使って背景や点線の下線の描画などをやりたいと思います。
といってもとても簡単で、 ReplacementSpan
を継承したクラスを作り、 draw
メソッドをオーバーライドして上げてそこで Canvas
に描画してあげるだけです。
ね、簡単でしょう?
サンプル
文章だけでもいいかな、と思ったんですがてきとーに実装もしたんで紹介します。
手順としては、先に下線や背景を描画したあとに、Textを描画してあげます。
スクリーンショット
上から、順に
- 点線の下線
- 背景色と角丸のborder
-
drawable
の背景画像
サンプルコード
今回実装したものは以下のようになります。
public class BackgroundSpan extends ReplacementSpan {
public static final int TYPE_DASH_UNDERLINE = 1;
public static final int TYPE_BORDER_RECT = 2;
public static final int TYPE_BACKGROUND_IMAGE = 3;
private int type;
private Bitmap bitmap;
public BackgroundSpan(int type) {
this.type = type;
}
public BackgroundSpan(int type, Bitmap bitmap) {
this.type = type;
this.bitmap = bitmap;
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
return (int) paint.measureText(text, start, end);
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
RectF rectF = new RectF(x, top, x + measureText(paint, text, start, end), bottom - 5);
paint.setStrokeWidth(2.0f);
switch (type) {
case TYPE_DASH_UNDERLINE:
drawDashUnderline(canvas, paint, rectF);
break;
case TYPE_BORDER_RECT:
drawBorderRect(canvas, paint, rectF);
break;
case TYPE_BACKGROUND_IMAGE:
drawBackgourdImage(canvas, paint, rectF);
break;
}
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
canvas.drawText(text, start, end, x, y, paint);
}
// 点線の下線を描画するメソッド
private void drawDashUnderline(Canvas canvas, Paint paint, RectF rectF) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
float interval = 10;
paint.setPathEffect(new DashPathEffect(new float[]{interval, interval}, 0));
canvas.drawLine(rectF.left, rectF.bottom, rectF.right, rectF.bottom, paint);
}
// 背景色と角丸のborderを描画するメソッド
private void drawBorderRect(Canvas canvas, Paint paint, RectF rectF) {
int cornerRadius = 10;
paint.setColor(Color.LTGRAY);
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLACK);
paint.setAntiAlias(true);
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
}
// 背景画像を描画するメソッド
private void drawBackgourdImage(Canvas canvas, Paint paint, RectF rectF) {
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, rect, rectF, paint);
}
private float measureText(Paint paint, CharSequence text, int start, int end) {
return paint.measureText(text, start, end);
}
}
ここで実装したクラスを以下のように TextView
にセットしてあげると適応されます。
final String DUMMY_TEXT = "これはダミーテキストです。";
SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append(DUMMY_TEXT);
builder.setSpan(new BackgroundSpan(BackgroundSpan.TYPE_DASH_UNDERLINE), 3, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
binding.textView1.setText(builder);
binding.textView1.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
builder = new SpannableStringBuilder();
builder.append(DUMMY_TEXT);
builder.setSpan(new BackgroundSpan(BackgroundSpan.TYPE_BORDER_RECT), 3, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
binding.textView2.setText(builder);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), android.R.drawable.sym_def_app_icon);
builder = new SpannableStringBuilder();
builder.append(DUMMY_TEXT);
builder.setSpan(new BackgroundSpan(BackgroundSpan.TYPE_BACKGROUND_IMAGE, bitmap), 3, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
binding.textView3.setText(builder);
以上です。なにか他にわからない点や、間違っている点があれば、気軽にコメントしていただけると幸いです。
参考
[Android Advanced TextView](Android Advanced TextView)