Android TextView Wyjustuj tekst

395

Jak uzyskać TextViewuzasadnienie tekstu a (z wyrównaniem tekstu po lewej i prawej stronie)?

Znalazłem możliwe rozwiązanie tutaj , ale to nie działa (nawet jeśli zmienisz pionowe centrum do center_vertical, etc).

Bill jaszczurka
źródło
@Jimbo odpowiedź jest poprawna zdecydowanie działa na moim przypadku na inputText i TextView w języku arabskim od strony prawej do lewej, ale wejście i wyświetlania tekstu wejściowego musiałem dodać także grawitację = „right”
SHAREEF
możesz użyć github.com/pouriaHemmati/JustifiedTextView
Pouria Hemati,

Odpowiedzi:

239

Nie wierzę, że Android obsługuje pełne uzasadnienie.

AKTUALIZACJA 01.01.2018 : Android 8.0+ obsługuje tryby justowania zTextView .

CommonsWare
źródło
5
Po dalszej analizie możesz dać androidowi: gravity = "fill_horizontal" strzał. Jest to opisane jako „Zwiększ rozmiar obiektu w poziomie, jeśli to konieczne, aby całkowicie wypełnił swój pojemnik”, ale nie wiem, jak „powiększają” tekst.
CommonsWare
8
android: gravity = "fill_horizontal" też nie działał. Wygląda na to, że Android wcale nie obsługuje uzasadnienia, no cóż :)
6
Nie, nie można ustawić właściwości jak grawitacja. Ale nadal możesz ustawić uzasadnienie tekstu, biorąc widok internetowy zamiast widoku tekstowego. Możesz odwołać się do seal.io/2010/12/only-way-how-to-align-text-in-block-in.html . (Ukradł z stackoverflow.com/questions/5976627/… )
jcaruso
2
@CommonsWare Teraz jakiś właściwy sposób na uzasadnienie tekstu?
John R
1
Człowieku, żyję z ciężkim przeglądaniem stron internetowych, aby to osiągnąć, i uwierzcie mi, mój interfejs użytkownika płacze, aby niektóre nowe rzeczy jeszcze nie zostały dodane do interfejsu API, ponieważ jest to cholernie powolne dla komponentów takich jak czat w widoku listy.
nobalG
156

Odpowiedź @CommonsWare jest poprawna. Android 8.0+ obsługuje „pełne uzasadnienie” (lub po prostu „usprawiedliwienie”, jak to niekiedy określa się niejednoznacznie).

System Android obsługuje także „Wyrównanie tekstu do lewej / prawej strony”. Zobacz artykuł w Wikipedii na temat uzasadnienia tego rozróżnienia. Wiele osób uważa, że ​​pojęcie „justowania” obejmuje pełne justowanie, a także wyrównanie tekstu do lewej / prawej strony, czego szukają, kiedy chcą wyrównać tekst do lewej / prawej strony. Ta odpowiedź wyjaśnia, jak osiągnąć wyrównanie tekstu do lewej / prawej.

Możliwe jest wyrównanie tekstu do lewej / prawej strony (w przeciwieństwie do pełnego justowania, o jakie pyta pytanie). Aby to zademonstrować, użyję podstawowego 2-kolumnowego formularza (etykiety w lewej kolumnie i pola tekstowe w prawej kolumnie) jako przykład. W tym przykładzie tekst na etykietach w lewej kolumnie zostanie wyrównany do prawej, dzięki czemu będą wyglądać na wyrównane z polami tekstowymi w prawej kolumnie.

W układzie XML można ustawić same elementy TextView (lewa kolumna), aby wyrównać do prawej, dodając następujący atrybut do wszystkich TextViews:

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

Jeśli jednak tekst zostanie zawinięty w wiele wierszy, tekst nadal będzie wyrównany do lewej w wyrównaniu w TextView. Dodanie następującego atrybutu powoduje wyrównanie tekstu w prawo z wyrównaniem do prawej (nierówny do lewej) w TextView:

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

Zatem atrybut grawitacji określa sposób wyrównywania tekstu wewnątrz TextView układ_grawitacyjny określa sposób wyrównywania / układu samego elementu TextView .

