LoginSignup
4
5

More than 5 years have passed since last update.

ReplacementSpanでTextViewの一部を装飾する

Last updated at Posted at 2016-09-05

例えばTextViewの一部をリンクにしたり、一部を強調したい、などの時にTextViewの一部に装飾したいときってありますよね?
実はTextViewはSpannableStringを使うことにより、一部を装飾したり、リンクにしたりといったことは簡単にできます。

詳しい内容は @wasabeef_jp さんの投稿 Android Advanced TextView にまとまっているのでそちらを参照してください。

今回は、その中で ReplacementSpan を使って背景や点線の下線の描画などをやりたいと思います。

といってもとても簡単で、 ReplacementSpan を継承したクラスを作り、 draw メソッドをオーバーライドして上げてそこで Canvas に描画してあげるだけです。
ね、簡単でしょう?

サンプル

文章だけでもいいかな、と思ったんですがてきとーに実装もしたんで紹介します。
手順としては、先に下線や背景を描画したあとに、Textを描画してあげます。

スクリーンショット

上から、順に

  • 点線の下線
  • 背景色と角丸のborder
  • drawable の背景画像

スクリーンショット 2016-09-05 16.34.23.png

サンプルコード

今回実装したものは以下のようになります。

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

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5