¿Justifica el texto en una aplicación de Android usando un WebView pero presentando una interfaz tipo TextView?

Estoy buscando una manera simple de olvidar que estoy usando un WebView para justificar el texto en mi TextView . ¿Alguien ha hecho una vista personalizada para esto? Soy muy consciente de que puedo hacer algo como esto:

  WebView view = new WebView(this); view.loadData("my html with text justification","text/html","utf-8"); 

Pero se pone feo cuando desea establecer el tamaño, el color u otras propiedades comunes de TextView . Debe haber una manera más conveniente de hacerlo.

Me estaba poniendo de los nervios, lo admito. Me gusta que las TextViews vean como TextViews en el código, e incluso si estoy usando una WebView como medio para lograr el formato text-align: justified, no quiero verlo de esa manera.

TextView una vista personalizada (fea, probablemente mala) que implementa los métodos que utilizo comúnmente en TextView y modifica el contenido de WebView para reflejar esos cambios. Ya sea que sea útil para otra persona o un riesgo potencial que realmente no conozco, para mí funciona, lo he usado en varios proyectos y no he tenido problemas. El único inconveniente menor es que lo asumo como un peaje más grande en cuanto a la memoria pero no hay nada de qué preocuparse si solo es uno o dos (corrígeme si me equivoco).

El resultado es el siguiente:

enter image description here

Y el código para configurarlo programáticamente es tan simple como esto:

  JustifiedTextView J = new JustifiedTextView(); J.setText("insert your text here"); 

Por supuesto, sería estúpido dejarlo así, así que también agregué los métodos para cambiar el tamaño de fuente y el color de fuente, que son básicamente todo lo que uso TextViews. Lo que significa que puedo hacer algo como esto:

  JustifiedTextView J = new JustifiedTextView(); J.setText("insert your text here"); J.setTextColor(Color.RED); J.setTextSize(30); 

Y obtenga el siguiente resultado (las imágenes se recortan):

enter image description here

¡Pero esto no es para mostrarnos cómo se ve, sino para compartir cómo lo ha hecho!

