Làm cách nào để hiển thị HTML trong TextView?


756

Tôi có HTML đơn giản :

<h2>Title</h2><br>
<p>description here</p>

Tôi muốn hiển thị văn bản theo kiểu HTML TextView. làm như thế nào?


7
Bạn có muốn hiển thị các thẻ hoặc bỏ qua chúng?
DerMike

1
kiểm tra liên kết này để biết ví dụ làm việc javatechig.com/2013/04/07/how-to-display-html-in-android-view
Nilanchal

1
Nếu bạn đang tìm kiếm giải pháp không dùng nữa, thì ngay tại đây stackoverflow.com/questions/37904739/
mẹo

Câu trả lời:


1351

Bạn cần sử dụng Html.fromHtml()để sử dụng HTML trong Chuỗi XML của mình. Chỉ cần tham khảo Chuỗi có HTML trong bố cục của bạn XML sẽ không hoạt động.

Đây là những gì bạn nên làm:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    textView.setText(Html.fromHtml("<h2>Title</h2><br><p>Description here</p>", Html.FROM_HTML_MODE_COMPACT));
} else { 
    textView.setText(Html.fromHtml("<h2>Title</h2><br><p>Description here</p>"));
}

7
h2theo định nghĩa tạo ra rất nhiều lề xung quanh chính nó. và pcũng đi kèm với một số lề. nếu bạn không muốn khoảng cách, bạn có thể muốn xem xét sử dụng các yếu tố html khác.
David Hedlund

10
Xin chào, bạn có thể đặt các thẻ trong XML, bạn chỉ cần bọc chúng trong ngoặc CDATA.
Gerard

3
Đối với những người muốn nó hoạt động với các thẻ ol / ul / li, hãy xem giải pháp này: stackoverflow.com/a/3150456/1369016
Tiago

13
Điều đó nên được android.text.Html.fromHtml. Tôi biết hầu hết các IDE sẽ sửa nó cho bạn nhưng để dễ đọc thì nên biết tên gói.
Martin

14
@Martin Tôi sẽ không nói về khả năng đọc mà thay vào đó là sự kiệt sức . Tên đủ điều kiện IMO được sử dụng trực tiếp trong mã như thế này ít đọc hơn tên ngắn. Nhưng tôi đồng ý với bạn về thực tế rằng một câu trả lời như thế này sẽ cung cấp gói (trên một ghi chú bên cạnh), mà điểm của liên kết ở đây;)
Joffrey

76

setText (Html.fromHtml (bodyData)) đang bị phản đối sau khi api 24. Bây giờ bạn phải làm điều này:

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
      tvDocument.setText(Html.fromHtml(bodyData,Html.FROM_HTML_MODE_LEGACY));
 } else {
      tvDocument.setText(Html.fromHtml(bodyData));
 }

4
Tại sao lại sử dụng TỪ KHÓA_MODE_LEGACY trong API 24+?
galcyurio

64

Hãy xem cái này: https://stackoverflow.com/a/8558249/450148

Nó cũng khá tốt !!

<resource>
    <string name="your_string">This is an <u>underline</u> text demo for TextView.</string>
</resources>

Nó chỉ hoạt động cho một vài thẻ.


12
Có bất kỳ danh sách các thẻ được hỗ trợ bởi phương pháp này?
mente

23
@mente Theo mã nguồn : <a>, <b>, <big>, <blockquote>, <br>, <cite>, <dfn> <div align = "...">, <em>, < font size = "..." color = "..." face = "..."> <h1-6>, <i>, <img src = "...">, <p>, <small > <strike> <strong> <sub>, <sup>, <tt>, <u> (nguồn: dzone.com/snippets/how-display-html-android )
JerabekJakub

@JerabekJakub nhưng hãy cẩn thận, nếu bạn định xử lý img, bạn phải thực hiện Html.ImageGetter.
MiguelHincapieC

@ 0mahc0 khi một người thực hiện img có thể đặt kích thước không?
Joh

1
@Joh vâng, nó có thể. Khi bạn đang triển khai .ImageGetter, có một phương thức gọi là getDrawable (Chuỗi nguồn). Nếu bạn cần thêm trợ giúp, hãy tạo một câu hỏi và gắn thẻ cho tôi, tôi sẽ cho bạn một ví dụ;)
MiguelHincapieC

41

Nếu bạn muốn có thể định cấu hình nó thông qua xml mà không cần sửa đổi gì trong mã java, bạn có thể thấy ý tưởng này hữu ích. Đơn giản là bạn gọi init từ constructor và đặt văn bản là html

public class HTMLTextView extends TextView {
    ... constructors calling init...
    private void init(){
       setText(Html.fromHtml(getText().toString()));
    }    
}

xml:

<com.package.HTMLTextView
android:text="@string/about_item_1"/>

