Texto do Android justificar texto

396

Como você TextViewjustifica o texto de a (com o texto nivelado nos lados esquerdo e direito)?

Encontrei uma solução possível aqui , mas ela não funciona (mesmo se você mudar o centro vertical para o center_vertical, etc.).

Bill the Lizard
fonte
@Jimbo resposta está correta definitivamente trabalhar para o meu caso em inputText e textview de língua árabe da direita para a entrada esquerda e exibição, mas para o texto de entrada i teve de acrescentar também a gravidade = "right"
shareef
você pode usar o github.com/pouriaHemmati/JustifiedTextView
Pouria Hemati

Respostas:

240

Não acredito que o Android suporte a justificação completa.

ATUALIZAÇÃO 01-01-2018 : O Android 8.0+ suporta modos de justificação comTextView .

CommonsWare
fonte
5
Após uma análise mais aprofundada, você poderia dar uma chance ao android: gravity = "fill_horizontal". Isso é descrito como "Aumente o tamanho horizontal do objeto, se necessário, para que ele preencha completamente o contêiner", mas não sei como eles "aumentam" o texto.
CommonsWare 18/08/09
8
android: gravity = "fill_horizontal" também não funcionou. Parece que o Android não suporta justificação afinal, oh bem :)
6
Não, você não pode definir a propriedade como gravidade. Ainda assim, você pode definir a justificativa para o seu texto usando a visualização na web em vez da visualização de texto. Você pode consultar seal.io/2010/12/only-way-how-to-align-text-in-block-in.html . (
Roubado
2
@CommonsWare Agora, existe alguma maneira adequada de justificar texto?
John R
11
Cara, estou vivendo com uma webview pesada para conseguir isso e, acredite, minha interface do usuário pede algumas coisas novas a serem adicionadas à API, porque é muito lento para componentes como o bate-papo em uma listview.
nobalG
156

A resposta @CommonsWare está correta. O Android 8.0 ou superior é compatível com "Justificação completa" (ou simplesmente "Justificação", como algumas vezes é ambígua).

O Android também suporta "Alinhamento de texto à esquerda / direita". Veja o artigo da Wikipedia sobre Justificação para a distinção. Muitas pessoas consideram que o conceito de 'justificação' engloba justificação completa e alinhamento de texto à esquerda / direita, que é o que eles procuram quando desejam fazer o alinhamento de texto à esquerda / direita. Esta resposta explica como conseguir o alinhamento do texto esquerdo / direito.

É possível obter alinhamento de texto nivelado à esquerda / direita (em oposição à justificação completa, conforme a pergunta está sendo feita). Para demonstrar, usarei um formulário básico de 2 colunas (rótulos na coluna esquerda e campos de texto na coluna direita) como exemplo. Neste exemplo, o texto nos rótulos na coluna esquerda será alinhado à direita, para que apareçam alinhados com seus campos de texto na coluna direita.

No layout XML, você pode alinhar os elementos TextView (a coluna da esquerda) à direita, adicionando o seguinte atributo a todos os TextViews:

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

No entanto, se o texto for agrupado em várias linhas, o texto ainda ficará alinhado à esquerda alinhado dentro do TextView. A adição do atributo a seguir torna o texto real alinhado à direita (irregular à esquerda) dentro do TextView:

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

Portanto, o atributo gravidade especifica como alinhar o texto dentro do TextView layout_gravity especifica como alinhar / layout o próprio elemento TextView.

plainjimbo
fonte
12
Se eu entendi corretamente, e dados os resultados do teste, tudo isso é alinhar o texto à esquerda ou à direita. Isso não justifica o texto, não é?
Paul Lammertsma
14
Excelente. Só para adicionar, se você quiser justificação central, poderá fazê-lo android:layout_gravity="center_horizontal|center" android:gravity="center".
Luis A. Florit
definitivamente trabalhando para o meu caso em inputtext e textview para o idioma árabe da direita para a esquerda, entrada e exibição
shareef
11
Isso é apenas alinhamento, não justificação. Leia esse link da Wikipedia com atenção. A diferença entre os diferentes tipos de justificação afeta apenas a última linha de um parágrafo. Não há justificativa esquerda / direita / central para parágrafos que possuem apenas uma linha.
Karu
então por que até respondê-lo aqui se não é sobre #justify
user924 15/1018
136

Para justificar o texto no Android, usei o 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");

e 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>

Ainda não consigo enviar imagens para provar isso, mas "funciona para mim".

Konrad Nowicki
fonte
3
Ótima solução aqui. FWIW, você não precisa da maioria do html extra. A etiqueta do corpo com alinhamento de texto é suficiente.
Gnac #
5
Isso funciona bem. Observe que você pode tornar o plano de fundo transparente seguindo view.loadData()com view.setBackgroundColor("#00000000").
Paul Lammertsma 12/09
No entanto, não consegui fazer com que ele carregasse uma fonte / tipo de letra personalizados. Eu tentei isso e essa sugestão, sem sorte.
Paul Lammertsma
2
Como mencionei nesses tópicos, encontrei uma resolução: se você criar um arquivo HTML e o colocar nos ativos, carregá-lo via view.loadUrl()works, enquanto view.loadData()não. Não tenho idéia do porquê do último não.
Paul Lammertsma
11
@PaulLammertsma, setBackgroundColor (0x00000000) seria o formato correto para definir o plano de fundo transparente.
richey
100

ATUALIZADA

Criamos uma classe simples para isso. Atualmente, existem dois métodos para alcançar o que você está procurando. Ambos não precisam de WEBVIEW e SUPORTES ESPANHÁVEIS .

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

SUPORTES : Android 2.0 a 5.X

CONFIGURAÇÃO

// Please visit Github for latest setup instructions.

SCREENSHOT

Comparison.png

Mathew Kurian
fonte
É realmente uma ajuda, mas, usando-o, meus TextViews não mantêm o formato original, eu me refiro a: margens, estilo de texto e acho que o tamanho do texto também, Plese continua trabalhando nele, deve ser uma grande ajuda
Leonardo Sapuy
Bem, eu não posso estabelecer essas classes. um deles não tinha nenhum nome de embalagem, o outro dá algum erro amarelo. Na verdade, eu não posso confiar.
mehmet
Boa biblioteca, mas ainda não sei como adicionar formatação ao texto usando esta biblioteca.
Semanticer
4
Obrigado por esta excelente biblioteca compartilhada, mas ela não suporta texto em persa ou árabe. Quando defino a direção, minha palavra desenha do último ao início, em vez do começo ao último. Quero dizer o seguinte: minha palavra é: "سلام" e seu desenho é o seguinte: "مالس". (se você não entende persa, veja este exemplo: deixe-me "1234" -> "4321")
Naruto Uzumaki
11
Com base no scrollView ... A solução agradável, no entanto, não consegue encontrar nenhuma resposta que o torne possível com o textview. :(
superUser
88

TextViewem Android Oofertas justificação completa (novo alinhamento tipográfica) em si.

Você só precisa fazer isso:

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);
}

