EllipsizedMultilineTextView.java revision 20347e439dc5e2c86bc105d432c64f6e7f69c7cc
1c046e4a310462aa6998a34ff50439eb5e2508d85mindyp/*
2c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * Copyright (C) 2013 Google Inc.
3c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * Licensed to The Android Open Source Project.
4c046e4a310462aa6998a34ff50439eb5e2508d85mindyp *
5c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * Licensed under the Apache License, Version 2.0 (the "License");
6c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * you may not use this file except in compliance with the License.
7c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * You may obtain a copy of the License at
8c046e4a310462aa6998a34ff50439eb5e2508d85mindyp *
9c046e4a310462aa6998a34ff50439eb5e2508d85mindyp *      http://www.apache.org/licenses/LICENSE-2.0
10c046e4a310462aa6998a34ff50439eb5e2508d85mindyp *
11c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * Unless required by applicable law or agreed to in writing, software
12c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * distributed under the License is distributed on an "AS IS" BASIS,
13c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * See the License for the specific language governing permissions and
15c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * limitations under the License.
16c046e4a310462aa6998a34ff50439eb5e2508d85mindyp */
17c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
18c046e4a310462aa6998a34ff50439eb5e2508d85mindyppackage com.android.mail.ui;
19c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
20c046e4a310462aa6998a34ff50439eb5e2508d85mindypimport android.content.Context;
21c046e4a310462aa6998a34ff50439eb5e2508d85mindypimport android.text.Layout;
22c046e4a310462aa6998a34ff50439eb5e2508d85mindypimport android.text.SpannableStringBuilder;
23c046e4a310462aa6998a34ff50439eb5e2508d85mindypimport android.text.TextUtils;
24c046e4a310462aa6998a34ff50439eb5e2508d85mindypimport android.util.AttributeSet;
25c046e4a310462aa6998a34ff50439eb5e2508d85mindypimport android.widget.TextView;
26c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
27c046e4a310462aa6998a34ff50439eb5e2508d85mindyp/**
28c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * A special MultiLine TextView that will apply ellipsize logic to only the last
29c046e4a310462aa6998a34ff50439eb5e2508d85mindyp * line of text, such that the last line may be shorter than any previous lines.
30c046e4a310462aa6998a34ff50439eb5e2508d85mindyp */
31c046e4a310462aa6998a34ff50439eb5e2508d85mindyppublic class EllipsizedMultilineTextView extends TextView {
32c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
33c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    public static final int ALL_AVAILABLE = -1;
34c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    private int mMaxLines;
35c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    private int mLastWSpec;
36c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    private int mLastHSpec;
37c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
38c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    public EllipsizedMultilineTextView(Context context) {
39c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        this(context, null);
40c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    }
41c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
42c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    public EllipsizedMultilineTextView(Context context, AttributeSet attrs) {
43c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        super(context, attrs);
44c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    }
45c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
46c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    @Override
47c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    public void setMaxLines(int maxlines) {
48c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        super.setMaxLines(maxlines);
49c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        mMaxLines = maxlines;
50c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    }
51c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
52c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    @Override
53c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
54c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
55c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
56c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        mLastWSpec = widthMeasureSpec;
57c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        mLastHSpec = heightMeasureSpec;
58c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    }
59c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
60c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    /**
61c046e4a310462aa6998a34ff50439eb5e2508d85mindyp     * Ellipsize just the last line of text in this view and set the text to the
62c046e4a310462aa6998a34ff50439eb5e2508d85mindyp     * new ellipsized value.
63c046e4a310462aa6998a34ff50439eb5e2508d85mindyp     * @param text Text to set and ellipsize
64c046e4a310462aa6998a34ff50439eb5e2508d85mindyp     * @param avail available width in pixels for the last line
65c046e4a310462aa6998a34ff50439eb5e2508d85mindyp     * @param paint Paint that has the proper properties set to measure the text
66c046e4a310462aa6998a34ff50439eb5e2508d85mindyp     *            for this view
67c046e4a310462aa6998a34ff50439eb5e2508d85mindyp     */
68c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    public void setText(final CharSequence text, int avail) {
69c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        if (text == null || text.length() == 0) {
70c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            return;
71c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        }
72c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
73c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        setEllipsize(null);
74c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        setText(text, TextView.BufferType.SPANNABLE);
75c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
76c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        if (avail == ALL_AVAILABLE) {
77c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            return;
78c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        }
79c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        Layout layout = getLayout();
80c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
81c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        if (layout == null) {
82c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            measure(mLastWSpec, mLastHSpec);
83c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            layout = getLayout();
84c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        }
85c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
86c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        if (layout == null) {
87c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            // Bail
88c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            return;
89c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        }
90c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
91c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        CharSequence remainder;
92c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        SpannableStringBuilder builder = new SpannableStringBuilder();
93c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        int lineCount = layout.getLineCount();
94c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        if (lineCount <= mMaxLines) {
95c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            remainder = null;
96c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        } else {
97c046e4a310462aa6998a34ff50439eb5e2508d85mindyp            remainder = TextUtils.ellipsize(
98c046e4a310462aa6998a34ff50439eb5e2508d85mindyp                    text.subSequence(layout.getLineStart(mMaxLines - 1), text.length()),
99c046e4a310462aa6998a34ff50439eb5e2508d85mindyp                    getPaint(), avail, TextUtils.TruncateAt.END);
100c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        }
101c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
102c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        builder.append(text, 0, layout.getLineStart(mMaxLines - 1));
10320347e439dc5e2c86bc105d432c64f6e7f69c7ccAndy Huang        if (!TextUtils.isEmpty(remainder)) {
10420347e439dc5e2c86bc105d432c64f6e7f69c7ccAndy Huang            builder.append(remainder);
105c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        }
106c046e4a310462aa6998a34ff50439eb5e2508d85mindyp        setText(builder, TextView.BufferType.SPANNABLE);
107c046e4a310462aa6998a34ff50439eb5e2508d85mindyp    }
108c046e4a310462aa6998a34ff50439eb5e2508d85mindyp}