Android TextView Justify Text

396

¿Cómo se consigue que el texto de TextViewa se justifique (con el texto al ras en los lados izquierdo y derecho)?

Encontré una posible solución aquí , pero no funciona (incluso si cambia vertical-center a center_vertical, etc.).

Bill el lagarto
fuente
La respuesta de @Jimbo es correcta, definitivamente funciona para mi caso en inputtext y textview para el idioma árabe de entrada y visualización de derecha a izquierda, pero para el texto de entrada tuve que agregar también gravity = "right"
shareef
puedes usar github.com/pouriaHemmati/JustifiedTextView
Pouria Hemati el

Respuestas:

240

No creo que Android admita una justificación completa.

ACTUALIZACIÓN 2018-01-01 : Android 8.0+ admite modos de justificación conTextView .

CommonsWare
fuente
55
Tras un análisis más detallado, podría darle una oportunidad a android: gravity = "fill_horizontal". Eso se describe como "Aumentar el tamaño horizontal del objeto si es necesario para que llene completamente su contenedor", pero no sé cómo "crecen" el texto.
CommonsWare
8
android: gravity = "fill_horizontal" tampoco funcionó. Parece que Android no admite justificación, después de todo, bueno :)
66
No, no puedes establecer la propiedad como la gravedad. Pero aún así puede establecer la justificación de su texto tomando vista web en lugar de vista de texto. Puede consultar seal.io/2010/12/only-way-how-to-align-text-in-block-in.html . (Robó de stackoverflow.com/questions/5976627/… )
jcaruso
2
@CommonsWare Ahora, ¿hay alguna forma adecuada de justificar el texto?
John R
1
Hombre, estoy viviendo con una gran vista web para lograr esto, y créanme, mi interfaz de usuario llora por algunas cosas nuevas que aún no se han agregado a la API, porque es muy lento para componentes como el chat en una vista de lista.
nobalG
156

La respuesta @CommonsWare es correcta. Android 8.0+ es compatible con "Justificación completa" (o simplemente "Justificación", como a veces se hace referencia de manera ambigua).

Android también es compatible con "Alineación de texto al ras / izquierda". Vea el artículo de Wikipedia sobre la justificación para la distinción. Muchas personas consideran que el concepto de 'justificación' abarca la justificación completa, así como la alineación de texto izquierda / derecha, que es lo que terminan buscando cuando quieren alinear texto a izquierda / derecha. Esta respuesta explica cómo lograr la alineación de texto izquierda / derecha.

Es posible lograr la alineación de texto al ras / izquierda (a diferencia de la justificación completa, ya que la pregunta es sobre). Para demostrarlo, usaré un formulario básico de 2 columnas (etiquetas en la columna izquierda y campos de texto en la columna derecha) como ejemplo. En este ejemplo, el texto en las etiquetas de la columna izquierda estará alineado a la derecha para que aparezcan alineados con sus campos de texto en la columna derecha.

En el diseño XML, puede hacer que los elementos TextView (la columna izquierda) se alineen a la derecha agregando el siguiente atributo dentro de todas las TextViews:

<TextView
   ...
   android:layout_gravity="center_vertical|end">
   ...
</TextView>

Sin embargo, si el texto se ajusta a varias líneas, el texto seguirá alineado dentro de TextView. Al agregar el siguiente atributo, el texto real se alinea a la derecha (irregular hacia la izquierda) dentro de TextView:

<TextView
   ...
   android:gravity="end">
   ...
</TextView>

Entonces, el atributo de gravedad especifica cómo alinear el texto dentro de TextView layout_gravity especifica cómo alinear / diseñar el elemento TextView en sí.

plainjimbo
fuente
12
Si entiendo correctamente, y dados los resultados de probar esto, todo lo que hace es alinear el texto hacia la izquierda o hacia la derecha. Esto no justifica el texto, ¿verdad?
Paul Lammertsma
14
Excelente. Solo para agregar, si desea una justificación central, puede hacerlo android:layout_gravity="center_horizontal|center" android:gravity="center".
Luis A. Florit
Definitivamente trabajando para mi caso en inputtext y textview para el idioma árabe de entrada y visualización de derecha a izquierda
shareef
1
Esto es solo alineación, no justificación. Lea ese enlace de Wikipedia con cuidado. La diferencia entre los diferentes tipos de justificación solo afecta la última línea de un párrafo. No hay justificación izquierda / derecha / centro para los párrafos que solo tienen una línea.
Karu
entonces por qué incluso respondiendo aquí si no se tratajustify
user924
136