plainjimbo
źródło
12
Jeśli dobrze rozumiem i biorąc pod uwagę wyniki tego testu, wszystko to wyrównuje tekst w lewo lub w prawo. To nie usprawiedliwia tekstu, prawda?
Paul Lammertsma
14
Świetny. Wystarczy dodać, jeśli chcesz wyśrodkować uzasadnienie, możesz to zrobić android:layout_gravity="center_horizontal|center" android:gravity="center".
Luis A. Florit,
zdecydowanie działa na moim przypadku na inputText i TextView dla języka arabskiego, od prawej do lewej wejście i wyświetlacza
Shareef
1
To tylko wyrównanie, a nie uzasadnienie. Przeczytaj uważnie ten link do Wikipedii. Różnica między różnymi rodzajami uzasadnienia wpływa tylko na ostatni wiersz akapitu. Nie ma uzasadnienia dla lewego / prawego / środkowego akapitu, który ma tylko jedną linię.
Karu
dlaczego więc w ogóle odpowiedzieć na to pytanie, jeśli nie chodzi o użytkownikajustify
user924,
136

Aby uzasadnić tekst w Androidzie, użyłem 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");

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

Nie mogę jeszcze przesłać zdjęć, aby to udowodnić, ale „to działa dla mnie”.

Konrad Nowicki
źródło
3
Ładne rozwiązanie tutaj. FWIW nie potrzebujesz większości dodatkowego html. Wystarczy znacznik body z wyrównaniem tekstu.
gnac
5
To działa dobrze. Pamiętaj, że możesz ustawić przezroczystość tła, postępując zgodnie view.loadData()z view.setBackgroundColor("#00000000").
Paul Lammertsma,
Nie udało mi się jednak załadować niestandardowej czcionki / kroju pisma. Próbowałem tego i tej sugestii, bez powodzenia.
Paul Lammertsma,
2
Jak wspomniałem w tych wątkach, znalazłem rozwiązanie: jeśli utworzysz plik HTML i umieścisz go w zasobach, wczytujesz go za pomocą view.loadUrl()utworów, podczas view.loadData()gdy nie. Nie mam pojęcia, dlaczego to drugie nie.
Paul Lammertsma
1
@PaulLammertsma, setBackgroundColor (0x00000000) wolałby być prawidłowym formatem do ustawiania przezroczystego tła.
richey
100

AKTUALIZACJA

Stworzyliśmy do tego prostą klasę. Obecnie istnieją dwie metody osiągnięcia tego, czego szukasz. Oba nie wymagają WEBVIEW i WSPIERA SPANNABLES .

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

WSPIERA : Android 2.0 do 5.X

USTAWIAĆ

// Please visit Github for latest setup instructions.

ZRZUT EKRANU

Porównanie.png

Mathew Kurian
źródło
To naprawdę pomoc, ale używając go, moje TextViews nie zachowują oryginalnego formatu, odnawiam: marginesy, styl tekstu i myślę, że rozmiar tekstu, Plese nadal w nim pracuje, powinien być naprawdę świetną pomocą
Leonardo Sapuy
Cóż, nie mogę ustanowić tych klas. jeden z nich nie miał żadnej nazwy pakietu, drugi daje żółty błąd. Właściwie nie mogę ufać.
mehmet
Niezła biblioteka, ale wciąż nie wiem, jak dodać formatowanie do tekstu za pomocą tej biblioteki.
Semanticer
4
Dzięki za świetną wspólną bibliotekę, ale nie obsługuje tekstu perskiego ani arabskiego. Kiedy ustalam kierunek, moje słowo rysuje od początku do początku, zamiast od początku do końca. Mam na myśli to: moje Słowo brzmi: „سلام” i jego losowanie jest następujące: „مالس”. (jeśli nie rozumiesz perskiego, zobacz ten przykład: pozwól mi „1234” -> „4321”)
Naruto Uzumaki,
1
Oparte na scrollView ... Ładne rozwiązanie, ale nie mogę znaleźć jeszcze żadnej odpowiedzi, która umożliwiłaby użycie widoku tekstowego. :(
superUser
88

TextVieww Android Oofertach samo pełne uzasadnienie (nowe wyrównanie typograficzne).

Musisz tylko to zrobić:

Kotlin

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

Jawa

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

domyślnie jest JUSTIFICATION_MODE_NONE.

Jaydipsinh Zala
źródło
3
Miejmy nadzieję, że zostanie przeniesiony z powrotem do biblioteki wsparcia, a następnie O :)
Stefan Haustein
2
proszę tutaj dodać bibliotekę !!
Kunal Dharaiya
4
jak uzasadnić za pomocą XML?
Vikash Parajuli
14
Możesz użyć Androida: justificationMode = "inter_word" w xml.
Christian D
5
API 26 wymagany dla Androida: justificationMode.
Bink
42

Możesz użyć projektu JustifiedTextView dla Androida w github. jest to widok niestandardowy, który symuluje dla Ciebie wyjustowany tekst. Obsługuje Android 2.0+ i języki od prawej do lewej. wprowadź opis zdjęcia tutaj

