java - que - ¿Cómo obtener el conteo de línea de vista de texto antes de renderizar?
render que es (5)
Debería usar el nuevo TextViewCompat para cambiar el tamaño del texto. Incluya la versión 26 de libs de soporte.
en tu build.gradle:
compile "com.android.support:appcompat-v7:$supportLibVersion"
En tu actividad:
TextViewCompat.setAutoSizeTextTypeUniformWithConfiguration(textView,
textMinSizeAsAnInteger,
textMaxSizeAsAnInteger,
stepIncrement,
TypedValue.COMPLEX_UNIT_PX);
¿Cómo puedo obtener el número de líneas que tomará una cadena en un TextView
antes de que se represente?
Un ViewTreeObserver
no funcionará porque solo se disparan después de que se procesa.
La respuesta aceptada no funciona cuando se coloca una palabra completa en la siguiente línea para evitar romper la palabra:
|hello |
|world! |
La única manera de estar 100% seguro sobre el número de líneas es usar el mismo motor de flujo de texto que utiliza TextView. Dado que TextView no comparte su lógica de re-flujo, aquí hay un procesador de cadenas personalizado que divide el texto en múltiples líneas, cada una de las cuales se ajusta al ancho dado. También hace todo lo posible para no romper las palabras a menos que la palabra completa no encaje:
public List<String> splitWordsIntoStringsThatFit(String source, float maxWidthPx, Paint paint) {
ArrayList<String> result = new ArrayList<>();
ArrayList<String> currentLine = new ArrayList<>();
String[] sources = source.split("//s");
for(String chunk : sources) {
if(paint.measureText(chunk) < maxWidthPx) {
processFitChunk(maxWidthPx, paint, result, currentLine, chunk);
} else {
//the chunk is too big, split it.
List<String> splitChunk = splitIntoStringsThatFit(chunk, maxWidthPx, paint);
for(String chunkChunk : splitChunk) {
processFitChunk(maxWidthPx, paint, result, currentLine, chunkChunk);
}
}
}
if(! currentLine.isEmpty()) {
result.add(TextUtils.join(" ", currentLine));
}
return result;
}
/**
* Splits a string to multiple strings each of which does not exceed the width
* of maxWidthPx.
*/
private List<String> splitIntoStringsThatFit(String source, float maxWidthPx, Paint paint) {
if(TextUtils.isEmpty(source) || paint.measureText(source) <= maxWidthPx) {
return Arrays.asList(source);
}
ArrayList<String> result = new ArrayList<>();
int start = 0;
for(int i = 1; i <= source.length(); i++) {
String substr = source.substring(start, i);
if(paint.measureText(substr) >= maxWidthPx) {
//this one doesn''t fit, take the previous one which fits
String fits = source.substring(start, i - 1);
result.add(fits);
start = i - 1;
}
if (i == source.length()) {
String fits = source.substring(start, i);
result.add(fits);
}
}
return result;
}
/**
* Processes the chunk which does not exceed maxWidth.
*/
private void processFitChunk(float maxWidth, Paint paint, ArrayList<String> result, ArrayList<String> currentLine, String chunk) {
currentLine.add(chunk);
String currentLineStr = TextUtils.join(" ", currentLine);
if (paint.measureText(currentLineStr) >= maxWidth) {
//remove chunk
currentLine.remove(currentLine.size() - 1);
result.add(TextUtils.join(" ", currentLine));
currentLine.clear();
//ok because chunk fits
currentLine.add(chunk);
}
}
Aquí hay una parte de una prueba de unidad:
String text = "Hello this is a very long and meanless chunk: abcdefghijkonetuhosnahrc.pgraoneuhnotehurc.pgansohtunsaohtu. Hope you like it!";
Paint paint = new Paint();
paint.setTextSize(30);
paint.setTypeface(Typeface.DEFAULT_BOLD);
List<String> strings = splitWordsIntoStringsThatFit(text, 50, paint);
assertEquals(3, strings.size());
assertEquals("Hello this is a very long and meanless chunk:", strings.get(0));
assertEquals("abcdefghijkonetuhosnahrc.pgraoneuhnotehurc.pganso", strings.get(1));
assertEquals("htunsaohtu. Hope you like it!", strings.get(2));
Ahora uno puede estar 100% seguro sobre el conteo de líneas en TextView sin necesidad de renderizarlo:
TextView textView = ... //text view must be of fixed width
Paint paint = new Paint();
paint.setTextSize(yourTextViewTextSizePx);
paint.setTypeface(yourTextViewTypeface);
float textViewWidthPx = ...;
List<String> strings = splitWordsIntoStringsThatFit(yourText, textViewWidthPx, paint);
textView.setText(TextUtils.join("/n", strings);
int lineCount = strings.size(); //will be the same as textView.getLineCount()
Referencia: Obtener la altura de la vista de texto antes de renderizar en el diseño
Obtener la línea de TextView antes de renderizar.
Este es mi código base el enlace de arriba. Está funcionando para mí.
private int widthMeasureSpec;
private int heightMeasureSpec;
private int heightOfEachLine;
private int paddingFirstLine;
private void calculateHeightOfEachLine() {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int deviceWidth = size.x;
widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
//1 line = 76; 2 lines = 76 + 66; 3 lines = 76 + 66 + 66
//=> height of first line = 76 pixel; height of second line = third line =... n line = 66 pixel
int heightOfFirstLine = getHeightOfTextView("A");
int heightOfSecondLine = getHeightOfTextView("A/nA") - heightOfFirstLine;
paddingFirstLine = heightOfFirstLine - heightOfSecondLine;
heightOfEachLine = heightOfSecondLine;
}
private int getHeightOfTextView(String text) {
// Getting height of text view before rendering to layout
TextView textView = new TextView(context);
textView.setPadding(10, 0, 10, 0);
//textView.setTypeface(typeface);
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.tv_size_14sp));
textView.setText(text, TextView.BufferType.SPANNABLE);
textView.measure(widthMeasureSpec, heightMeasureSpec);
return textView.getMeasuredHeight();
}
private int getLineCountOfTextViewBeforeRendering(String text) {
return (getHeightOfTextView(text) - paddingFirstLine) / heightOfEachLine;
}
Nota: Este código también debe configurarse para una vista textual real en la pantalla
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources().getDimension(R.dimen.tv_size_14sp));
Si conoce o puede determinar el ancho del elemento primario de TextView, puede invocar una medición de vista que resulte en el recuento de línea que se calcula.
val parentWidth = PARENT_WIDTH // assumes this is known/can be found
myTextView.measure(
MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED))
El diseño de TextView ya no es nulo y puede verificar el conteo de líneas calculado con myTextView.lineCount
.
Rect bounds = new Rect();
Paint paint = new Paint();
paint.setTextSize(currentTextSize);
paint.getTextBounds(testString, 0, testString.length(), bounds);
Ahora divida el ancho del texto con el ancho de su TextView para obtener el número total de líneas.
int numLines = (int) Math.ceil((float) bounds.width() / currentSize);