Para justificar texto en Android utilicé WebView

    setContentView(R.layout.main);

    WebView view = new WebView(this);
    view.setVerticalScrollBarEnabled(false);

    ((LinearLayout)findViewById(R.id.inset_web_view)).addView(view);

    view.loadData(getString(R.string.hello), "text/html; charset=utf-8", "utf-8");

y html.

<string name="hello">
<![CDATA[
<html>
 <head></head>
 <body style="text-align:justify;color:gray;background-color:black;">
  Lorem ipsum dolor sit amet, consectetur 
  adipiscing elit. Nunc pellentesque, urna
  nec hendrerit pellentesque, risus massa
 </body>
</html>
]]>
</string>

Todavía no puedo subir imágenes para probarlo, pero "funciona para mí".

Konrad Nowicki
fuente
3
Buena solución aquí. FWIW no necesita la mayoría del html extra. La etiqueta del cuerpo con el texto alineado es suficiente.
gnac
55
Esto funciona bien Tenga en cuenta que puede hacer que el fondo sea transparente siguiendo view.loadData()con view.setBackgroundColor("#00000000").
Paul Lammertsma
Sin embargo, no he logrado que cargue una fuente / tipografía personalizada. He intentado esto y esta sugerencia, sin suerte.
Paul Lammertsma
2
Como mencioné en esos hilos, encontré una resolución: si crea un archivo HTML y lo coloca en los activos, lo carga a través de view.loadUrl()trabajos, mientras view.loadData()que no lo hace. No tengo idea de por qué este último no.
Paul Lammertsma
1
@PaulLammertsma, setBackgroundColor (0x00000000) preferiría ser el formato correcto para configurar el fondo transparente.
Richey 01 de
100

ACTUALIZADO

Hemos creado una clase simple para esto. Actualmente hay dos métodos para lograr lo que está buscando. Ambos no requieren WEBVIEW y SOPORTAN ESPANABLES .

BIBLIOTECA : https://github.com/bluejamesbond/TextJustify-Android

SOPORTES : Android 2.0 a 5.X

PREPARAR

// Please visit Github for latest setup instructions.

CAPTURA DE PANTALLA

Comparación.png

Mathew Kurian
fuente
Es realmente una ayuda, pero usarlo, mi TextViews no mantiene el formato original, lo recomiendo: márgenes, estilo de texto, y creo que el tamaño del texto tampoco, Plese continúa trabajando en ello, debería ser una gran ayuda
Leonardo Sapuy
Bueno, no puedo establecer esas clases. uno de ellos no tenía ningún nombre de paquete, el otro da un error amarillo. En realidad no puedo confiar.
mehmet
Buena lib, pero todavía no sé cómo agregar ningún formato al texto usando esta biblioteca.
Semántico
44
Gracias por esta gran biblioteca compartida, pero no puede soportar texto persa o árabe. Cuando establezco la dirección, mi palabra se dibuja del último al comienzo, en lugar de comenzar al último. Quiero decir esto: mi palabra es: "سلام" y su sorteo es así: "مالس". (si no entiendes el persa mira este ejemplo: déjame "1234" -> "4321")
Naruto Uzumaki
1
Basado en scrollView ... Buena solución, sin embargo, no puedo encontrar ninguna respuesta que lo haga posible con textview. :(
superUser
88

TextViewen Android Oofertas justificación completa (nueva alineación tipográfica) en sí.

Solo necesitas hacer esto:

Kotlin

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    textView.justificationMode = JUSTIFICATION_MODE_INTER_WORD
}

Java

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    textView.setJustificationMode(JUSTIFICATION_MODE_INTER_WORD);
}

por defecto es JUSTIFICATION_MODE_NONE.

Jaydipsinh Zala
fuente
3
Esperemos que vuelva a la biblioteca de soporte y luego O :)
Stefan Haustein
2
¡Por favor agregue la biblioteca aquí!
Kunal Dharaiya
44
¿Cómo justificar el uso de XML?
Vikash Parajuli
14
Puede usar android: justificationMode = "inter_word" en xml.
Christian D
55
Se requiere API 26 para Android: justificationMode.
Bink
42

Puede usar el proyecto JustifiedTextView para Android en github. Esta es una vista personalizada que simula texto justificado para usted. Es compatible con Android 2.0+ y los idiomas de derecha a izquierda. ingrese la descripción de la imagen aquí

Saeed Zarinfam
fuente
no es compatible con cadenas
intercambiables
¿Cómo podemos agregar nuestro propio texto?
Karan
Por favor vea la muestra en github.
Saeed Zarinfam
hola Saeed, tnx por tu ayuda, ¿hay alguna forma de admitir vistas de texto que se puedan intercambiar?
Hamid Reza
@SaeedZarinfam Intenté usar "JustifiedTextView para Android", pero recibí un error en la etiqueta xml ir.noghteh.JustifiedTextView me ayudaría en esta pregunta stackoverflow.com/questions/37911376/…
Jumong
30

