通常Canvasで文字列を描画する場合は[Canvas.drawText](https://developer.android.com/reference/android/graphics/Canvas.html#drawText(java.lang.String, int, int, float, float, android.graphics.Paint))を使います。
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
を作らなければいけなくて時間がかかることです。割と重大な欠点な気がするのでこの方法はあまりおすすめしません。が、他に良いやり方が思いつかず……なんか良い方法があったら教えてください!