2013年6月18日火曜日

[Android] TextViewの複数行Ellipsize

TextViewの複数行末尾Ellipsizeの記事を見て前に同じのでハマったことを思い出したので、その時の方法を書きます。
    /**
     * @param view TextView
     * @param maxLines 最大行数
     * @param where 省略する箇所
     */
    public static void setMultilineEllipsize(TextView view, int maxLines, TruncateAt where) {
        if (maxLines >= view.getLineCount()) {
            // ellipsizeする必要無し
            return;
        }
        float avail = 0.0f;
        for (int i = 0; i < maxLines; i++) {
            avail += view.getLayout().getLineMax(i);
        }
        CharSequence ellipsizedText = TextUtils.ellipsize(
                view.getText(), view.getPaint(), avail, where);
        view.setText(ellipsizedText);
    }
TextUtils#ellipsize()はavailで指定された範囲に文字列をいい具合にカットしてくれるAPIです。
availはLayout#getLineMax()で指定行の描画範囲が取得できるので、それを最大行(maxLines)までの範囲を足してもとめます。

使用例

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final TextView tv = (TextView) findViewById(android.R.id.text1);
        tv.setText(R.string.attack_on_titan);
        tv.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                tv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                setMultilineEllipsize(tv, 3, TruncateAt.END);
            }
        });
    }
TextView#getLayout()などは描画後じゃないと取得できないので、OnGlobalLayoutListenerを使います。

activity_main.xml
    <TextView
        android:id="@android:id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
TextViewにellipsize,maxLinesは設定しないでください。

実行

  • Ellipsize=START, MaxLines=1

  • Ellipsize=MIDDLE, MaxLines=3

  • Ellipsize=END, MaxLines=5

  • Ellipsize=END, MaxLines=20

まとめ

このTextViewのバグでウォール・休日が破壊された。