改行を含め、文字サイズを縮小して表示するTextViewを作りたい(しかし、TextPaint#breakTextの実行結果がおかしいので、うまくいかない状態)

565 views
Skip to first unread message

helloooideeeeea

unread,
Mar 4, 2016, 4:45:24 AM3/4/16
to 日本Androidの会
お世話になります。

縦幅固定で、改行を含め、文字サイズを縮小して表示する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"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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'
Piyo_Maman_boost.png
Reply all
Reply to author
Forward
0 new messages