Html.fromHtml descontinuado no Android N

300

Eu estou usando Html.fromHtmlpara visualizar html em um TextView.

Spanned result = Html.fromHtml(mNews.getTitle());
...
...
mNewsTitle.setText(result);

Mas Html.fromHtmlagora está obsoleto no Android N +

O que / como encontro a nova maneira de fazer isso?

Aldasa
fonte

Respostas:

616

update : como @ Andy mencionado abaixo, o Google criou o HtmlCompatque pode ser usado em vez do método abaixo. Adicione essa dependência implementation 'androidx.core:core:1.0.1 ao arquivo build.gradle do seu aplicativo. Certifique-se de usar a versão mais recente do androidx.core:core.

Isso permite que você use:

HtmlCompat.fromHtml(html, HtmlCompat.FROM_HTML_MODE_LEGACY);

Você pode ler mais sobre os diferentes sinalizadores na documentação HtmlCompat

resposta original: No Android N, eles introduziram um novo Html.fromHtmlmétodo. Html.fromHtmlagora requer um parâmetro adicional, chamado flags. Esse sinalizador oferece mais controle sobre como o HTML é exibido.

No Android N e acima, você deve usar esse novo método. O método mais antigo está obsoleto e pode ser removido nas futuras versões do Android.

Você pode criar seu próprio método Util, que usará o método antigo em versões mais antigas e o mais recente no Android N e acima. Se você não adicionar uma versão, verifique se o aplicativo será interrompido nas versões inferiores do Android. Você pode usar esse método na sua classe Util.

@SuppressWarnings("deprecation")
public static Spanned fromHtml(String html){
    if(html == null){
        // return an empty spannable if the html is null
        return new SpannableString("");
    }else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        // FROM_HTML_MODE_LEGACY is the behaviour that was used for versions below android N
        // we are using this flag to give a consistent behaviour
        return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
    } else {
        return Html.fromHtml(html);
    }
}

Você pode converter o HTML.FROM_HTML_MODE_LEGACYparâmetro em um parâmetro adicional, se desejar. Isso lhe dá mais controle sobre qual sinalizador usar.

Você pode ler mais sobre os diferentes sinalizadores na documentação da classe Html

Rockney
fonte
2
Qual sinalizador representa o zero?
ban-geoengineering
4
Html.FROM_HTML_MODE_LEGACY
ban-geoengineering
14
ah, à espera de algo como HtmlCompat a aparecer
vanomart
12
Também é útil adicionar um //noinspection deprecationcomentário logo abaixo do elsepara evitar avisos de fiapos.
Ted Hopp
1
Você pode ver o que cada uma dessas bandeiras fazer neste post: medium.com/@yair.kukielka/...
Yair Kukielka
95

Eu tinha muitos desses avisos e sempre uso FROM_HTML_MODE_LEGACY, então criei uma classe auxiliar chamada HtmlCompat contendo o seguinte:

   @SuppressWarnings("deprecation")
   public static Spanned fromHtml(String source) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY);
        } else {
            return Html.fromHtml(source);
        }
    }
k2col
fonte
2
Mesmo efeito como a resposta aceita, mas uma causa de SuppressWarnings anotação
Stoycho Andreev
Você pode dar uma pequena explicação sobre esse modo?
precisa
você poderia fornecer todos HTMLCompact pode estar no hub git ele parece legal
shareef
@shareef eu iria, mas é realmente apenas uma classe de utilitário chato com este método único nele ....
k2col
61

Compare as bandeiras de fromHtml ().

<p style="color: blue;">This is a paragraph with a style</p>

<h4>Heading H4</h4>

<ul>
   <li style="color: yellow;">
      <font color=\'#FF8000\'>li orange element</font>
   </li>
   <li>li #2 element</li>
</ul>

<blockquote>This is a blockquote</blockquote>

Text after blockquote
Text before div

<div>This is a div</div>

Text after div

BANDEIRAS FROM_HTML

Xan
fonte
Você também pode compartilhar HTML de entrada? Isso ajudaria a entender melhor a conversão.
Kalpesh Patel
Vejo que os atributos de estilo não são implementados, existe uma maneira de implementá-los?
Christine
42

Ou você pode usar androidx.core.text.HtmlCompat:

HtmlCompat.fromHtml("<b>HTML</b>", HtmlCompat.FROM_HTML_MODE_LEGACY)

Documentos HtmlCompat

Ondřej Z
fonte
25

Se você tiver sorte o suficiente para desenvolver no Kotlin, basta criar uma função de extensão:

fun String.toSpanned(): Spanned {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return Html.fromHtml(this, Html.FROM_HTML_MODE_LEGACY)
    } else {
        @Suppress("DEPRECATION")
        return Html.fromHtml(this)
    }
}

E é tão bom usá-lo em qualquer lugar:

yourTextView.text = anyString.toSpanned()
Leo Droidcoder
fonte
5
você pode salvar digitações removendo Spannedereturn
Minami
14

fromHtml

Este método foi preterido no nível da API 24 .

Você deve usar FROM_HTML_MODE_LEGACY

Separe os elementos no nível do bloco com linhas em branco (dois caracteres de nova linha) no meio. Esse é o comportamento herdado anterior a N.

Código

if (Build.VERSION.SDK_INT >= 24)
        {
            etOBJ.setText(Html.fromHtml("Intellij \n Amiyo",Html.FROM_HTML_MODE_LEGACY));

         }
 else
        {
           etOBJ.setText(Html.fromHtml("Intellij \n Amiyo"));
        }

Para Kotlin