Escribo una base de widgets en la vista de texto nativa para hacerlo.

github

Frank Cheng
fuente
Lo recomiendo, principalmente porque se basa en la vista de texto original del SDK oficial de Android, que en mi opinión personal es mucho más ligera que la técnica de la vista web que muchas personas publican con respecto a este tema común. Si crea una aplicación que necesita memoria, usando objetos de vista de lista, por ejemplo, podría considerar usar algo como esto. Ya lo probé y funciona como se esperaba. Si ustedes conocen a otro mejor o como este 1, por favor podrían compartir su experiencia conmigo.
superUser
Buen trabajo por cierto. Lo que estaba buscando
superUser
55
no admite lenguajes RTL como el persa
fuego en el hoyo
1
@Frank Cheng Biblioteca muy útil. Obtengo muchos espacios al final del párrafo. ¿Cómo puedo arreglarlo?
iSrinivasan27
1
funcionó para mí, pero la última línea de la vista de texto se cortó. Tuve que seguir bajando 5 para la vista de texto.
TharakaNirmana
23

Encontré una manera de resolver este problema, pero esto puede no ser muy elegante, pero el efecto no es malo.

Su principio es reemplazar los espacios de cada línea al ImageSpan de ancho fijo (el color es transparente).

public static void justify(final TextView textView) {

    final AtomicBoolean isJustify = new AtomicBoolean(false);

    final String textString = textView.getText().toString();

    final TextPaint textPaint = textView.getPaint();

    final SpannableStringBuilder builder = new SpannableStringBuilder();

    textView.post(new Runnable() {
        @Override
        public void run() {

            if (!isJustify.get()) {

                final int lineCount = textView.getLineCount();
                final int textViewWidth = textView.getWidth();

                for (int i = 0; i < lineCount; i++) {

                    int lineStart = textView.getLayout().getLineStart(i);
                    int lineEnd = textView.getLayout().getLineEnd(i);

                    String lineString = textString.substring(lineStart, lineEnd);

                    if (i == lineCount - 1) {
                        builder.append(new SpannableString(lineString));
                        break;
                    }

                    String trimSpaceText = lineString.trim();
                    String removeSpaceText = lineString.replaceAll(" ", "");

                    float removeSpaceWidth = textPaint.measureText(removeSpaceText);
                    float spaceCount = trimSpaceText.length() - removeSpaceText.length();

                    float eachSpaceWidth = (textViewWidth - removeSpaceWidth) / spaceCount;

                    SpannableString spannableString = new SpannableString(lineString);
                    for (int j = 0; j < trimSpaceText.length(); j++) {
                        char c = trimSpaceText.charAt(j);
                        if (c == ' ') {
                            Drawable drawable = new ColorDrawable(0x00ffffff);
                            drawable.setBounds(0, 0, (int) eachSpaceWidth, 0);
                            ImageSpan span = new ImageSpan(drawable);
                            spannableString.setSpan(span, j, j + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                        }
                    }

                    builder.append(spannableString);
                }

                textView.setText(builder);
                isJustify.set(true);
            }
        }
    });
}

Puse el código en GitHub: https://github.com/twiceyuan/TextJustification

Visión general:

Visión general

dos veces yuanes
fuente
1
No funciona en la vista previa de XML pero funciona muy bien con un dispositivo real :)
pgreze
15

Diseño XML: declare WebView en lugar de TextView

<WebView
 android:id="@+id/textContent"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content" />

Código Java: establezca datos de texto en WebView

WebView view = (WebView) findViewById(R.id.textContent);
String text;
text = "<html><body><p align=\"justify\">";
text+= "This is the text will be justified when displayed!!!";
text+= "</p></body></html>";
view.loadData(text, "text/html", "utf-8");

Esto puede resolver su problema. Funcionó completamente para mí.


fuente
9

Así es como lo hice, creo que de la manera más elegante que pude. Con esta solución, las únicas cosas que debe hacer en sus diseños son:

  • agregar una xmlnsdeclaración adicional
  • cambiar el TextViewespacio de nombres de texto de su s de android a su nuevo espacio de nombres
  • reemplaza tu TextViews conx.y.z.JustifiedTextView

Aquí está el código. Funciona perfectamente bien en mis teléfonos (Galaxy Nexus Android 4.0.2, Galaxy Teos Android 2.1). Siéntase libre, por supuesto, de reemplazar el nombre de mi paquete con el suyo.