Saeed Zarinfam
źródło
nie obsługuje ciągów znaków
MSepehr
jak możemy dodać własny tekst?
Karan
Zobacz próbkę na github.
Saeed Zarinfam
cześć Saeed, tnx za twoją pomoc, czy jest jakiś sposób na obsługę przeglądalnych tekstów ?!
Hamid Reza
@SaeedZarinfam Próbowałem użyć „JustifiedTextView dla Androida”, ale dostałem błąd w tagu xml ir.noghteh.JustifiedTextView udzieliłbym pomocy, aby pomóc mi w tym pytaniu stackoverflow.com/questions/37911376/...
Jumong
30

Piszę widget na podstawie natywnego widoku tekstu, aby to zrobić.

github

Frank Cheng
źródło
Poleciłem ten, głównie dlatego, że opiera się on na oryginalnym widoku tekstu z oficjalnego sdk Androida, który moim zdaniem jest znacznie lżejszy niż technika podglądu, którą wiele osób publikuje na ten temat. Jeśli budujesz aplikację, która wymaga pamięci, na przykład używając obiektów listy, możesz rozważyć użycie czegoś takiego. Ï już to wypróbuj i działa zgodnie z oczekiwaniami. Jeśli ludzie znają inną, taką jak ta 1, proszę podzielić się ze mną swoimi doświadczeniami.
superUser
Dobra robota btw. Czego szukałem.
superUser
5
nie obsługuje języków RTL takich jak perski
odpal w dziurze
1
@Frank Cheng Bardzo przydatna biblioteka. Dostaję dużo miejsca na końcu akapitu. Jak mogę to naprawić?
iSrinivasan27,
1
działało dla mnie, ale ostatnia linia widoku tekstu została odcięta. Musiałem utrzymać padding 5 dla podglądu tekstu.
TharakaNirmana
23

Znalazłem sposób na rozwiązanie tego problemu, ale może to nie być bardzo łaska, ale efekt nie jest zły.

Jego zasadą jest zamiana spacji każdej linii na ImageSpan o stałej szerokości (kolor jest przezroczysty).

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

Umieszczam kod na GitHub: https://github.com/twiceyuan/TextJustification

Przegląd:

Przegląd

dwukrotnie Yuan
źródło
1
Nie działa w podglądzie XML, ale działa świetnie z prawdziwym urządzeniem :)
pgreze
15

Układ XML: deklaruj WebView zamiast TextView

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

Kod Java: ustaw dane tekstowe na 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");

To może rozwiązać problem. W pełni działało dla mnie.


źródło
9

Oto jak to zrobiłem, myślę, że najbardziej elegancki sposób, w jaki mogłem. Dzięki temu rozwiązaniu jedyne rzeczy, które musisz zrobić w swoich układach to:

  • dodaj dodatkową xmlnsdeklarację
  • Zmień swoje TextView źródłową przestrzeń nazw tekstu z Androida na nową
  • zastąpić TextViewszx.y.z.JustifiedTextView

Oto kod. Działa idealnie na moich telefonach (Galaxy Nexus Android 4.0.2, Galaxy Teos Android 2.1). Oczywiście nie krępuj się i zastąp moją nazwę paczki nazwą swoją.

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

Musimy ustawić renderowanie na oprogramowanie, aby uzyskać przezroczyste tło na Androidzie 3+. Stąd try-catch dla starszych wersji Androida.

Mam nadzieję że to pomoże!

PS: nie należy dodawać tego do całej aktywności na Androidzie 3+, aby uzyskać oczekiwane zachowanie:
android:hardwareAccelerated="false"

Benoit Duffez
źródło
To rozwiązanie oparte na webView. Każdy odkrył, że jest oparty na widoku tekstu, biorąc pod uwagę, że widok tekstu jest lżejszy niż przeglądanie stron internetowych i przewijanie.
superUser
9

Bardzo proste Możemy to zrobić w pliku xml

<TextView 
android:justificationMode="inter_word"
/>
Machhindra Neupane
źródło
6

Piszę własną klasę, aby rozwiązać ten problem. Tutaj wystarczy wywołać funkcję justowania statycznego, która przyjmuje dwa argumenty

  1. Obiekt widoku tekstu
  2. Szerokość treści (całkowita szerokość widoku tekstu)

//Główna aktywność

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
źródło
prośby uzupełnij ten przykład przynajmniej dla „\ n” lub System.getProperty („line.separator”), aby uszanować :)
ceph3us
5

FILL_HORIZONTALjest równoważne z CENTER_HORIZONTAL. Możesz zobaczyć ten fragment kodu w kodzie źródłowym textview:

case Gravity.CENTER_HORIZONTAL:
case Gravity.FILL_HORIZONTAL:
    return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
            getCompoundPaddingLeft() - getCompoundPaddingRight())) /
            getHorizontalFadingEdgeLength();
