Как узнать, было ли мое текстовое представление увеличено в виде многоточия?

У меня есть многострочный TextView, в котором установлено android:ellipsize="end". Однако я хотел бы знать, действительно ли строка, которую я помещаю туда, слишком длинная (чтобы я мог убедиться, что полная строка отображается в другом месте на странице).

Я мог бы использовать TextView.length() и найти приблизительную длину строки, но, поскольку это несколько строк, TextView определяет, когда переносить, поэтому это не всегда сработает.

Любые идеи?


person FrederickCook    schedule 23.10.2010    source источник


Ответы (18)


Вы можете получить макет TextView и проверить количество многоточий в строке. Для конечного многоточия достаточно проверить последнюю строку, например:

Layout l = textview.getLayout();
if (l != null) {
    int lines = l.getLineCount();
    if (lines > 0)
        if (l.getEllipsisCount(lines-1) > 0)
            Log.d(TAG, "Text is ellipsized");
}

Это работает только после фазы макета, в противном случае возвращенный макет будет нулевым, поэтому вызовите это в соответствующем месте вашего кода.

person Thorstenvv    schedule 24.10.2010
comment
Это не сработает, если вы введете длинный текст без пробелов в последней строке ввода, что-то вроде jashdkjashdkjashdkasjhdashdkasjdhkajsdhkasjdhakjshdksjahdaksjhdajkshdkajshdkjashdkjashdja. getEllipsisCount () в этом случае вернет 0. Чтобы исправить это, вместо проверки только последней строки вы должны перебрать все строки и проверить, возвращает ли (l.getEllipsisCount (n) ›0) true; для всех 0 ‹= n‹ строк. - person Bitcoin Cash - ADA enthusiast; 05.02.2015
comment
Из-за ошибки в функции getEllipsisCount в API ‹= 14 она завершится ошибкой и вернет 0, если текст содержит специальные символы, такие как '\ n'. Таким образом, вы можете обойти это, используя библиотеки поддержки и заменив if (l.getEllipsisCount(lines-1) > 0) на if (l.getEllipsisCount(lines-1) > 0 || TextViewCompat.getMaxLines(this)). - person Bam; 19.05.2017
comment
Ух, используйте скобки даже для однострочного оператора, если пожалуйста - person r3flss ExlUtr; 24.11.2017
comment
@ r3flssExlUtr, а почему именно? - person zarsky; 06.11.2018
comment
Не могли бы вы пояснить, что вы имеете в виду под этапом верстки. Вы имеете в виду, когда макет раздувается, и почему позже он станет нулевым? - person 6rchid; 31.05.2019
comment
@NocTurn TextView должен уже выполнить внутреннюю разметку текста. Обычно это происходит при верстке. Безопасная ставка - установить слушателя на onGlobalLayout (см. Ответ Химаншу Вирмани) или onPreDraw. Макет может стать нулевым позже, когда в TextView будут внесены изменения, например, будет установлен новый текст, что потребует создания нового внутреннего макета текста. Обратите внимание, что это не имеет ничего общего с раздуванием макета (android.text.Layout по сравнению с концепцией макета как иерархии представлений). - person Thorstenvv; 05.06.2019
comment
1. данная ошибка макет классификатора не имеет сопутствующего объекта при использовании Layout типа в Kotlin. 2. Функция getEllipsisCount вернула 0. пожалуйста, помогите мне - person NIKUNJ GADHIYA; 01.01.2020

textView.getLayout - это путь, но проблема в том, что он возвращает null, если макет не подготовлен. Используйте решение ниже.

 ViewTreeObserver vto = textview.getViewTreeObserver();
    vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
           Layout l = textview.getLayout();
           if ( l != null){
              int lines = l.getLineCount();
              if ( lines > 0)
                  if ( l.getEllipsisCount(lines-1) > 0)
                    Log.d(TAG, "Text is ellipsized");
           }  
        }
    });

Фрагмент кода для удаления слушателя (исходный код):

mLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    public void onGlobalLayout() {
        scrollToGridPos(getCenterPoint(), false);
        mLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);        
    }
});
person Himanshu Virmani    schedule 08.10.2013
comment
Не забывайте removeOnGlobalLayoutListener(), когда он вам больше не нужен. - person mmathieum; 16.12.2013
comment
Добавьте это, когда будет найдено многоточие: if (Build.VERSION.SDK_INT ‹16) {textview.getViewTreeObserver (). RemoveGlobalOnLayoutListener (this); } еще {textview.getViewTreeObserver (). removeOnGlobalLayoutListener (это); } - person Daniel Wilson; 09.04.2014
comment
Используйте view.post (), а не VTO! Все намного проще. - person a person; 28.04.2015
comment
Более того, используйте скобки даже для однострочного оператора ifs - person r3flss ExlUtr; 24.11.2017
comment
1. данная ошибка макет классификатора не имеет сопутствующего объекта при использовании Layout типа в Kotlin. 2. Функция getEllipsisCount вернула 0. пожалуйста, помогите мне - person NIKUNJ GADHIYA; 01.01.2020

Думаю, самым простым решением этого вопроса является следующий код:

String text = "some looooong text";
textView.setText(text);
boolean isEllipsize = !((textView.getLayout().getText().toString()).equalsIgnoreCase(text));

Этот код предполагает, что в вашем XML TextView установлен maxLineCount :)

person Francesco Florio    schedule 06.11.2015
comment
ленивый, но эффективный :-D - person msamardzic; 22.07.2016
comment
Ваш тест завершится неудачно, если для сортировки заданы заглавные буквы. Добавьте вызовы toLowerCase () к обеим строкам. - person Yarh; 28.04.2017
comment
Если ваш textView.getLayout () возвращает null, вы должны использовать: final ViewTreeObserver vto = tv.getViewTreeObserver (); vto.addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener () {@Override public void onGlobalLayout () {tv.getViewTreeObserver (). removeOnGlobalLayoutListener (this); Layoutay layout (tv.get) toString ()). equalsIgnoreCase (текст))) {// в многоточии} else {// НЕ в многоточии}}}); - person Royz; 03.10.2018
comment
Это нужно сделать после того, как textView отобразит текст. textView.post (() - ›{// сделай это здесь}) - person Sarith Nob; 11.03.2019
comment
Странно, что длина обоих объектов одинакова, но они отличаются от того, что видно. - person Sufian; 30.04.2019
comment
Предложение @SarithNOB заставило это решение работать для меня. - person Michael Osofsky; 17.08.2019
comment
Я обнаружил, что это хорошее решение, если в вашем xml есть singleLine = true. - person jj.; 26.08.2020

Это сработало для меня:

textView.post(new Runnable() {
                        @Override
                        public void run() {
                            if (textView.getLineCount() > 1) {
                                //do something
                            }
                        }
                    });
person Cícero Moura    schedule 27.07.2018
comment
спас мне день, потому что ViewTreeObserver плохо работает в RecyclerView - person kilian eller; 07.03.2019

public int getEllipsisCount (int line):

Возвращает количество символов, которые нужно удалить с помощью многоточия, или 0, если многоточие не требуется.

Итак, просто позвоните:

int lineCount = textview1.getLineCount();

if(textview1.getLayout().getEllipsisCount(lineCount) > 0) {
   // Do anything here..
}

Поскольку getLayout () не может быть вызван до установки макета, используйте это:

ViewTreeObserver vto = textview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
       Layout l = textview.getLayout();
       if ( l != null){
          int lines = l.getLineCount();
          if ( lines > 0)
              if ( l.getEllipsisCount(lines-1) > 0)
                Log.d(TAG, "Text is ellipsized");
       }  
    }
});

И, наконец, не забудьте удалить removeOnGlobalLayoutListener, когда он вам больше понадобится.