/assets/justified_textview.css :

body {
    font-size: 1.0em;
    color: rgb(180,180,180);
    text-align: justify;
}

@media screen and (-webkit-device-pixel-ratio: 1.5) {
    /* CSS for high-density screens */
    body {
        font-size: 1.05em;
    }
}

@media screen and (-webkit-device-pixel-ratio: 2.0) {
    /* CSS for extra high-density screens */
    body {
        font-size: 1.1em;
    }
}

/res/values/attrs.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="JustifiedTextView">
        <attr name="text" format="reference" />
    </declare-styleable>
</resources>

/res/layout/test.xml :

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myapp="http://schemas.android.com/apk/res/net.bicou.myapp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <net.bicou.myapp.widget.JustifiedTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            myapp:text="@string/surv1_1" />

    </LinearLayout>
</ScrollView>

/src/net/bicou/myapp/widget/JustifiedTextView.java :

package net.bicou.myapp.widget;

import net.bicou.myapp.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.webkit.WebView;

public class JustifiedTextView extends WebView {
    public JustifiedTextView(final Context context) {
        this(context, null, 0);
    }

    public JustifiedTextView(final Context context, final AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public JustifiedTextView(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);

        if (attrs != null) {
            final TypedValue tv = new TypedValue();
            final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.JustifiedTextView, defStyle, 0);
            if (ta != null) {
                ta.getValue(R.styleable.JustifiedTextView_text, tv);

                if (tv.resourceId > 0) {
                    final String text = context.getString(tv.resourceId).replace("\n", "<br />");
                    loadDataWithBaseURL("file:///android_asset/",
                            "<html><head>" +
                                    "<link rel=\"stylesheet\" type=\"text/css\" href=\"justified_textview.css\" />" +
                                    "</head><body>" + text + "</body></html>",

                                    "text/html", "UTF8", null);
                    setTransparentBackground();
                }
            }
        }
    }

    public void setTransparentBackground() {
        try {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        } catch (final NoSuchMethodError e) {
        }

        setBackgroundColor(Color.TRANSPARENT);
        setBackgroundDrawable(null);
        setBackgroundResource(0);
    }
}

Necesitamos configurar el renderizado en software para obtener un fondo transparente en Android 3+. De ahí el try-catch para versiones anteriores de Android.

¡Espero que esto ayude!

PD: no sea útil agregar esto a toda su actividad en Android 3+ para obtener el comportamiento esperado:
android:hardwareAccelerated="false"

Benoit Duffez
fuente
Esta es una solución basada en webView. Cualquiera ha encontrado aún la vista de texto basada, considerando que la vista de texto es más ligera que la vista web y la vista de desplazamiento.
superUser
9

Muy simple Podemos hacer eso en el archivo xml

<TextView 
android:justificationMode="inter_word"
/>
Machhindra Neupane
fuente
6

Escribo mi propia clase para resolver este problema, aquí es solo tienes que llamar a la función de justificación estática que toma dos argumentos

  1. Objeto de vista de texto
  2. Ancho del contenido (ancho total de su vista de texto)

//Actividad principal

package com.fawad.textjustification;
import android.app.Activity;
import android.database.Cursor;
import android.graphics.Point;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Gravity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {
    static Point size;
    static float density;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Display display = getWindowManager().getDefaultDisplay();
        size=new Point();
        DisplayMetrics dm=new DisplayMetrics();
        display.getMetrics(dm);
        density=dm.density;
        display.getSize(size);


        TextView tv=(TextView)findViewById(R.id.textView1);
        Typeface typeface=Typeface.createFromAsset(this.getAssets(), "Roboto-Medium.ttf");
        tv.setTypeface(typeface);
        tv.setLineSpacing(0f, 1.2f);
        tv.setTextSize(10*MainActivity.density);

        //some random long text
         String myText=getResources().getString(R.string.my_text);

         tv.setText(myText);
        TextJustification.justify(tv,size.x);


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

// TextJustificationClass

package com.fawad.textjustification;

import java.util.ArrayList;

import android.graphics.Paint;
import android.text.TextUtils;
import android.widget.TextView;

public class TextJustification {

    public static void justify(TextView textView,float contentWidth) {
        String text=textView.getText().toString();
        Paint paint=textView.getPaint();

        ArrayList<String> lineList=lineBreak(text,paint,contentWidth);

        textView.setText(TextUtils.join(" ", lineList).replaceFirst("\\s", ""));
    }


    private static ArrayList<String> lineBreak(String text,Paint paint,float contentWidth){
        String [] wordArray=text.split("\\s"); 
        ArrayList<String> lineList = new ArrayList<String>();
        String myText="";

        for(String word:wordArray){
            if(paint.measureText(myText+" "+word)<=contentWidth)
                myText=myText+" "+word;
            else{
                int totalSpacesToInsert=(int)((contentWidth-paint.measureText(myText))/paint.measureText(" "));
                lineList.add(justifyLine(myText,totalSpacesToInsert));
                myText=word;
            }
        }
        lineList.add(myText);
        return lineList;
    }

    private static String justifyLine(String text,int totalSpacesToInsert){
        String[] wordArray=text.split("\\s");
        String toAppend=" ";

        while((totalSpacesToInsert)>=(wordArray.length-1)){
            toAppend=toAppend+" ";
            totalSpacesToInsert=totalSpacesToInsert-(wordArray.length-1);
        }
        int i=0;
        String justifiedText="";
        for(String word:wordArray){
            if(i<totalSpacesToInsert)
                justifiedText=justifiedText+word+" "+toAppend;

            else                
                justifiedText=justifiedText+word+toAppend;

            i++;
        }

        return justifiedText;
    }

}

// XML

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context=".MainActivity" 
    >



    <ScrollView
        android:id="@+id/scrollView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"

             >
            <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
        </LinearLayout>
    </ScrollView>

</RelativeLayout>
Fawad Badar
fuente
Por favor complete este ejemplo al menos para "\ n" o System.getProperty ("line.separator") para respetar :)
ceph3us
5