padrão é JUSTIFICATION_MODE_NONE.

Jaydipsinh Zala
fonte
3
Vamos esperar ele recebe de volta portado para a biblioteca de suporte, em seguida, O :)
Stefan Haustein
2
pls adicionar biblioteca aqui !!
Kunal Dharaiya
4
como justificar o uso de XML?
Vikash Parajuli
14
Você pode usar o android: justificationMode = "inter_word" no xml.
Christian D
5
API 26 necessária para o Android: justificationMode.
Bink
42

Você pode usar o projeto JustifiedTextView for Android no github. essa é uma exibição personalizada que simula o texto justificado para você. Ele suporta Android 2.0 ou superior e idiomas da direita para a esquerda. insira a descrição da imagem aqui

Saeed Zarinfam
fonte
ele não suporta corda spannable
MSepehr
como podemos adicionar nosso próprio texto?
Karan
Por favor, veja a amostra no github.
Saeed Zarinfam
oi Saeed, tnx por sua ajuda, existe alguma maneira de oferecer suporte a visualizações de texto extensíveis ?!
Hamid Reza
@SaeedZarinfam Eu tentei usar "JustifiedTextView para Android", mas eu tenho de erro no ir.noghteh.JustifiedTextView tag xml seria u plz me ajuda sobre esta questão stackoverflow.com/questions/37911376/...
Jumong
30