person amalBit    schedule 21.02.2014
comment
Вы можете изменить ответ на правильный. @FrancescoDonzello - person amalBit; 29.10.2014
comment
Может быть, код не превосходен, но подход точно такой. Это решило мою проблему с определением, был ли текст увеличен. Этот подход очень полезен, когда вы добавляете представления в окно через оконный менеджер. - person Yoraco Gonzales; 29.01.2015
comment
К сожалению, похоже, что если многоточие встречается прямо в пустой строке (\ n), оно тоже возвращает 0, что правильно, поскольку это происходит в индексном символе 0. Так что в этом случае это не способ сказать ... - person Shyri; 06.09.2017

Самым красноречивым решением, которое я нашел (в Котлине), является создание функции расширения на TextView

fun TextView.isEllipsized() = layout.text.toString() != text.toString()

Это замечательно, потому что не нужно знать, что такое полная строка, или беспокоиться о том, сколько строк использует TextView.

TextView.text - это полный текст, который он пытается показать, а TextView.layout.text - это то, что на самом деле отображается на экране, поэтому, если они разные, он должен быть увеличен в многоточие

Чтобы использовать это:

if (my_text_view.isEllipsized()) {
    ...
}
person Matt Smith    schedule 07.01.2021

lateinit var toggleMoreButton: Runnable
toggleMoreButton = Runnable {
  if(reviewTextView.layout == null) { // wait while layout become available
       reviewTextView.post(toggleMoreButton) 
       return@Runnable
  }
  readMoreButton.visibility = if(reviewTextView.layout.text.toString() != comment) View.VISIBLE else View.GONE
}
reviewTextView.post(toggleMoreButton)

Это какой-то типичный случай:

  1. комментарий в 'reviewTextView'
  2. комментарий может быть свернут по некоторым критериям
  3. если комментарий свернут, вы показываете кнопку readMoreButton
person A.Y.    schedule 22.12.2018
comment
Этот ответ можно сделать более полезным с кратким текстовым объяснением кода. - person charleslparker; 22.12.2018
comment
Я должен сказать, что это было коротко и точно, и было написано на котлине. - person Raykud; 08.03.2019

Котлинский путь:

textView.post {
   if (textView.lineCount > MAX_LINES_COLLAPSED) {
   // text is not fully displayed
   }
}

Фактически View.post() выполняется после рендеринга представления и запускает предоставленную функцию

person 4ndro1d    schedule 24.09.2019

Простой метод Котлина. Позволяет использовать android:ellipsize и android:maxLines

fun isEllipsized(textView: TextView, text: String?) = textView.layout.text.toString() != text
person Chaseos    schedule 01.09.2020
comment
Здравствуйте, я понимаю, что вы преобразовали его в kotlin, но, похоже, уже есть ответ, делающий то же самое, что и в java. В следующий раз, возможно, вы сможете отредактировать существующий ответ или, может быть, предложить редактирование в комментарии к ответу вместо добавления совершенно нового ответа. Удачного кодирования !! - person because_im_batman; 01.09.2020

это работает для меня

if (l != null) {
    int lines = l.getLineCount();
     if (lines > 0) {
     for (int i = 0; i < lines; i++) {
     if (l.getEllipsisCount(i) > 0) {
      ellipsize = true;
      break;
     }
    }
   }
  }
person coffee    schedule 29.08.2016

Действительно работает так, например, чтобы передать полные данные в диалог из элемента RecyclerView:

holder.subInfo.post(new Runnable() {
                @Override
                public void run() {
                    Layout l = holder.subInfo.getLayout();
                    if (l != null) {
                        final int count = l.getLineCount();
                        if (count >= 3) {
                            holder.subInfo.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    final int c = holder.subInfo.getLineCount();
                                    if (c >= 3) {
                                        onClickToShowInfoDialog.showDialog(holder.title.getText().toString(), holder.subInfo.getText().toString());
                                    }
                                }
                            });
                        }
                    }
                }
            });
person nicolas asinovich    schedule 13.05.2018

Комбинируя @Thorstenvv awnser с @Tiano fix, вот версия Kotlin:

