Android TextView Justify Text

396

Comment obtenir que le texte d'un TextViewsoit justifié (avec affleurement de texte sur les côtés gauche et droit)?

J'ai trouvé une solution possible ici , mais cela ne fonctionne pas (même si vous changez vertical-center en center_vertical, etc.).

Bill le lézard
la source
@Jimbo réponse est correcte pour travailler definetly mon cas sur inputtext et textview pour la langue arabe de droite à gauche entrée et d' affichage , mais pour le texte d'entrée i devait également ajouter gravité = « right »
Shareef
vous pouvez utiliser github.com/pouriaHemmati/JustifiedTextView
Pouria Hemati

Réponses:

240

Je ne pense pas qu'Android supporte une justification complète.

MISE À JOUR 2018-01-01 : Android 8.0+ prend en charge les modes de justification avecTextView .

CommonsWare
la source
5
Après une analyse plus approfondie, vous pouvez donner un coup de feu à android: gravity = "fill_horizontal". Cela est décrit comme "Augmenter la taille horizontale de l'objet si nécessaire pour qu'il remplisse complètement son conteneur", mais je ne sais pas comment ils "agrandissent" le texte.
CommonsWare
8
android: gravity = "fill_horizontal" ne fonctionnait pas non plus. Il semble qu'Android ne supporte pas la justification après tout, oh bien :)
6
Non, vous ne pouvez pas définir la propriété comme la gravité. Mais vous pouvez toujours définir la justification de votre texte en prenant une vue Web au lieu d'une vue texte. Vous pouvez vous référer à seal.io/2010/12/only-way-how-to-align-text-in-block-in.html . (Volé de stackoverflow.com/questions/5976627/… )
jcaruso
2
@CommonsWare Existe-t-il un moyen approprié de justifier le texte?
John R
1
Mec, je vis avec une vision Web lourde pour y parvenir, et croyez-moi, mon interface utilisateur pleure pour de nouvelles choses à ajouter à l'API, car il est sacrément lent pour des composants comme le chat dans une liste.
nobalG
156

La réponse @CommonsWare est correcte. Android 8.0+ prend en charge la «justification complète» (ou simplement la «justification», car elle est parfois appelée de manière ambiguë).

Android prend également en charge "Alignement du texte à gauche / droite". Voir l'article de wikipedia sur la justification de la distinction. Beaucoup de gens considèrent que le concept de `` justification '' englobe la justification complète ainsi que l'alignement du texte gauche / droite, ce qu'ils recherchent finalement lorsqu'ils veulent faire un alignement du texte gauche / droite. Cette réponse explique comment réaliser l'alignement du texte gauche / droite.

Il est possible d'obtenir un alignement du texte à gauche / droite (contrairement à la justification complète, comme la question le demande). Pour démontrer, j'utiliserai un formulaire de base à 2 colonnes (étiquettes dans la colonne de gauche et champs de texte dans la colonne de droite) comme exemple. Dans cet exemple, le texte dans les étiquettes de la colonne de gauche sera aligné à droite afin qu'il apparaisse aligné avec leurs champs de texte dans la colonne de droite.

Dans la disposition XML, vous pouvez obtenir les éléments TextView eux-mêmes (la colonne de gauche) pour qu'ils s'alignent à droite en ajoutant l'attribut suivant à l'intérieur de tous les TextViews:

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

Toutefois, si le texte passe à plusieurs lignes, le texte sera toujours aligné à gauche dans TextView. L'ajout de l'attribut suivant rend le texte réel aligné à droite (gauche irrégulier) à l'intérieur de TextView:

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

Ainsi, l' attribut gravity spécifie comment aligner le texte à l'intérieur de TextView layout_gravity spécifie comment aligner / mettre en page l'élément TextView lui-même.

plainjimbo
la source
12
Si je comprends bien, et étant donné les résultats des tests, tout cela ne fait qu'aligner le texte à gauche ou à droite. Cela ne justifie pas le texte, n'est-ce pas?
Paul Lammertsma
14
Excellent. Juste pour ajouter, si vous voulez une justification centrale, vous pouvez le faire android:layout_gravity="center_horizontal|center" android:gravity="center".
Luis A. Florit
travailler définitivement pour mon cas sur inputtext et textview pour la langue arabe de droite à gauche entrée et affichage
shareef
1
Ce n'est qu'un alignement, pas une justification. Lisez attentivement ce lien Wikipédia. La différence entre les différents types de justification affecte uniquement la dernière ligne d'un paragraphe. Il n'y a pas de justification gauche / droite / centre pour les paragraphes qui n'ont qu'une seule ligne.
Karu
alors pourquoi y répondre même si ce n'est pas le casjustify
user924
136