Eu escrevo uma base de widget no textview nativo para fazer isso.

github

Frank Cheng
fonte
Eu recomendo este, principalmente porque é baseado no texto original do android oficial sdk, que na minha opinião pessoal é muito mais leve que a técnica do webview que muitas pessoas estão postando sobre esse tópico comum. Se você estiver construindo um aplicativo que precisa ter memória, usando objetos de exibição de lista, por exemplo, considere usar algo parecido com isto. Ï já experimente e funcione conforme o esperado. Se você conhece alguém melhor como este 1, por favor, compartilhe sua experiência comigo.
SuperUser
Bom trabalho btw. O que eu estava procurando.
SuperUser
5
não suporta idiomas RTL como persa
fogo no buraco
11
@Frank Cheng Biblioteca Muito Útil. Recebo muitos espaços no final do parágrafo. Como posso corrigir isso?
ISrinivasan27
11
funcionou para mim, mas a última linha da visualização de texto foi cortada. Eu tive que continuar preenchendo 5 para a visualização de texto.
TharakaNirmana 17/03/16
23

Encontrei uma maneira de resolver esse problema, mas isso pode não ser muito agradável, mas o efeito não é ruim.

Seu princípio é substituir os espaços de cada linha no ImageSpan de largura fixa (a cor é 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);
            }
        }
    });
}

Coloquei o código no GitHub: https://github.com/twiceyuan/TextJustification

Visão geral:

Visão geral

duas vezes
fonte
11
Não funciona na visualização XML, mas ótimo trabalhar com um dispositivo real :)
pgreze
15

Layout XML: declarar WebView em vez de TextView

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

Código Java: defina os dados de texto como 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");

Isso pode resolver seu problema. É totalmente funcionou para mim.


fonte
9

Aqui está como eu fiz isso, acho que da maneira mais elegante que pude. Com esta solução, as únicas coisas que você precisa fazer nos seus layouts são:

  • adicione um adicional xmlns declaração
  • mude seu TextView namespace de texto de origem do android para o seu novo namespace
  • substitua seu TextViews porx.y.z.JustifiedTextView

Aqui está o código. Funciona perfeitamente nos meus telefones (Galaxy Nexus Android 4.0.2, Galaxy Teos Android 2.1). Sinta-se à vontade, é claro, para substituir o nome do meu pacote pelo seu.

/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);
    }
}

Precisamos definir a renderização como software para obter um plano de fundo transparente no Android 3+. Daí o try-catch para versões mais antigas do Android.

Espero que isto ajude!

PS: não é útil adicionar isso a toda a sua atividade no Android 3 ou superior para obter o comportamento esperado:
android:hardwareAccelerated="false"

Benoit Duffez
fonte
Esta é uma solução baseada no webView. Qualquer um que tenha encontrado ainda o textview, considerando que o textview é mais leve que o webview e o scrollview.
SuperUser
9

Muito simples Podemos fazer isso no arquivo xml

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

Eu escrevo minha própria classe para resolver esse problema, aqui está Apenas você tem que chamar a função justificar estática que leva dois argumentos

  1. Objeto de exibição de texto
  2. Largura do conteúdo (largura total da sua exibição de texto)

//Atividade 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
fonte
fundamentos completar este exemplo, pelo menos, para "\ n" ou System.getProperty ( "line.separator") para respeitar :)
ceph3us
5

FILL_HORIZONTALé equivalente a CENTER_HORIZONTAL. Você pode ver esse trecho de código no código fonte do textview:

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

