Văn bản Android Xem văn bản biện minh


396

Làm thế nào để bạn có được văn bản của a TextViewđể được chứng minh (với văn bản tuôn ra ở bên trái và bên phải)?

Tôi đã tìm thấy một giải pháp khả thi ở đây , nhưng nó không hoạt động (ngay cả khi bạn thay đổi trung tâm dọc thành centre_vertical, v.v.).


Câu trả lời @Jimbo là chính xác làm việc cho trường hợp của tôi trên inputtexttextview cho ngôn ngữ tiếng Ả Rập từ phải sang trái và hiển thị nhưng đối với văn bản đầu vào tôi phải thêm trọng lực = "phải"
shareef 21/12/12

Câu trả lời:


239

Tôi không tin rằng Android hỗ trợ biện minh đầy đủ.

CẬP NHẬT 2018-01-01 : Android 8.0+ hỗ trợ các chế độ biện minh vớiTextView .


5
Sau khi phân tích sâu hơn, bạn có thể cung cấp cho android: vity = "fill_horizontal". Điều đó được mô tả là "Tăng kích thước ngang của đối tượng nếu cần để nó hoàn toàn lấp đầy thùng chứa của nó", nhưng tôi không biết làm thế nào họ "phát triển" văn bản.
CommonsWare

8
android: vity = "fill_horizontal" cũng không hoạt động. Dường như android không hỗ trợ biện minh cho tất cả, ồ tốt :)

6
Không, bạn không thể đặt thuộc tính như trọng lực. Nhưng bạn vẫn có thể đặt lời biện minh cho văn bản của mình bằng cách xem webview thay vì xem văn bản. Bạn có thể tham khảo seal.io/2010/12/only-way-how-to-align-text-in-block-in.html . (Lấy trộm từ stackoverflow.com/questions/5976627/ trên )
jcaruso

2
@CommonsWare Bây giờ có cách nào thích hợp để biện minh cho văn bản không?
John R

1
Man, tôi đang sống với webview nặng để đạt được điều này và tin tôi đi, UI của tôi khóc cho một số thứ mới chưa được thêm vào API, vì nó rất chậm đối với các thành phần như trò chuyện trong listview.
nobalG

156

Câu trả lời @CommonsWare là chính xác. Android 8.0+ không hỗ trợ "Full Justify" (hoặc đơn giản là "Justify", vì đôi khi nó được gọi một cách mơ hồ).

Android cũng hỗ trợ "Sắp xếp văn bản trái / phải". Xem bài viết trên wikipedia về Sự biện minh cho sự khác biệt. Nhiều người coi khái niệm 'biện minh' bao gồm toàn bộ biện minh cũng như căn chỉnh văn bản trái / phải, đó là những gì họ kết thúc tìm kiếm khi họ muốn thực hiện căn chỉnh văn bản trái / phải. Câu trả lời này giải thích làm thế nào để đạt được sự liên kết văn bản trái / phải.

Có thể đạt được sự sắp xếp văn bản trái / phải của Flush (trái ngược với sự biện minh đầy đủ, như câu hỏi đang hỏi về). Để chứng minh tôi sẽ sử dụng một biểu mẫu 2 cột cơ bản (nhãn ở cột bên trái và trường văn bản ở cột bên phải) làm ví dụ. Trong ví dụ này, văn bản trong các nhãn ở cột bên trái sẽ được căn phải để chúng xuất hiện lộn ngược với các trường văn bản của chúng trong cột bên phải.

Trong bố cục XML, bạn có thể tự lấy các phần tử TextView (cột bên trái) để căn chỉnh sang phải bằng cách thêm thuộc tính sau vào bên trong tất cả các TextViews:

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

Tuy nhiên, nếu văn bản kết thúc thành nhiều dòng, văn bản vẫn sẽ được căn trái bên trong TextView. Việc thêm thuộc tính sau làm cho văn bản thực tế được căn phải thẳng hàng (rách bên trái) bên trong TextView:

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

Vì vậy, thuộc tính trọng lực chỉ định cách căn chỉnh văn bản bên trong TextView layout_gravity chỉ định cách căn chỉnh / bố trí chính phần tử TextView.


12
Nếu tôi hiểu chính xác và đưa ra kết quả kiểm tra này, tất cả những điều này là căn chỉnh văn bản sang trái hoặc phải. Điều này không biện minh cho văn bản, phải không?
Paul Lammertsma

14
Thông minh. Chỉ cần thêm, nếu bạn muốn biện minh trung tâm, bạn có thể làm android:layout_gravity="center_horizontal|center" android:gravity="center".
Luis A. Florit

chắc chắn làm việc cho trường hợp của tôi trên inputtexttextview cho ngôn ngữ tiếng Ả Rập từ phải sang trái và hiển thị
shareef