Pour justifier le texte dans Android, j'ai utilisé 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");

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

Je ne peux pas encore télécharger d'images pour le prouver mais "ça marche pour moi".

Konrad Nowicki
la source
3
Belle solution ici. FWIW vous n'avez pas besoin de la plupart des html supplémentaires. La balise body avec alignement du texte suffit.
gnac
5
Cela fonctionne bien. Notez que vous pouvez rendre l'arrière-plan transparent en suivant view.loadData()avec view.setBackgroundColor("#00000000").
Paul Lammertsma
Cependant, je n'ai pas réussi à le faire charger une police / police de caractères personnalisée. J'ai essayé ceci et cette suggestion, sans aucune chance.
Paul Lammertsma
2
Comme je l'ai mentionné dans ces discussions, j'ai trouvé une résolution: si vous créez un fichier HTML et le placez dans les actifs, le charger via view.loadUrl()works, alors view.loadData()que non. Je n'ai aucune idée pourquoi ce dernier ne fonctionne pas.
Paul Lammertsma
1
@PaulLammertsma, setBackgroundColor (0x00000000) serait plutôt le format correct pour définir l'arrière-plan transparent.
richey
100

MISE À JOUR

Nous avons créé une classe simple pour cela. Il existe actuellement deux méthodes pour réaliser ce que vous recherchez. Les deux ne nécessitent PAS DE WEBVIEW et SUPPORTTS SPANNABLES .

BIBLIOTHÈQUE : https://github.com/bluejamesbond/TextJustify-Android

SUPPORTS : Android 2.0 à 5.X

INSTALLER

// Please visit Github for latest setup instructions.

CAPTURE D'ÉCRAN

Comparison.png

