krikor Herlopian
krikor Herlopian

Reputation: 731

ellipsize not working with Textview

This 2 works

 <TextView
    android:id="@+id/item2"
    android:layout_below="@id/item1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="middle"
    android:singleLine="true"
    android:paddingLeft="10dp"
    android:paddingRight="120dp"
    android:paddingTop="5dp" />

  <TextView
    android:id="@+id/item2"
    android:layout_below="@id/item1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="end"
    android:maxLines="3"
    android:paddingLeft="10dp"
    android:paddingRight="120dp"
    android:paddingTop="5dp" />

This does not work

  <TextView
    android:id="@+id/item2"
    android:layout_below="@id/item1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="middle"
    android:maxLines="3"
    android:paddingLeft="10dp"
    android:paddingRight="120dp"
    android:paddingTop="5dp" />

So, what is the soluton. and why such incosistency? Why does it work when I HAVE ellipsize end and maxlines, but not when i have ellipsize middle and max lines. And why it works with singleline as well the ellipsize middle and not on maxlines? Thank You for help. I need ellipsize middle and maxlines 3.

Upvotes: 4

Views: 8212

Answers (4)

Daniel
Daniel

Reputation: 11

 fun ellipsize(
    textView: TextView,
    originText: CharSequence,
    maxLines: Int,
    truncateAt: TruncateAt
): CharSequence {
    val availableWidth =
        textView.width - textView.paddingEnd - textView.paddingStart - textView.compoundDrawablePadding * 2
    val textWidth = textView.paint.measureText(originText.toString())
    // gt 1 line.
    if (textWidth / availableWidth > 0) {
        val realLine = min((textWidth + availableWidth - 1).toInt() / availableWidth, maxLines)
        return TextUtils.ellipsize(
            textView.text,
            textView.paint,
            min(availableWidth * realLine.toFloat(), textWidth),
            truncateAt
        )
    }
    return originText
}

hope this helps.

Upvotes: 0

Sabri Mevis
Sabri Mevis

Reputation: 2431

I also made a custom TextView regarding to @deadfish answer. If you don't want to lose your words you may use this; It removes the previous word of the last word in the sentence if It does not fit the line. like;

This is a good sentence. -> This is a .. sentence.

private String smartTrim__word_cut(String input,int visible){
    int visibleLength = visible;
    int textSize = input.length();//input.length();
    Boolean hasDot = false;
    String visibleText = "";

    while(textSize > visibleLength)
    {
        // To ArrayList
        List<String> l2 = new ArrayList<>(Arrays.asList(input.split(" ")));

        if(!hasDot){
            l2.set(l2.size()-2, "..");
            hasDot = true;
        }
        else{
            l2.remove(l2.size()-3);
        }

        StringBuilder listString = new StringBuilder();
        for (String s : l2){
            listString.append(s+" ");
        }
        visibleText = listString.toString().trim();
        textSize = visibleText.length();
        input = visibleText;
    }
    return visibleText;
}

NOTE: It may also cut the first sentence in some cases and make it like; ".. sentence". Needs to be improved.

Upvotes: -1

deadfish
deadfish

Reputation: 12304

Here is information from documentation of TextView

public void setEllipsize (TextUtils.TruncateAt where)
Added in API level 1

Causes words in the text that are longer than the view is wide to be ellipsized instead of broken in the middle. You may also want to setSingleLine() or setHorizontallyScrolling(boolean) to constrain the text to a single line. Use null to turn off ellipsizing. If setMaxLines(int) has been used to set two or more lines, only END and MARQUEE are supported (other ellipsizing types will not do anything).


However I've made very simple ellipsize="middle" for multiline. Of course it should be more upgraded in free time but here it is.

This is class of widget to paste into root of package

import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;

public class MiddleMultilineTextView extends TextView {

    private String SYMBOL = " ... ";
    private final int SYMBOL_LENGTH = SYMBOL.length();

    public MiddleMultilineTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (getMaxLines() > 1) {
            int originalLength = getText().length();
            int visibleLength = getVisibleLength();

            if (originalLength > visibleLength) {
                setText(smartTrim(getText().toString(), visibleLength - SYMBOL_LENGTH));
            }
        }
    }

    private String smartTrim(String string, int maxLength) {
        if (string == null)
            return null;
        if (maxLength < 1)
            return string;
        if (string.length() <= maxLength)
            return string;
        if (maxLength == 1)
            return string.substring(0, 1) + "...";

        int midpoint = (int) Math.ceil(string.length() / 2);
        int toremove = string.length() - maxLength;
        int lstrip = (int) Math.ceil(toremove / 2);
        int rstrip = toremove - lstrip;

        String result = string.substring(0, midpoint - lstrip) + SYMBOL + string.substring(midpoint + rstrip);
        return result;
    }

    private int getVisibleLength() {
        int start = getLayout().getLineStart(0);
        int end = getLayout().getLineEnd(getMaxLines() - 1);
        return getText().toString().substring(start, end).length();
    }
}

This is custom widget to use in layout:

<com.example.middlemultiline.MiddleMultilineTextView
        android:id="@+id/item2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="middle"
        android:maxLines="4"
        android:text="Months earlier, in May 2007, a typically busy time for construction work, he sat home for two weeks without any jobs lined up, the first time that had ever happened in all the years he’d been an independent contractor. It was an early indication that hard times were ahead. By fall, he tried to find a steady job with a construction company but by then no one was hiring. And now he no longer had the extra income to support his wife’s entrepreneurial effort — a coffee vending machine business — so that went under too." />

Result:

preview

Code was based on:
https://stackoverflow.com/a/8798989/619673
https://stackoverflow.com/a/831583/619673

Upvotes: 10

Amit Desale
Amit Desale

Reputation: 1291

Actually android:ellipsize="end" itself means you have a content with elip working at end so must have to use android:singleLine="true" See documentation here

Upvotes: -1

Related Questions