1
Cái gì '...'. Xin làm rõ
GilbertS

25

Nếu bạn đang cố gắng hiển thị HTML từ id tài nguyên chuỗi, định dạng có thể không hiển thị trên màn hình. Nếu điều đó đang xảy ra với bạn, hãy thử sử dụng thẻ CDATA thay thế:

strings.xml:
<string name="sample_string"><![CDATA[<h2>Title</h2><br><p>Description here</p>]]></string>

...

MainActivity.java:
text.setText(Html.fromHtml(getString(R.string.sample_string));

Xem bài đăng này để biết thêm chi tiết.


Cảm ơn, điều này đã giúp tôi - sử dụng API 23.
XMAN

24

Các mã dưới đây đã cho kết quả tốt nhất cho tôi.

TextView myTextview = (TextView) findViewById(R.id.my_text_view);
htmltext = <your html (markup) character>;
Spanned sp = Html.fromHtml(htmltext);
myTextview.setText(sp);

13
String value = "<html> <a href=\"http://example.com/\">example.com</a> </html>";
    SiteLink= (TextView) findViewById(R.id.textViewSite);
    SiteLink.setText(Html.fromHtml(value));
    SiteLink.setMovementMethod(LinkMovementMethod.getInstance());

Làm thế nào để bạn thay đổi màu sắc của neo?
EdmundYeung99

android: textColorLink = "color"
Pedro

cái này sẽ tô màu toàn bộ textview thành màu đỏ, nhưng nếu tôi chỉ muốn các thẻ neo, tôi cần bọc thẻ <a> bằng các thẻ <font> và thêm màu vào đó
EdmundYeung99

11

Nếu bạn chỉ muốn hiển thị một số văn bản html và không thực sự cần a TextView, thì hãy lấy WebViewvà sử dụng nó như sau:

String htmlText = ...;
webview.loadData(htmlText , "text/html; charset=UTF-8", null);

Điều này cũng không giới hạn bạn trong một vài thẻ html.


2
Trong khi đây là một cách rất hữu ích để có được xung quanh các thiết lập giới hạn của thẻ html, được hỗ trợ bởi TextView, nó có những bất lợi mà nó không hoạt động tốt với layout_height="wrap_content". Thay vào đó, bạn sẽ phải đặt chiều cao rõ ràng hoặc match_parent.
Vô lý

3

11

Cách tiếp cận tốt nhất để sử dụng các phần CData cho chuỗi trong tệp String.xml để hiển thị thực tế nội dung html cho TextView đoạn mã dưới đây sẽ cho bạn ý tưởng hợp lý.

//in string.xml file
<string name="welcome_text"><![CDATA[<b>Welcome,</b> to the forthetyroprogrammers blog Logged in as:]]> %1$s.</string>

//and in Java code
String welcomStr=String.format(getString(R.string.welcome_text),username);
tvWelcomeUser.setText(Html.fromHtml(welcomStr));

Phần CData trong văn bản chuỗi giữ nguyên dữ liệu thẻ html ngay cả sau khi định dạng văn bản bằng phương thức String.format. Vì vậy, Html.fromHtml (str) hoạt động tốt và bạn sẽ thấy văn bản in đậm trong thông điệp Chào mừng.

Đầu ra:

Chào mừng bạn đến cửa hàng ứng dụng âm nhạc yêu thích của bạn. Đăng nhập với tên: tên người dùng


Cảm ơn, điều này đã giúp tôi - sử dụng API 23.
XMAN

cảm ơn, bạn đã lưu ngày của tôi :) Chỉ là một bổ sung nhỏ: Chúng tôi cần thêm kiểm tra này vào mã ở trên: if (Build.VERSION.SDK_INT> = Build.VERSION_CODES.N) {// cho 24 api và nhiều textView.setText ( Html.fromHtml (welcomeStr, Html.FROMET_OPTION_USE_CSS_COLORS)); } other {// hoặc cho api textView.setText cũ hơn (Html.fromHtml (welcomeStr)); }. Giá trị cho cờ tham số thứ 2 cho API> = 24, có thể là bất cứ điều gì theo yêu cầu.
AndroidGuy


6

Tôi cũng muốn đề xuất dự án sau: https://github.com/NightWhistler/HtmlSpanner

Cách sử dụng gần giống như trình chuyển đổi Android mặc định:

(new HtmlSpanner()).fromHtml()

Tìm thấy nó sau khi tôi đã bắt đầu bằng cách triển khai html sang trình chuyển đổi có thể mở rộng, bởi vì Html.fromHtml tiêu chuẩn không cung cấp đủ tính linh hoạt đối với kiểm soát kết xuất và thậm chí không có khả năng sử dụng phông chữ tùy chỉnh từ ttf


Tôi đang gặp lỗi sau: Lỗi: (80, 13) Không thể giải quyết: com.osbcp.cssparser: cssparser: 1.5 Làm cách nào để giải quyết vấn đề này?
Araju

6

Tôi biết câu hỏi này là cũ. Các câu trả lời khác ở đây gợi ýHtml.fromHtml() phương pháp. Tôi đề nghị bạn sử dụng HtmlCompat.fromHtml()từ androidx.core.text.HtmlCompatgói. Vì đây là phiên bản tương thích ngược củaHtml lớp.

Mã mẫu:

import androidx.core.text.HtmlCompat;
import android.text.Spanned;
import android.widget.TextView;

String htmlString = "<h1>Hello World!</h1>";

Spanned spanned = HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_COMPACT);