FILL_HORIZONTALes equivalente a CENTER_HORIZONTAL. Puede ver este fragmento de código en el código fuente de textview:

case Gravity.CENTER_HORIZONTAL:
case Gravity.FILL_HORIZONTAL:
    return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
            getCompoundPaddingLeft() - getCompoundPaddingRight())) /
            getHorizontalFadingEdgeLength();
jiashie
fuente
4

Hay una vista personalizada para este problema, esta vista de texto personalizada es compatible con la vista de texto justificado.

Saquea esto: 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<Line> linesCollection = new ArrayList<Line>();
        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<String> words = new ArrayList<String>();
                float spacing = 15f;

                public Line() {
                }

                public Line(ArrayList<String> 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<String> getWords() {
                        return words;
                }
        }
}

Agregue la clase anterior a su carpeta src y use este código de muestra para agregar a su diseño:

JustifiedTextView jtv= new JustifiedTextView(getApplicationContext(), "Lorem ipsum dolor sit amet... ");
LinearLayout place = (LinearLayout) findViewById(R.id.book_profile_content);
place.addView(jtv);
Merter
fuente
4

ver aquí en el github

Simplemente importe los dos archivos "TextJustifyUtils.java" y "TextViewEx.java" en su proyecto.

public class TextJustifyUtils {
    // Please use run(...) instead
    public static void justify(TextView textView) {
        Paint paint = new Paint();

        String[] blocks;
        float spaceOffset = 0;
        float textWrapWidth = 0;

        int spacesToSpread;
        float wrappedEdgeSpace;
        String block;
        String[] lineAsWords;
        String wrappedLine;
        String smb = "";
        Object[] wrappedObj;

        // Pull widget properties
        paint.setColor(textView.getCurrentTextColor());
        paint.setTypeface(textView.getTypeface());
        paint.setTextSize(textView.getTextSize());

        textWrapWidth = textView.getWidth();
        spaceOffset = paint.measureText(" ");
        blocks = textView.getText().toString().split("((?<=\n)|(?=\n))");

        if (textWrapWidth < 20) {
            return;
        }

        for (int i = 0; i < blocks.length; i++) {
            block = blocks[i];

            if (block.length() == 0) {
                continue;
            } else if (block.equals("\n")) {
                smb += block;
                continue;
            }

            block = block.trim();

            if (block.length() == 0)
                continue;

            wrappedObj = TextJustifyUtils.createWrappedLine(block, paint,
                    spaceOffset, textWrapWidth);
            wrappedLine = ((String) wrappedObj[0]);
            wrappedEdgeSpace = (Float) wrappedObj[1];
            lineAsWords = wrappedLine.split(" ");
            spacesToSpread = (int) (wrappedEdgeSpace != Float.MIN_VALUE ? wrappedEdgeSpace
                    / spaceOffset
                    : 0);

            for (String word : lineAsWords) {
                smb += word + " ";

                if (--spacesToSpread > 0) {
                    smb += " ";
                }
            }

            smb = smb.trim();

            if (blocks[i].length() > 0) {
                blocks[i] = blocks[i].substring(wrappedLine.length());

                if (blocks[i].length() > 0) {
                    smb += "\n";
                }

                i--;
            }
        }

        textView.setGravity(Gravity.LEFT);
        textView.setText(smb);
    }