Sé que sé. Aquí está el código completo. También aborda los problemas al establecer fondo transparente y cargar cadenas UTF-8 en la vista. Vea los comentarios en reloadData () para más detalles.

 public class JustifiedTextView extends WebView{ private String core = "%s"; private String textColor = "0,0,0,255"; private String text = ""; private int textSize = 12; private int backgroundColor=Color.TRANSPARENT; public JustifiedTextView(Context context, AttributeSet attrs) { super(context, attrs); this.setWebChromeClient(new WebChromeClient(){}); } public void setText(String s){ this.text = s; reloadData(); } @SuppressLint("NewApi") private void reloadData(){ // loadData(...) has a bug showing utf-8 correctly. That's why we need to set it first. this.getSettings().setDefaultTextEncodingName("utf-8"); this.loadData(String.format(core,textColor,textSize,text), "text/html","utf-8"); // set WebView's background color *after* data was loaded. super.setBackgroundColor(backgroundColor); // Hardware rendering breaks background color to work as expected. // Need to use software renderer in that case. if(android.os.Build.VERSION.SDK_INT >= 11) this.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null); } public void setTextColor(int hex){ String h = Integer.toHexString(hex); int a = Integer.parseInt(h.substring(0, 2),16); int r = Integer.parseInt(h.substring(2, 4),16); int g = Integer.parseInt(h.substring(4, 6),16); int b = Integer.parseInt(h.substring(6, 8),16); textColor = String.format("%d,%d,%d,%d", r, g, b, a); reloadData(); } public void setBackgroundColor(int hex){ backgroundColor = hex; reloadData(); } public void setTextSize(int textSize){ this.textSize = textSize; reloadData(); } } 

Sin la solución webview es: https://github.com/merterhk/JustifiedTextView

 import java.util.ArrayList; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Typeface; import android.text.TextPaint; import android.view.View; public class JustifiedTextView extends View { String text; ArrayList linesCollection = new ArrayList(); TextPaint textPaint; Typeface font; int textColor; float textSize = 42f, lineHeight = 57f, wordSpacing = 15f, lineSpacing = 15f; float onBirim, w, h; float leftPadding, rightPadding; public JustifiedTextView(Context context, String text) { super(context); this.text = text; init(); } private void init() { textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textColor = Color.BLACK; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (font != null) { font = Typeface.createFromAsset(getContext().getAssets(), "font/Trykker-Regular.ttf"); textPaint.setTypeface(font); } textPaint.setColor(textColor); int minw = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth(); w = resolveSizeAndState(minw, widthMeasureSpec, 1); h = MeasureSpec.getSize(widthMeasureSpec); onBirim = 0.009259259f * w; lineHeight = textSize + lineSpacing; leftPadding = 3 * onBirim + getPaddingLeft(); rightPadding = 3 * onBirim + getPaddingRight(); textPaint.setTextSize(textSize); wordSpacing = 15f; Line lineBuffer = new Line(); this.linesCollection.clear(); String[] lines = text.split("\n"); for (String line : lines) { String[] words = line.split(" "); lineBuffer = new Line(); float lineWidth = leftPadding + rightPadding; float totalWordWidth = 0; for (String word : words) { float ww = textPaint.measureText(word) + wordSpacing; if (lineWidth + ww + (lineBuffer.getWords().size() * wordSpacing) > w) {// is lineBuffer.addWord(word); totalWordWidth += textPaint.measureText(word); lineBuffer.setSpacing((w - totalWordWidth - leftPadding - rightPadding) / (lineBuffer.getWords().size() - 1)); this.linesCollection.add(lineBuffer); lineBuffer = new Line(); totalWordWidth = 0; lineWidth = leftPadding + rightPadding; } else { lineBuffer.setSpacing(wordSpacing); lineBuffer.addWord(word); totalWordWidth += textPaint.measureText(word); lineWidth += ww; } } this.linesCollection.add(lineBuffer); } setMeasuredDimension((int) w, (int) ((this.linesCollection.size() + 1) * lineHeight + (10 * onBirim))); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawLine(0f, 10f, getMeasuredWidth(), 10f, textPaint); float x, y = lineHeight + onBirim; for (Line line : linesCollection) { x = leftPadding; for (String s : line.getWords()) { canvas.drawText(s, x, y, textPaint); x += textPaint.measureText(s) + line.spacing; } y += lineHeight; } } public String getText() { return text; } public void setText(String text) { this.text = text; } public Typeface getFont() { return font; } public void setFont(Typeface font) { this.font = font; } public float getLineHeight() { return lineHeight; } public void setLineHeight(float lineHeight) { this.lineHeight = lineHeight; } public float getLeftPadding() { return leftPadding; } public void setLeftPadding(float leftPadding) { this.leftPadding = leftPadding; } public float getRightPadding() { return rightPadding; } public void setRightPadding(float rightPadding) { this.rightPadding = rightPadding; } public void setWordSpacing(float wordSpacing) { this.wordSpacing = wordSpacing; } public float getWordSpacing() { return wordSpacing; } public float getLineSpacing() { return lineSpacing; } public void setLineSpacing(float lineSpacing) { this.lineSpacing = lineSpacing; } class Line { ArrayList words = new ArrayList(); float spacing = 15f; public Line() { } public Line(ArrayList words, float spacing) { this.words = words; this.spacing = spacing; } public void setSpacing(float spacing) { this.spacing = spacing; } public float getSpacing() { return spacing; } public void addWord(String s) { words.add(s); } public ArrayList getWords() { return words; } } } 

En solo tres pasos, puede justificar su texto de vista web.

1)

 // Justify tag String justifyTag = "%s"; 

2)

 // Concatenate your string with the tag to Justify it String dataString = String.format(Locale.US, justifyTag, "my html with text justification"); 

3)

 // Load the data in the web view webView.loadDataWithBaseURL("", dataString, "text/html", "UTF-8", ""); 

Esta es la misma clase JustifiedTextView dada por Juan (y editada por mí), pero extendida para trabajar con atributos xml personalizados que puede usar en sus archivos xml de diseño. Incluso el editor de diseño de Eclipse mostrará sus atributos personalizados en la tabla de atributos, lo cual es genial. Puse esto en una respuesta adicional, en caso de que quiera mantener las cosas limpias y no necesite atributos xml.

 public class JustifiedTextView extends WebView{ private String core = "%s"; private String text; private int textColor; private int backgroundColor; private int textSize; public JustifiedTextView(Context context, AttributeSet attrs) { super(context, attrs); init(attrs); } public JustifiedTextView(Context context, AttributeSet attrs, int i) { super(context, attrs, i); init(attrs); } @SuppressLint("NewApi") public JustifiedTextView(Context context, AttributeSet attrs, int i, boolean b) { super(context, attrs, i, b); init(attrs); } private void init(AttributeSet attrs) { TypedArray a=getContext().obtainStyledAttributes( attrs, R.styleable.JustifiedTextView); text = a.getString(R.styleable.JustifiedTextView_text); if(text==null) text=""; textColor = a.getColor(R.styleable.JustifiedTextView_textColor, Color.BLACK); backgroundColor = a.getColor(R.styleable.JustifiedTextView_backgroundColor, Color.TRANSPARENT); textSize = a.getInt(R.styleable.JustifiedTextView_textSize, 12); a.recycle(); this.setWebChromeClient(new WebChromeClient(){}); reloadData(); } public void setText(String s){ if(s==null) this.text=""; else this.text = s; reloadData(); } @SuppressLint("NewApi") private void reloadData(){ if(text!=null) { String data = String.format(core,toRgba(textColor),textSize,text); Log.d("test", data); this.loadDataWithBaseURL(null, data, "text/html","utf-8", null); } // set WebView's background color *after* data was loaded. super.setBackgroundColor(backgroundColor); // Hardware rendering breaks background color to work as expected. // Need to use software renderer in that case. if(android.os.Build.VERSION.SDK_INT >= 11) this.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null); } public void setTextColor(int hex){ textColor = hex; reloadData(); } public void setBackgroundColor(int hex){ backgroundColor = hex; reloadData(); } public void setTextSize(int textSize){ this.textSize = textSize; reloadData(); } private String toRgba(int hex) { String h = Integer.toHexString(hex); int a = Integer.parseInt(h.substring(0, 2),16); int r = Integer.parseInt(h.substring(2, 4),16); int g = Integer.parseInt(h.substring(4, 6),16); int b = Integer.parseInt(h.substring(6, 8),16); return String.format("%d,%d,%d,%d", r, g, b, a); } } 

Agregue esto como justified_text_view_attr.xml en su carpeta res / values ​​/ o combínelo en su attrs.xml existente:

 < ?xml version="1.0" encoding="utf-8"?>         

Siéntase libre de editar si encuentra algún error.

Yo creo esta forma más simple. Y trabajé perfectamente

 package domo.suichbt.util; import android.content.Context; import android.text.Html; import android.util.AttributeSet; import android.widget.TextView; public class JustifiedTextView extends TextView { private final String CORE_TEMPLATE = "%s"; public JustifiedTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText()))); } public JustifiedTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText()))); } public JustifiedTextView(Context context) { super(context); setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText()))); } public JustifiedTextView(Context context, AttributeSet attrs) { super(context, attrs); setText(Html.fromHtml(String.format(CORE_TEMPLATE,getText()))); } } 

Insertar ejemplo xml

    

Eche un vistazo a este enlace. Utiliza un WebView para ser completamente compatible con el texto de un CheckBox en Android. También se puede usar exactamente igual en TextView, ya que cada CheckBox es de hecho una Vista de texto y un Botón. http://www.collegemobile.com/2014/09/justify-text-android-checkbox/