jiashie
źródło
4

Dla tego problemu istnieje CustomView, ten niestandardowy widok tekstu obsługuje Widok uzasadnionego tekstu.

Łup na to: 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;
                }
        }
}

Dodaj powyższą klasę do folderu src i użyj tego przykładowego kodu, aby dodać do swojego układu:

JustifiedTextView jtv= new JustifiedTextView(getApplicationContext(), "Lorem ipsum dolor sit amet... ");
LinearLayout place = (LinearLayout) findViewById(R.id.book_profile_content);
place.addView(jtv);
Merter
źródło
4

patrz tutaj na githubie

Wystarczy zaimportować dwa pliki „TextJustifyUtils.java” i „TextViewEx.java” do swojego projektu.

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

i

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

Teraz, jeśli używasz normalnego tekstu, zobacz:

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

Po prostu użyj

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

Zdefiniuj zmienną i ustaw justify to true,

TextViewEx changed = (TextViewEx) findViewById(R.id.changed);
changed.setText(getResources().getString(R.string.lorum_ipsum),true);
Mr_Moradi
źródło
pogrubiony tekst nie działa, proszę o pomoc, jeśli masz jakieś poprawki?
praveenb,
4

Android Text Justify For TextView XML

Po prostu uzasadnij tekst za pomocą Androida w XML. Możesz po prostu zaimplementować w widżecie widoku tekstu.

 <TextView
    android:justificationMode="inter_word"
/>

Domyślnie jest android:justificationMode="none"

Samad Talukder
źródło
2

Myślę, że są dwie opcje:

  • Użyj czegoś takiego jak Pango, który specjalizuje się w tym za pośrednictwem NDK i renderuj tekst na OpenGL lub innej powierzchni.

  • Użyj Paint.measureText () i znajomych, aby uzyskać długości słów i ułożyć je ręcznie na kanwie w widoku niestandardowym.

Matthew Willis
źródło
2

Na Androidzie, aby po lewej stronie wyjustować tekst i nie mieć obcięcia koloru tła, spróbuj tego, działało to dla mnie, dając spójne wyniki na Androidzie, FF, tj. & Chrome, ale musisz zmierzyć miejsce, które pozostało pomiędzy tekstem przy obliczaniu wypełnienia.

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

Włamanie polega na padding-right:1000px;popychaniu tekstu do skrajnej lewej strony.

Każda próba opuszczenia lub uzasadnienia kodu w css lub html powoduje, że tło ma tylko połowę szerokości.

Robin Glas
źródło
1

Android nie obsługuje jeszcze pełnego uzasadnienia. Możemy korzystać z Webview i uzasadniać HTML zamiast z textview. Działa tak dobrze. Jeśli nie macie jasności, zapytajcie mnie :)

kypiseth
źródło
Można to zrobić. Ale czy możemy ustawić tło WebView transparent. Mam obraz tła.
Mr.India,
Nie sądzę, że może to być mądre.
superUser
1

TextView Content Uzasadnienie: Łatwi faceci po prostu używają Androida: justificationMode = "inter_word" w tagu 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
źródło
-4

Spróbuj użyć < RelativeLayout >(upewniając się, że fill_parent), a następnie po prostu dodaj android:layout_alignParentLeft="true"i

android:layout_alignParentRight="true" do elementów, które chcesz na zewnątrz LEWO i PRAWO.

BLAM, uzasadnione!

esharp
źródło
świetny przykład tutaj: stackoverflow.com/questions/2099249/…
esharp
3
Nadal nie jest tym, czego szuka. Patrz uzasadnienie na Wikipedii: en.wikipedia.org/wiki/Justification_(typesetting)
Kevin Coppock
To nie jest uzasadnienie
Arash Hatami
-5

Musisz ustawić

android:layout_height="wrap_content"

i

android:layout_centerInParent="true"
Lukas
źródło
11
Centruje to tekst, który nie jest w pełni uzasadniony
Janusz
-12

To tak naprawdę nie usprawiedliwia twojego tekstu, ale

android:gravity="center_horizontal"

to najlepszy wybór, jaki masz.

Wolfen
źródło
9
Nie, to wyśrodkowuje tekst. To nie usprawiedliwia tego. Cytując Wikipedię : „W uzasadnionym tekście odstępy między słowami oraz, w mniejszym stopniu, między glifami lub literami (kerning), są rozciągnięte lub czasem skompresowane w celu wyrównania tekstu z lewym i prawym marginesem”.
CommonsWare
tekst nie jest uzasadniony twoim kodem, ale wyśrodkuj go poziomo
Matteo