Mathew Kurian
la source
Est-ce vraiment une aide, mais en l'utilisant, mes TextViews ne conservent pas le format d'origine, je réfère: les marges, le style de texte, et je pense que la taille du texte non plus, Plese continue de travailler dedans, devrait être une très grande aide
Leonardo Sapuy
Eh bien, je ne peux pas établir ces classes. l'un d'eux n'avait pas de nom de paquet, l'autre donne une erreur jaune. En fait, je ne peux pas faire confiance.
mehmet
Belle bibliothèque, mais je ne sais toujours pas comment ajouter de formatage au texte en utilisant cette bibliothèque.
Semanticer
4
Merci pour cette excellente bibliothèque partagée, mais elle ne peut pas prendre en charge le texte persan ou arabe. Lorsque je définis la direction, ma parole dessine du dernier au début, au lieu du début au dernier. Je veux dire ceci: ma Parole est: "سلام" et son tirage comme ceci: "مالس". (si vous ne comprenez pas le persan, voyez cet exemple: laissez-moi "1234" -> "4321")
Naruto Uzumaki
1
Basé sur scrollView ... Nice solution cependant ne trouve pas encore de réponse qui le rend possible avec textview. :(
superUser
89

TextViewin Android Ooffre une justification complète (nouvel alignement typographique) lui-même.

Il vous suffit de faire ceci:

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

la valeur par défaut est JUSTIFICATION_MODE_NONE.

Jaydipsinh Zala
la source
3
Espérons qu'il sera renvoyé à la bibliothèque de support puis O :)
Stefan Haustein
2
pls ajouter la bibliothèque ici !!
Kunal Dharaiya
4
comment justifier l'utilisation de XML?
Vikash Parajuli
14
Vous pouvez utiliser android: justificationMode = "inter_word" en xml.
Christian D
5
API 26 requise pour Android: justificationMode.
Bink
42

Vous pouvez utiliser le projet JustifiedTextView pour Android dans github. il s'agit d'une vue personnalisée qui simule pour vous du texte justifié. Il prend en charge Android 2.0+ et les langues de droite à gauche. entrez la description de l'image ici

Saeed Zarinfam
la source
il ne prend pas en charge la chaîne
extensible
comment ajouter notre propre texte?
Karan
Veuillez voir l'exemple sur github.
Saeed Zarinfam
salut Saeed, tnx pour votre aide, existe-t-il un moyen de prendre en charge les vues de texte pouvant être étendues?!
Hamid Reza
@SaeedZarinfam J'ai essayé d'utiliser "JustifiedTextView pour Android" mais j'ai eu une erreur sur la balise xml ir.noghteh.JustifiedTextView serait u plz pour m'aider sur cette question stackoverflow.com/questions/37911376/…
Jumong
30

J'écris une base de widget sur textview native pour le faire.

github

Frank Cheng
la source
Je recommanderais celui-ci, principalement parce qu'il est basé sur la vue de texte originale du SDK officiel Android, qui, à mon avis, est beaucoup plus légère que la technique de la vue Web que beaucoup de gens publient sur ce sujet commun. Si vous construisez une application qui doit être sage en mémoire, en utilisant des objets listview par exemple, vous pourriez envisager d'utiliser quelque chose comme ça. Je l'ai déjà essayé et fonctionne comme prévu. Si vous en connaissez un autre mieux ou comme celui-ci, s'il vous plaît, vous pourriez partager votre expérience avec moi.
superUser
Beau boulot. Ce que je cherchais.
superUser
5
ne prend pas en charge les langues RTL comme le persan
feu dans le trou
1
@Frank Cheng Bibliothèque très utile. J'obtiens beaucoup d'espaces à la fin du paragraphe. Comment puis-je le réparer?
iSrinivasan27
1
a fonctionné pour moi, mais la dernière ligne du texte a été coupée. J'ai dû continuer à remplir 5 pour la visualisation de texte.
TharakaNirmana
23

J'ai trouvé un moyen de résoudre ce problème, mais ce n'est peut-être pas très gracieux, mais l'effet n'est pas mauvais.

Son principe est de remplacer les espaces de chaque ligne par ImageSpan à largeur fixe (la couleur est 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);
            }
        }
    });
}

J'ai mis le code sur GitHub: https://github.com/twiceyuan/TextJustification

Aperçu:

Aperçu

deux foisYuan
la source
1
Ne fonctionne pas dans l'aperçu XML mais fonctionne très bien avec un vrai appareil :)
pgreze
15

Disposition XML: déclarer WebView au lieu de TextView

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

Code Java: définissez les données de texte sur 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");

Cela peut résoudre votre problème. Son entièrement fonctionné pour moi.


la source
9

Voici comment je l'ai fait, je pense de la manière la plus élégante possible. Avec cette solution, les seules choses que vous devez faire dans vos mises en page sont:

  • ajouter une xmlnsdéclaration supplémentaire
  • changer l' TextViewespace de noms de votre texte source d'Android en votre nouvel espace de noms
  • remplacez votre TextViews parx.y.z.JustifiedTextView

Voici le code. Fonctionne parfaitement sur mes téléphones (Galaxy Nexus Android 4.0.2, Galaxy Teos Android 2.1). N'hésitez pas, bien sûr, à remplacer mon nom de package par le vôtre.

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

Nous devons définir le rendu sur le logiciel afin d'obtenir un fond transparent sur Android 3+. D'où le try-catch pour les anciennes versions d'Android.

J'espère que cela t'aides!

PS: veuillez noter qu'il pourrait être utile d'ajouter cela à l'ensemble de votre activité sur Android 3+ afin d'obtenir le comportement attendu:
android:hardwareAccelerated="false"

Benoit Duffez
la source
Il s'agit d'une solution basée sur WebView. Tout le monde a trouvé encore basé sur textview, considérant que textview est plus léger que webview et scrollview.
superUser
9

Très simple, nous pouvons le faire dans le fichier xml

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

J'écris ma propre classe pour résoudre ce problème, ici c'est juste que vous devez appeler la fonction de justification statique qui prend deux arguments

  1. Objet Vue texte
  2. Largeur du contenu (largeur totale de votre affichage de texte)

//Activité principale

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
la source
merci de compléter cet exemple au moins pour que "\ n" ou System.getProperty ("line.separator") respecte :)
ceph3us
5