1
Đây chỉ là sự liên kết, không phải là biện minh. Đọc rằng Wikipedia liên kết cẩn thận. Sự khác biệt giữa các loại biện minh khác nhau chỉ ảnh hưởng đến dòng cuối cùng của đoạn. Không có lời biện minh trái / phải / trung tâm cho các đoạn chỉ có một dòng.
Karu

sau đó tại sao thậm chí trả lời nó ở đây nếu nó không phải là vềjustify
user924

136

Để biện minh cho văn bản trong Android, tôi đã sử dụng 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");

và 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>

Tôi chưa thể tải lên hình ảnh để chứng minh nhưng "nó hoạt động với tôi".


3
Giải pháp tốt đẹp đây. FWIW bạn không cần hầu hết các html bổ sung. Thẻ cơ thể với căn chỉnh văn bản là đủ.
gnac

5
Điều này hoạt động tốt. Lưu ý rằng bạn có thể làm cho nền trong suốt bằng cách làm theo view.loadData()với view.setBackgroundColor("#00000000").
Paul Lammertsma

Tuy nhiên, tôi đã không thành công trong việc khiến nó tải một phông chữ / kiểu chữ tùy chỉnh. Tôi đã thử điều này và đề nghị này , không có may mắn.
Paul Lammertsma

2
Như tôi đã đề cập trong các luồng đó, tôi đã tìm thấy một giải pháp: nếu bạn tạo tệp HTML và đặt nó vào tài sản, tải nó qua view.loadUrl()các tác phẩm, trong khi view.loadData()không. Tôi không biết tại sao cái sau không.
Paul Lammertsma

1
@PaulLammertsma, setBackgroundColor (0x00000000) thay vào đó là định dạng chính xác để đặt nền trong suốt.
richey

100

CẬP NHẬT

Chúng tôi đã tạo ra một lớp đơn giản cho việc này. Hiện tại có hai phương pháp để đạt được những gì bạn đang tìm kiếm. Cả hai đều không yêu cầu WEBVIEWSUPPORTS SPANNABLES .

THƯ VIỆN : https://github.com/bluejamesbond/TextJustify-Android

HP TRỢ : Android 2.0 lên 5.X

THIẾT LẬP

// Please visit Github for latest setup instructions.

MÀN HÌNH

So sánh.png


Thực sự hữu ích, nhưng sử dụng nó, TextViews của tôi không giữ định dạng ban đầu, tôi giới thiệu: lề, kiểu văn bản và tôi nghĩ rằng kích thước văn bản cũng không, Plese tiếp tục làm việc trong đó, nên là một trợ giúp thực sự tuyệt vời
Leonardo Sapuy

Vâng, tôi không thể thành lập các lớp. Một trong số họ không có bất kỳ packagename nào, cái còn lại có một số lỗi màu vàng. Thật ra tôi không thể tin được.
mehmet

Rất vui, nhưng tôi vẫn không biết cách thêm bất kỳ định dạng nào vào Văn bản bằng thư viện này.
Semanticer

4
Cảm ơn thư viện chia sẻ tuyệt vời này, nhưng nó không thể hỗ trợ văn bản Ba Tư hoặc tiếng Ả Rập. Khi tôi đặt hướng, từ của tôi rút từ cuối đến bắt đầu, thay vì bắt đầu từ cuối. Tôi có nghĩa là thế này: Lời của tôi là: "سلام" và bản vẽ của nó như thế này: "مالس". (nếu bạn không hiểu Ba Tư hãy xem ví dụ này: hãy để tôi "1234" -> "4321")
Naruto Uzumaki

1
Dựa trên scrollView ... Tuy nhiên, giải pháp tuyệt vời không thể tìm thấy bất kỳ câu trả lời nào làm cho nó rõ ràng với textview. :(
superUser

88

TextViewtrong Android Ocung cấp đầy đủ biện minh (căn chỉnh kiểu chữ mới) chính nó.

Bạn chỉ cần làm điều này:

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

mặc định là JUSTIFICATION_MODE_NONE.


3
Chúng ta hãy hy vọng nó được chuyển trở lại thư viện hỗ trợ sau đó O :)
Stefan Haustein

2
vui lòng thêm thư viện ở đây !!
Kunal Dharaiya

4
Làm thế nào để biện minh cho việc sử dụng XML?
Vikash Parajuli

14
Bạn có thể sử dụng android: justificationMode = "inter_word" trong xml.
Christian D

5
API 26 cần thiết cho android: justificationMode.
Bink

42

Bạn có thể sử dụng dự án JustifiedTextView cho Android trong github. đây là chế độ xem tùy chỉnh mô phỏng văn bản hợp lý cho bạn. Nó hỗ trợ Android 2.0+ và các ngôn ngữ từ phải sang trái. nhập mô tả hình ảnh ở đây