Há um CustomView para esse problema, esse modo de exibição de texto personalizado é compatível com o modo de exibição justificado de texto.

Pilhagem neste: 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;
                }
        }
}

Adicione a classe acima à sua pasta src e use este código de exemplo para adicionar ao seu layout:

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

veja aqui no github

Apenas importe os dois arquivos "TextJustifyUtils.java" e "TextViewEx.java" no seu projeto.

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;
    }
}

e

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);
        }
    }
}

Agora, se você usar texto normal, como:

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

Basta usar

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

Defina uma variável e defina justificar como verdadeiro,

TextViewEx changed = (TextViewEx) findViewById(R.id.changed);
changed.setText(getResources().getString(R.string.lorum_ipsum),true);
Mr_Moradi
fonte
texto em negrito não está funcionando, por favor, ajude se você tiver alguma correção para isso?
praveenb 20/09/19
4

Justificar texto do Android para XML do TextView

Simplesmente android, justifique o texto usando em XML. Você pode simplesmente implementar no widget de visualização de texto.

 <TextView
    android:justificationMode="inter_word"
/>

O padrão é android:justificationMode="none"

Samad Talukder
fonte
2

Eu acho que existem duas opções:

  • Use algo como o Pango, especializado nisso via NDK e renderize o texto em um OpenGL ou outra superfície.

  • Use Paint.measureText () e amigos para obter o comprimento das palavras e distribuí-las manualmente em um Canvas em uma exibição personalizada.

Matthew Willis
fonte
2

No android, para justificar à esquerda o texto e não ter truncamento da cor de fundo, tente isso, funcionou para mim, produzindo resultados consistentes no android, ff, ou seja, & chrome, mas você precisa medir o espaço que resta para o texto ao calcular o preenchimento.

<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;
>

O hack é o padding-right:1000px; que empurra o texto para a extrema esquerda.

Qualquer tentativa à esquerda ou justificar o código em css ou html resulta em um plano de fundo com apenas metade da largura.

Robin Glas
fonte
1

O Android ainda não suporta justificação completa. Podemos usar o Webview e justificar o HTML em vez de usar o textview. Funciona tão bem. Se vocês não tiverem certeza, não hesite em me perguntar :)

kypiseth
fonte
Isso pode ser feito. Mas podemos definir o plano de fundo WebView transparent. Eu tenho uma imagem de fundo.
Mr.India
Eu não acho que isso pode ser sensato em memória.
SuperUser
1

Justificativa para o conteúdo do TextView: Seus funcionários fáceis usam apenas android: justificationMode = "inter_word" na sua tag 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
fonte
-4

Tente usar < RelativeLayout >(certificando-se de fill_parent), depois adicione android:layout_alignParentLeft="true"e

android:layout_alignParentRight="true" para os elementos que você gostaria do lado de fora ESQUERDO & DIREITO.

BLAM, justificado!

esharp
fonte
exemplo excelente aqui: stackoverflow.com/questions/2099249/…
esharp
3
Ainda não é o que ele está procurando. Veja Justificação na Wikipedia: en.wikipedia.org/wiki/Justification_(typesetting)
Kevin Coppock
Não é uma justificativa
Arash Hatami
-5

Você tem que definir

android:layout_height="wrap_content"

e

android:layout_centerInParent="true"
Lukas
fonte
11
Isso centraliza o texto que não está totalmente justificado
Janusz
-12

Isso realmente não justifica seu texto, mas

android:gravity="center_horizontal"

é a melhor escolha que você tem.

Wolfen
fonte
9
Não, isso centraliza o texto. Isso não justifica. Citando a Wikipedia : "No texto justificado, os espaços entre as palavras e, em menor grau, entre glifos ou letras (kerning), são esticados ou, às vezes, compactados para fazer o texto alinhar-se com as margens esquerda e direita".
CommonsWare
o texto não se justifica pelo seu código, mas centraliza o texto na horizontal
Matteo