FILL_HORIZONTALest équivalent à CENTER_HORIZONTAL. Vous pouvez voir cet extrait de code dans le code source de textview:

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

Il existe une vue personnalisée pour ce problème, cette vue de texte personnalisée prend en charge la vue de texte justifié.

Pillez à ceci: 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;
                }
        }
}

Ajoutez la classe ci-dessus à votre dossier src et utilisez cet exemple de code pour ajouter à votre mise en page:

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

voir ici dans le github

Importez simplement les deux fichiers "TextJustifyUtils.java" et "TextViewEx.java" dans votre projet.

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

et

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

Maintenant, si vous utilisez textView normal comme:

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

Utilisez simplement

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

Définissez une variable et définissez la justification pour être vraie,

TextViewEx changed = (TextViewEx) findViewById(R.id.changed);
changed.setText(getResources().getString(R.string.lorum_ipsum),true);
Mr_Moradi
la source
le texte en gras ne fonctionne pas, aidez-nous si vous avez une solution?
praveenb
4

Texte Android Justify pour TextView XML

Justifiez simplement le texte Android en utilisant XML. Vous pouvez simplement implémenter dans le widget textview.

 <TextView
    android:justificationMode="inter_word"
/>

La valeur par défaut est android:justificationMode="none"

Samad Talukder
la source
2

Je pense qu'il y a deux options:

  • Utilisez quelque chose comme Pango qui se spécialise dans cela via le NDK et restituez le texte sur une OpenGL ou une autre surface.

  • Utilisez Paint.measureText () et vos amis pour obtenir la longueur des mots et les disposer manuellement sur un canevas dans une vue personnalisée.

Matthew Willis
la source
2

Sur Android, pour justifier le texte à gauche et ne pas avoir de troncature de la couleur d'arrière-plan, essayez cela, cela a fonctionné pour moi, produisant des résultats cohérents sur Android, FF, c'est-à-dire & Chrome, mais vous devez mesurer l'espace restant entre les deux pour le texte lors du calcul du rembourrage.

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

Le hack est le padding-right:1000px;qui pousse le texte à l'extrême gauche.

Toute tentative de gauche ou de justification de code en CSS ou HTML entraîne un arrière-plan qui n'est que de la moitié de la largeur.

Robin Glas
la source
1

Android ne prend pas encore en charge la justification complète. Nous pouvons utiliser Webview et justifier HTML au lieu d'utiliser textview. Cela fonctionne si bien. Si vous n'êtes pas clair, n'hésitez pas à me demander :)

kypiseth
la source
Cela peut être fait. Mais pouvons-nous définir l'arrière-plan de WebView transparent. J'ai une image de fond.
Mr.India
Je ne pense pas que ce soit sage.
superUser
1

Justification du contenu TextView: ses gars simples utilisent simplement android: justificationMode = "inter_word" dans votre balise 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
la source
-4

Essayez d'utiliser < RelativeLayout >(en veillant à remplir_parent), puis ajoutez android:layout_alignParentLeft="true"et

android:layout_alignParentRight="true" aux éléments que vous souhaitez à l'extérieur GAUCHE et DROITE.

BLAM, justifié!

esharp
la source
excellent exemple ici: stackoverflow.com/questions/2099249/…
esharp
3
Ce n'est toujours pas ce qu'il cherche. Voir Justification sur Wikipedia: en.wikipedia.org/wiki/Justification_(typesetting)
Kevin Coppock
Ce n'est pas une justification
Arash Hatami
-5

Vous devez définir

android:layout_height="wrap_content"

et

android:layout_centerInParent="true"
Lukas
la source
11
Cela centre le texte qui n'est pas pleinement justifié
Janusz
-12

Cela ne justifie pas vraiment votre texte mais

android:gravity="center_horizontal"

est le meilleur choix que vous ayez.

Wolfen
la source
9
Non, cela centre le texte. Cela ne le justifie pas. Citant Wikipedia : "Dans le texte justifié, les espaces entre les mots et, dans une moindre mesure, entre les glyphes ou les lettres (crénage), sont étirés ou parfois compressés afin d'aligner le texte avec les marges gauche et droite."
CommonsWare
le texte n'est pas justifié par votre code mais centre horizontal le texte
Matteo