    protected static Object[] createWrappedLine(String block, Paint paint,
            float spaceOffset, float maxWidth) {
        float cacheWidth = maxWidth;
        float origMaxWidth = maxWidth;

        String line = "";

        for (String word : block.split("\\s")) {
            cacheWidth = paint.measureText(word);
            maxWidth -= cacheWidth;

            if (maxWidth <= 0) {
                return new Object[] { line, maxWidth + cacheWidth + spaceOffset };
            }

            line += word + " ";
            maxWidth -= spaceOffset;

        }

        if (paint.measureText(block) <= origMaxWidth) {
            return new Object[] { block, Float.MIN_VALUE };
        }

        return new Object[] { line, maxWidth };
    }

    final static String SYSTEM_NEWLINE = "\n";
    final static float COMPLEXITY = 5.12f; // Reducing this will increase
                                            // efficiency but will decrease
                                            // effectiveness
    final static Paint p = new Paint();

    public static void run(final TextView tv, float origWidth) {
        String s = tv.getText().toString();
        p.setTypeface(tv.getTypeface());
        String[] splits = s.split(SYSTEM_NEWLINE);
        float width = origWidth - 5;
        for (int x = 0; x < splits.length; x++)
            if (p.measureText(splits[x]) > width) {
                splits[x] = wrap(splits[x], width, p);
                String[] microSplits = splits[x].split(SYSTEM_NEWLINE);
                for (int y = 0; y < microSplits.length - 1; y++)
                    microSplits[y] = justify(removeLast(microSplits[y], " "),
                            width, p);
                StringBuilder smb_internal = new StringBuilder();
                for (int z = 0; z < microSplits.length; z++)
                    smb_internal.append(microSplits[z]
                            + ((z + 1 < microSplits.length) ? SYSTEM_NEWLINE
                                    : ""));
                splits[x] = smb_internal.toString();
            }
        final StringBuilder smb = new StringBuilder();
        for (String cleaned : splits)
            smb.append(cleaned + SYSTEM_NEWLINE);
        tv.setGravity(Gravity.LEFT);
        tv.setText(smb);
    }

    private static String wrap(String s, float width, Paint p) {
        String[] str = s.split("\\s"); // regex
        StringBuilder smb = new StringBuilder(); // save memory
        smb.append(SYSTEM_NEWLINE);
        for (int x = 0; x < str.length; x++) {
            float length = p.measureText(str[x]);
            String[] pieces = smb.toString().split(SYSTEM_NEWLINE);
            try {
                if (p.measureText(pieces[pieces.length - 1]) + length > width)
                    smb.append(SYSTEM_NEWLINE);
            } catch (Exception e) {
            }
            smb.append(str[x] + " ");
        }
        return smb.toString().replaceFirst(SYSTEM_NEWLINE, "");
    }

    private static String removeLast(String s, String g) {
        if (s.contains(g)) {
            int index = s.lastIndexOf(g);
            int indexEnd = index + g.length();
            if (index == 0)
                return s.substring(1);
            else if (index == s.length() - 1)
                return s.substring(0, index);
            else
                return s.substring(0, index) + s.substring(indexEnd);
        }
        return s;
    }

    private static String justifyOperation(String s, float width, Paint p) {
        float holder = (float) (COMPLEXITY * Math.random());
        while (s.contains(Float.toString(holder)))
            holder = (float) (COMPLEXITY * Math.random());
        String holder_string = Float.toString(holder);
        float lessThan = width;
        int timeOut = 100;
        int current = 0;
        while (p.measureText(s) < lessThan && current < timeOut) {
            s = s.replaceFirst(" ([^" + holder_string + "])", " "
                    + holder_string + "$1");
            lessThan = p.measureText(holder_string) + lessThan
                    - p.measureText(" ");
            current++;
        }
        String cleaned = s.replaceAll(holder_string, " ");
        return cleaned;
    }

    private static String justify(String s, float width, Paint p) {
        while (p.measureText(s) < width) {
            s = justifyOperation(s, width, p);
        }
        return s;
    }
}

y

public class TextViewEx extends TextView {
    private Paint paint = new Paint();

    private String[] blocks;
    private float spaceOffset = 0;
    private float horizontalOffset = 0;
    private float verticalOffset = 0;
    private float horizontalFontOffset = 0;
    private float dirtyRegionWidth = 0;
    private boolean wrapEnabled = false;
    int left, top, right, bottom = 0;
    private Align _align = Align.LEFT;
    private float strecthOffset;
    private float wrappedEdgeSpace;
    private String block;
    private String wrappedLine;
    private String[] lineAsWords;
    private Object[] wrappedObj;

