Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Нестандартный вывод текста в TextView

#java #android #textview #customview


Необходимо вписать текст в TextView ограниченный кругом. пример 
Подскажите, в какую сторону копать
    


Ответы

Ответ 1



Написал код onDraw(Canvas canvas) своего класса наследника TextViewрешающий задачу для меня. Комментарии описываю последовательность действий: @Override protected void onDraw(Canvas canvas) { // круг, в который вписан текст canvas.drawCircle(mRadius, mRadius, mRadius, mGlowPaint); // высота строки float textHeight = mTextPaint.getFontSpacing(); // измеряем длинну текста float widthText = mTextPaint.measureText(mText); if(widthText <= mRadius*2) { // всего одна строка помещается - рисуем ее и выходим canvas.drawText(mText, mRadius, mRadius, mTextPaint); return; } // 1 Делим строку на два, сдвигаем к ближайшему пробелу. получаем индекс пробела, близкого к середине текста int centerSpace = calcCenterSpace(mText); // 2 Сначала рисуем текст вверх : String leftString = mText.substring(0, centerSpace); int cnt = 0; // количество прорисованных строк вверх float widthLine; int n; while (true) { // измеряем длинну строки widthLine = calcWidthLine(mRadius, textHeight * cnt++); // считаем сколько символов поместится в новой строке n = mTextPaint.breakText(leftString, false, widthLine, null); if (n == 0) // прерываем, так как строка слишком длинная break; // создаем строку int rest = leftString.length() - n; // проверка на последнюю строку if (rest != 0) { String s = leftString.substring(leftString.length() - n); // обрезаем до первого пробела int fixed = s.indexOf(' '); // создаем новую аккуратную строку s = s.substring(fixed + 1); // рисуем ее на высоте соответствующую данной строке canvas.drawText(s, mRadius, mRadius - textHeight * cnt + textHeight, mTextPaint); // сокращаем левый кусок текста на длинну отрисованной строки leftString = leftString.substring(0, leftString.length() - s.length()); } else { // последняя строка canvas.drawText(leftString, mRadius, mRadius - textHeight * cnt + textHeight, mTextPaint); break; } } // 3. Теперь рисуем вниз String rightString = mText.substring(centerSpace); cnt = 0; // количество прорисованных строк вверх while(true){ widthLine = calcWidthLine(mRadius, textHeight * cnt++); n = mTextPaint.breakText(rightString, false, widthLine, null); if (n == 0) // прерываем если весь текст не поместился break; int rest = rightString.length() - n; if(rest != 0) { String s = rightString.substring(0, n); int fixed = s.lastIndexOf(' '); s = s.substring(0, fixed); canvas.drawText(s, mRadius, mRadius + textHeight * cnt, mTextPaint); rightString = rightString.substring(s.length(), rightString.length()); } else { canvas.drawText(rightString, mRadius, mRadius + textHeight * cnt, mTextPaint); break; } } } private static int calcWidthLine(float r, float b){ double a = Math.sqrt(r * r - b * b); return (int)(2*a); } private static int calcCenterSpace(String text){ int index = text.length()/2; if(text.charAt(index) == ' ') return index; String subLeft = text.substring(0, index); int indexSpaceLeft = subLeft.lastIndexOf(' '); String subRight = text.substring(index + 2); int indexSpaceRight = subRight.indexOf(' '); if(index - indexSpaceLeft <= indexSpaceRight) return indexSpaceLeft; else return indexSpaceRight; } Алгоритм не идеален, на поставленную задачу выполняет. Еще в планах сделать растягивание строки. Оптимизация и недочеты приветствую. Вот скриншоты:

Ответ 2



Можно сделать кастомное view с LinearLayout, содержащий TextView различной длины. Предлагаю следующий алгоритм: Оценить размер круга, необходимый для размещения данного объема текста. Для выполнения этого шага нужно учесть остальные. Построить LinearLayout соответсвующей высоты и ширины. Разместить по строкам TextView различной длины. Длину определить по длине хорды на соответвующей высоте текста + высоты самой строки. Заполнить соответсвующие TextView текстом. Сложности могут возникнуть с переносом слов и обрывком строк не доходя до круга. Тут можно использовать свойство letter spacing: брать строки не больше заданной длины хорды и увеличивать letter-spacing, если строка меньше чем нужно. Поделиться реализацией с сообществом :-)

Ответ 3



Создайте в Drawable bg_circle.xml: Потом примените этот бекграунд к вашему TextView!

Комментариев нет:

Отправить комментарий