nó không hỗ trợ chuỗi có thể mở rộng
MSepehr 04/07/2015

Làm thế nào chúng ta có thể thêm văn bản của chúng ta?
Karan

Xin vui lòng xem mẫu trên github.
Saeed Zarinfam

chào Saeed, tnx vì sự giúp đỡ của bạn, có cách nào để hỗ trợ các cuộc phỏng vấn có thể mở rộng không?!
Hamid Reza

@SaeedZarinfam Tôi đã thử sử dụng "JustifiedTextView cho Android" nhưng tôi đã gặp lỗi trên thẻ xml ir.noghteh.JustifiedTextView sẽ giúp tôi về câu hỏi này stackoverflow.com/questions/37911376/
Jumong

30

Tôi viết một cơ sở widget trên textview bản địa để làm điều đó.

github


Tôi muốn giới thiệu cái này, chủ yếu là vì nó dựa trên textview gốc từ sdk chính thức của Android, theo ý kiến ​​cá nhân của tôi, nó nhẹ hơn kỹ thuật của webview mà nhiều người đang đăng về chủ đề chung này. Nếu bạn xây dựng một ứng dụng cần phải có trí nhớ, ví dụ sử dụng các đối tượng listview, bạn có thể cân nhắc sử dụng một cái gì đó như thế này. Đã sẵn sàng dùng thử và hoạt động như mong đợi. Nếu mọi người biết một người khác tốt hơn như thế này, xin vui lòng bạn có thể chia sẻ kinh nghiệm của bạn với tôi.
siêu người dùng

Làm tốt lắm btw. Những gì tôi đang tìm kiếm.
siêu người dùng

5
không hỗ trợ các ngôn ngữ RTL như Ba Tư
bắn vào lỗ

1
@Frank Cheng Thư viện rất hữu ích. Tôi nhận được rất nhiều khoảng trống ở cuối đoạn. Làm thế nào tôi có thể sửa chữa nó?
iSrinivasan27

1
làm việc cho tôi, nhưng dòng cuối cùng của văn bản đã bị cắt. Tôi đã phải tiếp tục đệm xuống 5 cho phần xem.
TharakaNirmana 17/03/2016

23

Tôi tìm thấy một cách để giải quyết vấn đề này, nhưng điều này có thể không duyên dáng lắm, nhưng hiệu quả không tệ.

Nguyên tắc của nó là thay thế khoảng trắng của mỗi dòng thành ImageSpan có chiều rộng cố định (màu trong suốt).

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

Tôi đặt mã trên GitHub: https://github.com/twiceyuan/TextJustification

Tổng quat:

Tổng quat


1
Không hoạt động trong bản xem trước XML nhưng hoạt động tuyệt vời với một thiết bị thực :)
pgreze 15/03/18

15

Bố cục XML: khai báo WebView thay vì TextView

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

Mã Java: đặt dữ liệu văn bản thành 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");

Điều này có thể giải quyết vấn đề của bạn. Nó hoàn toàn làm việc cho tôi.


9

Đây là cách tôi đã làm nó, tôi nghĩ rằng cách thanh lịch nhất tôi có thể. Với giải pháp này, điều duy nhất bạn cần làm trong bố cục của mình là:

  • thêm một xmlnstuyên bố bổ sung
  • thay đổi TextViewkhông gian tên văn bản nguồn của bạn từ Android sang không gian tên mới của bạn
  • thay TextViews của bạn bằngx.y.z.JustifiedTextView

Đây là mã. Hoạt động hoàn toàn tốt trên điện thoại của tôi (Galaxy Nexus Android 4.0.2, Galaxy Teos Android 2.1). Tất nhiên, hãy thoải mái thay thế tên gói của tôi bằng tên của bạn.

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

Chúng ta cần đặt kết xuất thành phần mềm để có được nền trong suốt trên Android 3+. Do đó, thử bắt cho các phiên bản Android cũ hơn.

Hi vọng điêu nay co ich!

PS: vui lòng không hữu ích khi thêm phần này vào toàn bộ hoạt động của bạn trên Android 3+ để có được hành vi mong đợi:
android:hardwareAccelerated="false"


Đây là giải pháp dựa trên webView. Bất kỳ ai đã tìm thấy dựa trên textview, xem xét textview nhẹ hơn so với webview và scrollview.
siêu người dùng

9

Rất đơn giản Chúng tôi có thể làm điều đó trong tệp xml

<TextView 
android:justificationMode="inter_word"
/>


6

Tôi viết lớp riêng của mình để giải quyết vấn đề này. Ở đây, bạn chỉ cần gọi hàm justify tĩnh có hai đối số

  1. Đối tượng xem văn bản
  2. Chiều rộng nội dung (Tổng chiều rộng của chế độ xem văn bản của bạn)

//Hoạt động chính

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>