TextView tvOutput = (TextView) findViewById(R.id.text_view_id);

tvOutput.setText(spanned);

Bằng cách này, bạn có thể tránh kiểm tra phiên bản API của Android và thật dễ sử dụng (giải pháp một dòng).


Làm thế nào mà khác với methot cũ? Mục đích chế độ html là gì?
1209216

1
Đã tìm kiếm một cái gì đó như thế này. Cảm ơn :)
Subhrajyoti Sen

5

Sử dụng đơn giản Html.fromHtml("html string"). Điều này sẽ làm việc. Nếu chuỗi có các thẻ như <h1>thì không gian sẽ đến. Nhưng chúng ta không thể loại bỏ những không gian đó. Nếu bạn vẫn muốn xóa khoảng trắng, thì bạn có thể xóa các thẻ trong chuỗi và sau đó chuyển chuỗi sang phương thức Html.fromHtml("html string");. Ngoài ra, nhìn chung các chuỗi này đến từ máy chủ (động) nhưng không thường xuyên, nếu đó là trường hợp tốt hơn để truyền chuỗi vì nó là phương thức hơn là cố gắng loại bỏ các thẻ khỏi chuỗi.


4
String value = html value ....
mTextView.setText(Html.fromHtml(value),TextView.BufferType.SPANNABLE)

4

Thực hiện một phương pháp toàn cầu như:

public static Spanned stripHtml(String html) {
            if (!TextUtils.isEmpty(html)) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    return Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT);
                } else {
                    return Html.fromHtml(html);
                }
            }
            return null;
        }

Bạn cũng có thể sử dụng nó trong Activity / Fragment của mình như:

text_view.setText(stripHtml(htmlText));

3

Tôi đã thực hiện điều này bằng cách sử dụng xem web. Trong trường hợp của tôi, tôi phải tải hình ảnh từ URL cùng với văn bản trong chế độ xem văn bản và điều này làm việc cho tôi.

WebView myWebView =new WebView(_context);
        String html = childText;
        String mime = "text/html";
        String encoding = "utf-8";
        myWebView.getSettings().setJavaScriptEnabled(true);
        myWebView.loadDataWithBaseURL(null, html, mime, encoding, null);

Để hiển thị đúng UTF-8, bạn cần đặt loại MIME thành "text / html; charset = UTF-8".
shawkinaw

3

Nó đã được đề xuất thông qua các câu trả lời khác nhau để sử dụng lớp khung Html như được đề xuất ở đây, nhưng thật không may, lớp này có hành vi khác nhau trong các phiên bản khác nhau của Android và các lỗi không được khắc phục khác nhau, như đã được trình bày trong các vấn đề 214637 , 14778 , 23512875953 .

Do đó, bạn có thể muốn sử dụng thư viện tương thích để chuẩn hóa và nhập lại lớp Html trên các phiên bản Android, bao gồm nhiều cuộc gọi lại cho các yếu tố và kiểu dáng:

Dự án Github HtmlCompat

Mặc dù tương tự như lớp Html của khung công tác, một số thay đổi chữ ký được yêu cầu để cho phép nhiều cuộc gọi lại hơn. Đây là mẫu từ trang GitHub:

Spanned fromHtml = HtmlCompat.fromHtml(context, source, 0);
// You may want to provide an ImageGetter, TagHandler and SpanCallback:
//Spanned fromHtml = HtmlCompat.fromHtml(context, source, 0,
//        imageGetter, tagHandler, spanCallback);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(fromHtml);

@MartijnPieters Câu trả lời đã đóng trước đó là một bản sao của câu trả lời cho câu hỏi này liên quan đến sự phản đối của một phương pháp khung . Tôi đã mở rộng lý do sử dụng thư viện tương thích sẽ là cách tiếp cận tốt hơn. Tôi không nghĩ là hợp lý khi gắn cờ câu hỏi là trùng lặp với nhau vì chúng rõ ràng khác nhau.
Paul Lammertsma

2

