お世話になります。
縦幅固定で、改行を含め、文字サイズを縮小して表示するTextViewを作りたいと思っています。
方法としては、まず、TextViewを継承したクラスを作ります。
そして、onLayout時に「改行を含めた表示するTextの高さ」を計算し、「TextViewの固定の高さ」と比べ、「改行を含めたTextの高さ」が「TextViewの固定高さ」より大きい場合、textSizeを小さくして、
「改行を含めたTextの高さ」を計算仕直し(ループ)、最終的に「改行を含めたTextの高さ」が「TextViewの固定高さ」より小さくなったら、そのtextSizeで文字列を表示する
という方法です。
実装して動かしてみましたが、想定した動きになりませんでした。
その原因は、以下のTextPaint#breakTextにあると思っています。
index = paint.breakText(text, 0, text.length(), true, maxTextViewWidth, null);
このメソッドは、TextViewの横幅に、指定した文字列を、どの文字まで表示できるか(正確には表示可能な文字列のindex)を返却するメソッドと認識しています。
しかし、実機でビルドして文字を表示した場合と、LogCatで表示されるTextPaint#breakTextの実行結果が一致しません。
今回は、「Piyo Hogeo boost」という文字列を表示します。
TextPaint#breakTextの結果をLogCatで表示されると、以下のようになるのですが、
一行目は、'Piyo H'
二行目は、'ogeo b'
三行目は、'oost'
実機表示(端末は、SO-02G)すると、
一行目は、'Piyo'
二行目は、'Hogeo'
三行目は、'boost'
になります。
質問内容としては、
・TextPaint#breakTextが誤った表示可能なindexを返すことってありますか?
・誰か正常に動作するように教えていただけますか?
以上、わかりにくい説明で申し訳ありませんが、どなたかご教授よろしくお願い致します。
なお、以下は、詳細ソースになります。
-- HeightResizeTextVie.java --
public class HeightResizeTextView extends TextView {
private static final String TAG = HeightResizeTextView.class.getSimpleName();
public HeightResizeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
resize();
}
private void resize() {
// TextViewの縦幅
int viewHeight = getHeight();
// TextViewの横幅
int viewWidth = getWidth();
int textSize = (int) getTextSize();
// 「TextViewの高さ」と「改行含めたTextの高さ」を比べた時に、「改行含めたTextの高さ」が大きい場合に、textSizeを小さくして、「改行含めたTextの高さ」を計算し直す。
while (getHeightOfMultiLineText(getText().toString(), textSize, viewWidth) > viewHeight) {
textSize--;
}
setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
// 改行を含めたTextの高さを計算する
public int getHeightOfMultiLineText(String text, int textSize, int maxWidth) {
TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG);
paint.setSubpixelText(true);
paint.setTypeface(getTypeface());
paint.setTextSize(textSize);
int index = 0;
int linecount = 0;
while (index < text.length() - 1) {
int pre = index;
// 横幅に収まる文字列長のindexを返す。文字列長よりindexが小さいという事は、改行する事になる <= ※ここが問題
index += paint.breakText(text, index, text.length(), true, maxWidth, null);
linecount++;
int aft = index;
android.util.Log.e(TAG, String.format("index='%d' subStr='%s' lineCount='%d'", index, text.substring(pre, aft), linecount));
}
Rect bounds = new Rect();
paint.getTextBounds("Py", 0, 2, bounds);
double lineSpacing = Math.max(0, ((linecount - 1) * bounds.height() * 0.25));
return (int) Math.floor(lineSpacing + linecount * bounds.height());
}
}
-- MainActivity.java --
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
}
}
-- content_main.xml --
<?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<jp.meteostrike.dynamictextview.HeightResizeTextView
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@drawable/background"
android:text="Piyo Hogeo boost"
android:textSize="300sp" />
</RelativeLayout>
-- background.xml --
<?xml version="1.0" encoding="utf-8"?>
<item android:state_pressed="false">
<shape android:shape="rectangle">
<solid android:color="#FFFDF9" />
<stroke android:width="1dp" android:color="#DB4A37" />
</shape>
</item>
</selector>
-- LogCatで表示されるTextPaint#breakTextの実行結果 --
03-04 17:30:01.474 30017-30017/jp.hoge.dynamictextview E/HeightResizeTextView: index='6' subStr='Piyo H' lineCount='1'
03-04 17:30:01.474 30017-30017/jp.hoge.dynamictextview E/HeightResizeTextView: index='12' subStr='ogeo b' lineCount='2'
03-04 17:30:01.474 30017-30017/jp.hoge.dynamictextview E/HeightResizeTextView: index='16' subStr='oost' lineCount='3'