val layout = textView.layout ?: return@doOnLayout
val lines = layout.lineCount
val hasLine = lines > 0
val hasEllipsis = ((lines - 1) downTo 0).any { layout.getEllipsisCount(it) > 0 }
if (hasLine && hasEllipsis) {
    // Text is ellipsized
}
person Victor    schedule 29.10.2019

В Kotlin вы можете использовать приведенный ниже код.

var str= "Kotlin is one of the best languages."
textView.text=str
textView.post {
val isEllipsize: Boolean = !textView.layout.text.toString().equals(str)

if (isEllipsize) {
     holder.itemView.tv_viewMore.visibility = View.VISIBLE
} else {
     holder.itemView.tv_viewMore.visibility = View.GONE
}    
}
person hetsgandhi    schedule 20.06.2020

Это простая библиотека для создания расширяемого текстового представления. Типа "Продолжить" или "Меньше". Это расширенная версия библиотеки TextView. Легко использовать.

implementation 'com.github.mahimrocky:ShowMoreText:1.0.2'

Вот так 1 https://raw.githubusercontent.com/mahimrocky/ShowMoreText/master/screenshot1.png

2 https://raw.githubusercontent.com/mahimrocky/ShowMoreText/master/screenshot2.png

 <com.skyhope.showmoretextview.ShowMoreTextView
    android:id="@+id/text_view_show_more"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@string/text"
    />

В Activity вы можете использовать как:

ShowMoreTextView textView = findViewById(R.id.text_view_show_more);

//You have to use following one of method    

// For using character length
textView.setShowingChar(numberOfCharacter);
//number of line you want to short
textView.setShowingLine(numberOfLine);
person Gershon Tusson    schedule 04.02.2021

Если ваше текстовое представление содержит несколько абзацев, использование getEllipsisCount не будет работать для пустых строк внутри него. getEllipsisCount для последней строки любого абзаца вернет 0.

person Duke Caesar    schedule 19.04.2021

Решение с расширениями kotlin:

infoText.afterLayoutConfiguration {
    val hasEllipsize = infoText.hasEllipsize()
    ...
}

Расширения:

/**
 * Function for detect when layout completely configure.
 */
fun View.afterLayoutConfiguration(func: () -> Unit) {
    viewTreeObserver?.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            viewTreeObserver?.removeOnGlobalLayoutListener(this)
            func()
        }
    })
}

fun TextView.hasEllipsize(): Boolean = layout.getEllipsisCount(lineCount - 1) > 0
person SerjantArbuz    schedule 20.05.2021

Использование getEllipsisCount не будет работать с текстом, в котором есть пустые строки. Я использовал следующий код, чтобы он заработал:

message.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {

            if(m.isEllipsized == -1) {
                Layout l = message.getLayout();
                if (message.getLineCount() > 5) {
                    m.isEllipsized = 1;
                    message.setMaxLines(5);
                    return false;
                } else {
                    m.isEllipsized = 0;
                }
            }
            return true;
        }
    });

Убедитесь, что в вашем XML не установлено maxLineCount. Затем вы можете проверить lineCount в своем коде, и если он больше определенного числа, вы можете вернуть false, чтобы отменить рисование TextView и установить количество строк, а также флаг, чтобы сохранить, не слишком ли длинное текстовое представление или нет. Текстовое представление снова будет рисоваться с правильным количеством строк, и вы узнаете, имеет ли он многоточие или нет флаг.

Затем вы можете использовать флаг isEllipsized, чтобы делать все, что вам нужно.

person js123    schedule 14.02.2015

создайте метод внутри своего класса TextViewUtils

public static boolean isEllipsized(String newValue, String oldValue) {
    return !((newValue).equals(oldValue));
}

вызовите этот метод, когда это необходимо, например:

        if (TextViewUtils.isEllipsized(textviewDescription.getLayout().getText().toString(), yourModelObject.getDescription()))
            holder.viewMore.setVisibility(View.VISIBLE);//show view more option
        else
            holder.viewMore.setVisibility(View.GONE);//hide 

но textView.getLayout () не может вызвать до установки представления (макета).

person Abdul Rizwan    schedule 28.03.2017