fun setTextHTML(html: String): Spanned
    {
        val result: Spanned = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
        } else {
            Html.fromHtml(html)
        }
        return result
    }

Ligar

 txt_OBJ.text  = setTextHTML("IIT Amiyo")
IntelliJ Amiya
fonte
Você pode dar uma pequena explicação sobre esse modo?
precisa
se você quiser que o SDK manipule verificações de versão, use: HtmlCompat.fromHtml("textWithHtmlTags", HtmlCompat.FROM_HTML_MODE_LEGACY)
Wajid Ali
8

Do documento oficial:

fromHtml(String)O método foi preterido no nível 24 da API fromHtml(String, int) .

  1. TO_HTML_PARAGRAPH_LINES_CONSECUTIVEOpção para toHtml(Spanned, int): Quebrar linhas consecutivas de texto delimitadas por elementos '\n'internos <p>.

  2. TO_HTML_PARAGRAPH_LINES_INDIVIDUALOpção para toHtml(Spanned, int): quebrar cada linha de texto delimitada por '\n'um <p>ou um <li> elemento.

https://developer.android.com/reference/android/text/Html.html

USKMobility
fonte
8

Se você estiver usando o Kotlin , consegui isso usando uma extensão do Kotlin:

fun TextView.htmlText(text: String){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        setText(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY))
    } else {
        setText(Html.fromHtml(text))
    }
}

Então chame assim:

textView.htmlText(yourHtmlText)
David Jarvis
fonte
5

Apenas para estender a resposta de @Rockney e @ k2col, o código aprimorado pode se parecer com:

@NonNull
public static Spanned fromHtml(@NonNull String html) {
    if (CompatUtils.isApiNonLowerThan(VERSION_CODES.N)) {
        return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
    } else {
        //noinspection deprecation
        return Html.fromHtml(html);
    }
}

Onde CompatUtils.isApiNonLowerThan:

public static boolean isApiNonLowerThan(int versionCode) {
    return Build.VERSION.SDK_INT >= versionCode;
}

A diferença é que não há variável local extra e a depreciação ocorre apenas em else ramificação. Portanto, isso não suprimirá todo método, exceto uma ramificação única.

Pode ajudar quando o Google decidir em algumas versões futuras do Android descontinuar o fromHtml(String source, int flags)método.

jakubbialkowski
fonte
4

Você pode usar

//noinspection deprecation
return Html.fromHtml(source);

suprimir a inspeção apenas para uma única declaração, mas não para todo o método.

Nikolay Tsigouro
fonte
2

A classe de estrutura foi modificada para exigir um sinalizador para informar fromHtml()como processar quebras de linha. Isso foi adicionado ao Nougat e aborda apenas o desafio das incompatibilidades dessa classe nas versões do Android.

Publiquei uma biblioteca de compatibilidade para padronizar e suportar a classe e incluir mais retornos de chamada para elementos e estilo:

https://github.com/Pixplicity/HtmlCompat

Embora seja semelhante à classe Html da estrutura, algumas alterações de assinatura foram necessárias para permitir mais retornos de chamada. Aqui está o exemplo da página do 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);
Paul Lammertsma
fonte
Quando uso sua biblioteca em um aplicativo que usa minSdkVersion 15e targetSdkVersion 23recebo um erro de construção para values-v24.xml : Error:(3) Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Borderless.Colored'.Sua biblioteca é direcionada ao nível 25 da API, obviamente. Como ainda posso usá-lo?
JJD
2

Aqui está a minha solução.

 if (Build.VERSION.SDK_INT >= 24) {
        holder.notificationTitle.setText(Html.fromHtml(notificationSucces.getMessage(), Html.FROM_HTML_MODE_LEGACY));
    } else {
        holder.notificationTitle.setText(Html.fromHtml(notificationSucces.getMessage()));

    }
pavel
fonte
1

basta fazer uma função:

public Spanned fromHtml(String str){
  return Build.VERSION.SDK_INT >= 24 ? Html.fromHtml(str, Html.FROM_HTML_MODE_LEGACY) : Html.fromHtml(str);
}
ROHIT LIEN
fonte
-2

Tente o seguinte para oferecer suporte a tags html básicas, incluindo tags ul ol li. Crie um manipulador de tags, como mostrado abaixo

import org.xml.sax.XMLReader;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.Html.TagHandler;
import android.util.Log;

public class MyTagHandler implements TagHandler {
    boolean first= true;
    String parent=null;
    int index=1;
    @Override
    public void handleTag(boolean opening, String tag, Editable output,
                          XMLReader xmlReader) {

        if(tag.equals("ul")) parent="ul";
        else if(tag.equals("ol")) parent="ol";
        if(tag.equals("li")){
            if(parent.equals("ul")){
                if(first){
                    output.append("\n\t•");
                    first= false;
                }else{
                    first = true;
                }
            }
            else{
                if(first){
                    output.append("\n\t"+index+". ");
                    first= false;
                    index++;
                }else{
                    first = true;
                }
            }
        }
    }
}

Defina o texto em Atividade, como mostrado abaixo

@SuppressWarnings("deprecation")
    public void init(){
        try {
            TextView help = (TextView) findViewById(R.id.help);
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                help.setText(Html.fromHtml(getString(R.string.help_html),Html.FROM_HTML_MODE_LEGACY, null, new MyTagHandler()));
            } else {
                help.setText(Html.fromHtml(getString(R.string.help_html), null, new MyTagHandler()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

E texto html em arquivos de cadeia de recursos como

<! [CDATA [... dados html brutos ...]]>

Bruce
fonte