    private Bitmap cache = null;
    private boolean cacheEnabled = false;

    public TextViewEx(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // set a minimum of left and right padding so that the texts are not too
        // close to the side screen
        // this.setPadding(10, 0, 10, 0);
    }

    public TextViewEx(Context context, AttributeSet attrs) {
        super(context, attrs);
        // this.setPadding(10, 0, 10, 0);
    }

    public TextViewEx(Context context) {
        super(context);
        // this.setPadding(10, 0, 10, 0);
    }

    @Override
    public void setPadding(int left, int top, int right, int bottom) {
        // TODO Auto-generated method stub
        super.setPadding(left + 10, top, right + 10, bottom);
    }

    @Override
    public void setDrawingCacheEnabled(boolean cacheEnabled) {
        this.cacheEnabled = cacheEnabled;
    }

    public void setText(String st, boolean wrap) {
        wrapEnabled = wrap;
        super.setText(st);
    }

    public void setTextAlign(Align align) {
        _align = align;
    }

    @SuppressLint("NewApi")
    @Override
    protected void onDraw(Canvas canvas) {
        // If wrap is disabled then,
        // request original onDraw
        if (!wrapEnabled) {
            super.onDraw(canvas);
            return;
        }

        // Active canas needs to be set
        // based on cacheEnabled
        Canvas activeCanvas = null;

        // Set the active canvas based on
        // whether cache is enabled
        if (cacheEnabled) {

            if (cache != null) {
                // Draw to the OS provided canvas
                // if the cache is not empty
                canvas.drawBitmap(cache, 0, 0, paint);
                return;
            } else {
                // Create a bitmap and set the activeCanvas
                // to the one derived from the bitmap
                cache = Bitmap.createBitmap(getWidth(), getHeight(),
                        Config.ARGB_4444);
                activeCanvas = new Canvas(cache);
            }
        } else {
            // Active canvas is the OS
            // provided canvas
            activeCanvas = canvas;
        }

        // Pull widget properties
        paint.setColor(getCurrentTextColor());
        paint.setTypeface(getTypeface());
        paint.setTextSize(getTextSize());
        paint.setTextAlign(_align);
        paint.setFlags(Paint.ANTI_ALIAS_FLAG);

        // minus out the paddings pixel
        dirtyRegionWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int maxLines = Integer.MAX_VALUE;
        int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (currentapiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
            maxLines = getMaxLines();
        }
        int lines = 1;
        blocks = getText().toString().split("((?<=\n)|(?=\n))");
        verticalOffset = horizontalFontOffset = getLineHeight() - 0.5f; // Temp
                                                                        // fix
        spaceOffset = paint.measureText(" ");

        for (int i = 0; i < blocks.length && lines <= maxLines; i++) {
            block = blocks[i];
            horizontalOffset = 0;

            if (block.length() == 0) {
                continue;
            } else if (block.equals("\n")) {
                verticalOffset += horizontalFontOffset;
                continue;
            }

            block = block.trim();

            if (block.length() == 0) {
                continue;
            }

            wrappedObj = TextJustifyUtils.createWrappedLine(block, paint,
                    spaceOffset, dirtyRegionWidth);

            wrappedLine = ((String) wrappedObj[0]);
            wrappedEdgeSpace = (Float) wrappedObj[1];
            lineAsWords = wrappedLine.split(" ");
            strecthOffset = wrappedEdgeSpace != Float.MIN_VALUE ? wrappedEdgeSpace
                    / (lineAsWords.length - 1)
                    : 0;

            for (int j = 0; j < lineAsWords.length; j++) {
                String word = lineAsWords[j];
                if (lines == maxLines && j == lineAsWords.length - 1) {
                    activeCanvas.drawText("...", horizontalOffset,
                            verticalOffset, paint);

                } else if (j == 0) {
                    // if it is the first word of the line, text will be drawn
                    // starting from right edge of textview
                    if (_align == Align.RIGHT) {
                        activeCanvas.drawText(word, getWidth()
                                - (getPaddingRight()), verticalOffset, paint);
                        // add in the paddings to the horizontalOffset
                        horizontalOffset += getWidth() - (getPaddingRight());
                    } else {
                        activeCanvas.drawText(word, getPaddingLeft(),
                                verticalOffset, paint);
                        horizontalOffset += getPaddingLeft();
                    }

                } else {
                    activeCanvas.drawText(word, horizontalOffset,
                            verticalOffset, paint);
                }
                if (_align == Align.RIGHT)
                    horizontalOffset -= paint.measureText(word) + spaceOffset
                            + strecthOffset;
                else
                    horizontalOffset += paint.measureText(word) + spaceOffset
                            + strecthOffset;
            }

            lines++;

            if (blocks[i].length() > 0) {
                blocks[i] = blocks[i].substring(wrappedLine.length());
                verticalOffset += blocks[i].length() > 0 ? horizontalFontOffset
                        : 0;
                i--;
            }
        }

        if (cacheEnabled) {
            // Draw the cache onto the OS provided
            // canvas.
            canvas.drawBitmap(cache, 0, 0, paint);
        }
    }
}

