Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
9
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@niusounds

Canvasで文字列を描画する時に長かったら勝手に改行してほしいし長過ぎたら省略したかったのでやってみた

通常Canvasで文字列を描画する場合はCanvas.drawTextを使います。

canvas.drawText(text, x, y, paint);

この方法は文字列中に改行があっても無視します。また、文字列が長くて描画領域に収まらない時に勝手に折り返すような親切な機能はありません。
つまり、確実に1行しかなく表示する文字列の長さが予想できる場合にしか使えないということです。

改行されていたら改行表示したいし、Canvasをはみ出るくらい長い時は折り返したい。そういう場合はStaticLayoutを使います。

// 最初にStaticLayoutを作る。widthは描画領域の幅。1行の文字列がこの幅を超えると、自動で折り返す。
StaticLayout staticLayout = new StaticLayout(text, paint, width, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);

// staticLayout.drawで描画する。座標を指定できないので、まずCanvasの座標を動かしてから描画している。
canvas.save();
canvas.translate(x, y);
staticLayout.draw(canvas);
canvas.restore();

ここまでで要望の一つである勝手に改行してほしいは実現できます。しかしこの方法ではもう一つの要望である長過ぎたら省略してほしいはできません。

どうれば実現できるかいろいろやり方を考えたのですが、最終的にStaticLayoutを作成した後に行数をチェックして、オーバーしている場合は文字列の末尾を削除して「…」を付けるというのを指定行数以内に収まるまで繰り返すという力技で実装することにしました…

// タイトルが長すぎる場合は2行で収まるようになるまで短くする
StringBuilder sb = new StringBuilder(text);
while (true) {

  staticLayout = new StaticLayout(sb, paint, width - 16, Layout.Alignment.ALIGN_NORMAL, 1, 0, true);

  if (staticLayout.getLineCount() > 2) {
    // 最後の二文字を削除して、… を付ける
    sb.delete(sb.length() - 2, sb.length());
    sb.append("…");
    continue;
  }

  break;
}

この方法の欠点は極端に入力文字列が長い場合はループを抜けるまでに多数のStaticLayoutを作らなければいけなくて時間がかかることです。割と重大な欠点な気がするのでこの方法はあまりおすすめしません。が、他に良いやり方が思いつかず……なんか良い方法があったら教えてください!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
9
Help us understand the problem. What are the problem?