xin vui lòng hoàn thành ví dụ này ít nhất là để "\ n" hoặc System.getProperty ("line.separator") tôn trọng :)
ceph3us

5

FILL_HORIZONTALtương đương với CENTER_HORIZONTAL. Bạn có thể thấy đoạn mã này trong mã nguồn của textview:

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

4

Có một CustomView cho vấn đề này, chế độ xem văn bản tùy chỉnh này hỗ trợ Chế độ xem văn bản hợp lý.

Xem tại đây: 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;
                }
        }
}

Thêm lớp trên vào thư mục src của bạn và sử dụng mã mẫu này để thêm vào bố cục của bạn:

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

4

xem ở đây trong github

Chỉ cần nhập hai tệp "TextJustifyUtils.java" và "TextViewEx.java" trong dự án của bạn.

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

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

Bây giờ, nếu bạn sử dụng textView bình thường như:

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

Đơn giản chỉ cần sử dụng

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

Xác định một biến và đặt biện minh là đúng,

TextViewEx changed = (TextViewEx) findViewById(R.id.changed);
changed.setText(getResources().getString(R.string.lorum_ipsum),true);

văn bản in đậm không hoạt động, xin vui lòng giúp đỡ nếu bạn có bất kỳ sửa chữa cho nó?
Praveenb

4

Văn bản Android biện minh cho TextView XML

Đơn giản chỉ cần sử dụng văn bản android bằng cách sử dụng trong XML. Bạn chỉ có thể thực hiện trong widget textview.

 <TextView
    android:justificationMode="inter_word"
/>

Mặc định là android:justificationMode="none"


2

Tôi nghĩ có hai lựa chọn:

  • Sử dụng một cái gì đó như Pango chuyên về điều này thông qua NDK và kết xuất văn bản thành OpenGL hoặc bề mặt khác.

  • Sử dụng Paint.measureText () và bạn bè để lấy độ dài của từ và đặt chúng theo cách thủ công trên Canvas trong chế độ xem tùy chỉnh.


2

Trên Android, để lại văn bản biện minh và không cắt bớt màu nền, hãy thử điều này, nó hoạt động với tôi, tạo ra kết quả nhất quán trên Android, ff, tức là & chrome nhưng bạn phải đo khoảng trống còn lại giữa văn bản khi tính toán phần đệm.

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

Việc hack là padding-right:1000px;đẩy văn bản sang cực tả.

Bất kỳ nỗ lực nào để mã bên trái hoặc chứng minh bằng css hoặc html đều dẫn đến một nền chỉ có một nửa chiều rộng.



1

Android chưa hỗ trợ biện minh đầy đủ. Chúng tôi có thể sử dụng Webview và chứng minh HTML thay vì sử dụng textview. Nó hoạt động rất tốt. Nếu các bạn không rõ ràng, hãy hỏi tôi :)


Điều đó có thể được thực hiện. Nhưng chúng ta có thể thiết lập nền tảng của WebView transparent. Tôi có một hình nền.
Mr.Ấn

Tôi không nghĩ rằng đây có thể là trí nhớ khôn ngoan.
siêu người dùng


1

Văn bản chứng minh nội dung TextView: Những kẻ dễ dàng chỉ cần sử dụng android: justificationMode = "inter_word" trong thẻ TextView của bạn.

 <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"
     />

-4

Hãy thử sử dụng < RelativeLayout >(đảm bảo điền_parent), sau đó chỉ cần thêm android:layout_alignParentLeft="true"

android:layout_alignParentRight="true" đến các yếu tố bạn muốn ở bên ngoài TRÁI & PHẢI.

BLAM, hợp lý!


ví dụ tuyệt vời ở đây: stackoverflow.com/questions/2099249/ từ
esharp

3
Vẫn không phải là những gì anh ấy đang tìm kiếm. Xem Biện minh tại Wikipedia: vi.wikipedia.org/wiki/Justification_(typesding)
Kevin Coppock

Đó không phải là một lời biện minh
Arash Hatami

-5

Bạn phải đặt

android:layout_height="wrap_content"

android:layout_centerInParent="true"

11
Điều này tập trung vào văn bản không đầy đủ chính đáng
Janusz

-12

Điều này không thực sự biện minh cho văn bản của bạn nhưng

android:gravity="center_horizontal"

là sự lựa chọn tốt nhất mà bạn có.


9
Không, đó là trung tâm văn bản. Nó không biện minh cho nó. Trích dẫn Wikipedia : "Trong văn bản hợp lý, khoảng cách giữa các từ và, ở mức độ thấp hơn, giữa glyphs hoặc chữ cái (kTHER), được kéo dài hoặc đôi khi được nén để làm cho văn bản thẳng hàng với cả lề trái và lề phải."
CommonsWare

văn bản không được chứng minh bằng mã của bạn mà nằm giữa văn bản
Matteo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.