Ahora, si usa textView normal como:

<TextView
                android:id="@+id/original"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/lorum_ipsum" />

Simplemente use

<yourpackagename.TextViewEx
                android:id="@+id/changed"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/lorum_ipsum" />

Definir una variable y establecer justificar como verdadero

TextViewEx changed = (TextViewEx) findViewById(R.id.changed);
changed.setText(getResources().getString(R.string.lorum_ipsum),true);
Mr_Moradi
fuente
el texto en negrita no funciona, por favor, ayuda si tienes alguna solución para ello.
praveenb
4

Texto de Android Justify para TextView XML

Simplemente justifique el texto de Android con XML. Simplemente puede implementar en el widget de vista de texto.

 <TextView
    android:justificationMode="inter_word"
/>

El valor predeterminado es android:justificationMode="none"

Samad Talukder
fuente
2

Creo que hay dos opciones:

  • Use algo como Pango que se especialice en esto a través del NDK y renderice texto en un OpenGL u otra superficie.

  • Use Paint.measureText () y sus amigos para obtener la longitud de las palabras y colocarlas manualmente en un lienzo en una vista personalizada.

Matthew Willis
fuente
2

En Android, para justificar el texto a la izquierda y no tener truncamiento del color de fondo, intente esto, funcionó para mí, produciendo resultados consistentes en Android, FF, ie y Chrome, pero debe medir el espacio que queda entre el texto. al calcular el relleno.

<td style="font-family:Calibri,Arial;
    font-size:15px;
    font-weight:800;
    background-color:#f5d5fd;
    color:black;
    border-style:solid;
    border-width:1px;
    border-color:#bd07eb;
    padding-left:10px;
    padding-right:1000px;
    padding-top:3px;
    padding-bottom:3px;
>

El truco es el padding-right:1000px;que empuja el texto al extremo izquierdo.

Cualquier intento de ir a la izquierda o justificar el código en css o html da como resultado un fondo de solo medio ancho.

Robin Glas
fuente
1

Android aún no admite la justificación completa. Podemos usar Webview y justificar HTML en lugar de usar textview. Funciona muy bien Si ustedes no están claros, no duden en preguntarme :)

kypiseth
fuente
Eso se puede hacer. Pero ¿podemos establecer el fondo de WebView transparent. Tengo una imagen de fondo.
Mr.India
No creo que esto pueda ser sabio de memoria.
superUser
1

Justificación del contenido de TextView: es fácil usar solo android: justificationMode = "inter_word" dentro de su etiqueta TextView.

 <TextView
    android:id="@+id/textView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="92dp"
    android:text="@string/contents"
    android:layout_margin="20dp"
    android:justificationMode="inter_word"
     />
Ashraf Gardizy
fuente
-4

Intente usar < RelativeLayout >(asegurándose de llenar_parente), luego simplemente agregue android:layout_alignParentLeft="true"y

android:layout_alignParentRight="true" a los elementos que desea en el exterior IZQUIERDO Y DERECHO.

BLAM, justificado!

esharp
fuente
gran ejemplo aquí: stackoverflow.com/questions/2099249/…
esharp
3
Todavía no es lo que está buscando. Ver Justificación en Wikipedia: en.wikipedia.org/wiki/Justification_(typesetting)
Kevin Coppock
No es una justificación
Arash Hatami
-5

Tienes que configurar

android:layout_height="wrap_content"

y

android:layout_centerInParent="true"
Lukas
fuente
11
Esto centra el texto que no es justificación completa
Janusz
-12

Esto realmente no justifica su texto pero

android:gravity="center_horizontal"

es la mejor opción que tienes

Wolfen
fuente
99
No, eso centra el texto. No lo justifica. Citando Wikipedia : "En el texto justificado, los espacios entre palabras y, en menor medida, entre glifos o letras (interletraje), se estiran o a veces se comprimen para que el texto se alinee con los márgenes izquierdo y derecho".
CommonsWare
el texto no está justificado por su código, sino que es el centro del texto horizontal
Matteo