Bất cứ khi nào bạn viết tùy chỉnh xem văn bản, tính năng văn bản của bộ HTML sẽ bị biến mất dưới dạng một số thiết bị.

Vì vậy, chúng ta cần phải làm theo các bước gây nghiện sau đây là công việc

public class CustomTextView extends TextView {

    public CustomTextView(..) {
        // other instructions
        setText(Html.fromHtml(getText().toString()));
    }
}

1
public class HtmlTextView extends AppCompatTextView {

public HtmlTextView(Context context) {
    super(context);
    init();
}

private void init(){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        setText(Html.fromHtml(getText().toString(), Html.FROM_HTML_MODE_COMPACT));
    } else {
        setText(Html.fromHtml(getText().toString()));
    }
 }
}

cập nhật câu trả lời ở trên


1

Sử dụng mã dưới đây để có được giải pháp:

textView.setText(fromHtml("<Your Html Text>"))

Phương pháp sử dụng

public static Spanned fromHtml(String text)
{
    Spanned result;
    if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
        result = Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY);
    } else {
        result = Html.fromHtml(text);
    }
    return result;
}

1

Đã tạo tiện ích mở rộng Kotlin để chuyển đổi html từ Chuỗi -

fun String?.toHtml(): Spanned? {
    if (this.isNullOrEmpty()) return null
    return HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_COMPACT)
}

0

Tôi có thể đề nghị một giải pháp hơi khó khăn nhưng vẫn thiên tài! Tôi đã có ý tưởng từ bài viết này và điều chỉnh nó cho Android. Về cơ bản, bạn sử dụng WebViewvà chèn HTML bạn muốn hiển thị và chỉnh sửa trong thẻ div có thể chỉnh sửa. Cách này khi người dùng chạmWebView bàn phím xuất hiện và cho phép chỉnh sửa. Họ chỉ cần thêm một số JavaScript để lấy lại HTML và voila đã chỉnh sửa!

Đây là mã:

public class HtmlTextEditor extends WebView {

    class JsObject {
        // This field always keeps the latest edited text
        public String text;
        @JavascriptInterface
        public void textDidChange(String newText) {
            text = newText.replace("\n", "");
        }
    }

    private JsObject mJsObject;

    public HtmlTextEditor(Context context, AttributeSet attrs) {
        super(context, attrs);

        getSettings().setJavaScriptEnabled(true);
        mJsObject = new JsObject();
        addJavascriptInterface(mJsObject, "injectedObject");
        setWebViewClient(new WebViewClient(){
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                loadUrl(
                        "javascript:(function() { " +
                            "    var editor = document.getElementById(\"editor\");" +
                            "    editor.addEventListener(\"input\", function() {" +
                            "        injectedObject.textDidChange(editor.innerHTML);" +
                            "    }, false)" +
                            "})()");
            }
        });
    }

    public void setText(String text) {
        if (text == null) { text = ""; }

        String editableHtmlTemplate = "<!DOCTYPE html>" + "<html>" + "<head>" + "<meta name=\"viewport\" content=\"initial-scale=1.0\" />" + "</head>" + "<body>" + "<div id=\"editor\" contenteditable=\"true\">___REPLACE___</div>" + "</body>" + "</html>";
        String editableHtml = editableHtmlTemplate.replace("___REPLACE___", text);
        loadData(editableHtml, "text/html; charset=utf-8", "UTF-8");
        // Init the text field in case it's read without editing the text before
        mJsObject.text = text;
    }

    public String getText() {
        return mJsObject.text;
    }
}

đây là thành phần như một Gist.

Lưu ý: Tôi không cần gọi lại thay đổi chiều cao từ giải pháp ban đầu để thiếu ở đây nhưng bạn có thể dễ dàng thêm nó nếu cần.


0

Nếu bạn sử dụng androidx.các lớp * trong dự án của bạn, bạn nên sử dụng HtmlCompat.fromHtml(text, flag). Nguồn của phương thức là:

@NonNull public static Spanned fromHtml(@NonNull String source, @FromHtmlFlags int flags) { if (Build.VERSION.SDK_INT >= 24) { return Html.fromHtml(source, flags); } //noinspection deprecation return Html.fromHtml(source); }

Đó là cách tốt hơn so với Html.fromHtml vì có ít mã hơn, chỉ có một dòng và cách được khuyến nghị để sử dụng nó.


0

Bạn có thể sử dụng chức năng mở rộng Kotlin đơn giản như thế này:

fun TextView.setHtmlText(source: String) {
    this.text = HtmlCompat.fromHtml(source, HtmlCompat.FROM_HTML_MODE_LEGACY)
}

Và cách sử dụng:

textViewMessage.setHtmlText("Message: <b>Hello World</b>")

0

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

String variable="StackOverflow";
textView.setText(Html.fromHtml("<b>Hello : </b>"+ variable));
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.