48 votes

Android : Comment utiliser le Html.TagHandler ?

J'essaie de créer une application Android pour un forum de discussion. Pour afficher le format html du contenu des messages, j'ai choisi le TextView et la méthode Html.fromHtml(). Malheureusement, cela ne couvre que quelques balises html. Les balises inconnues sont gérées par une classe qui implémente TagHandler et doit être générée par moi-même.

J'ai beaucoup cherché sur Internet et je n'ai pas trouvé d'exemple de la façon dont cette classe devrait fonctionner. L

Il est appelé de la manière suivante :

public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {

Les deux premiers arguments sont bons. Je suppose que je dois modifier la sortie en utilisant output.append(). Mais comment joindre quelque chose de souligné à cet endroit ?

103voto

janoliver Points 2595

Alors, j'ai finalement trouvé tout seul.

public class MyHtmlTagHandler implements TagHandler {

    public void handleTag(boolean opening, String tag, Editable output,
            XMLReader xmlReader) {
        if(tag.equalsIgnoreCase("strike") || tag.equals("s")) {
            processStrike(opening, output);
        }
    }

    private void processStrike(boolean opening, Editable output) {
        int len = output.length();
        if(opening) {
            output.setSpan(new StrikethroughSpan(), len, len, Spannable.SPAN_MARK_MARK);
        } else {
            Object obj = getLast(output, StrikethroughSpan.class);
            int where = output.getSpanStart(obj);

            output.removeSpan(obj);

            if (where != len) {
                output.setSpan(new StrikethroughSpan(), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }

    private Object getLast(Editable text, Class kind) {
        Object[] objs = text.getSpans(0, text.length(), kind);

        if (objs.length == 0) {
            return null;
        } else {
            for(int i = objs.length;i>0;i--) {
                if(text.getSpanFlags(objs[i-1]) == Spannable.SPAN_MARK_MARK) {
                    return objs[i-1];
                }
            }
            return null;
        }
    }

}

Et pour votre TextView, vous pouvez l'appeler comme ceci :

myTextView.setText (Html.fromHtml(text.toString(), null, new MyHtmlTagHandler()));

si quelqu'un en a besoin.

Cheers

0 votes

Joli. Bien que je ne comprenne pas encore, les détails peuvent être déterrés plus tard.

1 votes

Je pense que j'ai juste utilisé la documentation d'Android et l'ai assemblé moi-même en quelque sorte. Je ne trouvais pas grand-chose sur ce sujet à l'époque, mais c'est peut-être plus facile maintenant.

0 votes

Parce que nous avons affaire à une balise de fermeture.

13voto

Binghammer Points 1592

Cette solution se trouve dans le Sdk Android

Sur android.text.html . Lignes 596 - 626. Copié/collé

private static <T> Object getLast(Spanned text, Class<T> kind) {
    /*
     * This knows that the last returned object from getSpans()
     * will be the most recently added.
     */
    Object[] objs = text.getSpans(0, text.length(), kind);

    if (objs.length == 0) {
        return null;
    } else {
        return objs[objs.length - 1];
    }
}

private static void start(SpannableStringBuilder text, Object mark) {
    int len = text.length();
    text.setSpan(mark, len, len, Spannable.SPAN_MARK_MARK);
}

private static <T> void end(SpannableStringBuilder text, Class<T> kind,
                        Object repl) {
    int len = text.length();
    Object obj = getLast(text, kind);
    int where = text.getSpanStart(obj);

    text.removeSpan(obj);

    if (where != len) {
        text.setSpan(repl, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }
}

Pour l'utiliser, remplacez TagHandler comme suit :

public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {

    if(tag.equalsIgnoreCase("strike") || tag.equals("s")) {

        if(opening){
            start((SpannableStringBuilder) output, new Strike();

        } else {
            end((SpannableStringBuilder) output, Strike.class, new StrikethroughSpan());
        }
    }       
}

/* 
 * Notice this class. It doesn't really do anything when it spans over the text. 
 * The reason is we just need to distinguish what needs to be spanned, then on our closing
 * tag, we will apply the spannable. For each of your different spannables you implement, just 
 * create a class here. 
 */
 private static class Strike{}

5voto

Dandre Allison Points 2434

J'ai pris janoliver de réponse et est venu avec ma version qui tente de soutenir plus d'options

        String text = ""; // HTML text to convert
        // Preprocessing phase to set up for HTML.fromHtml(...)
        text = text.replaceAll("<span style=\"(?:color: (#[a-fA-F\\d]{6})?; )?(?:font-family: (.*?); )?(?:font-size: (.*?);)? ?\">(.*?)</span>",
                               "<font color=\"$1\" face=\"$2\" size=\"$3\">$4</font>");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )face=\"'(.*?)', .*?\"", "face=\"$1\"");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"xx-small\"", "$1size=\"1\"");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"x-small\"", "$1size=\"2\"");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"small\"", "$1size=\"3\"");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"medium\"", "$1size=\"4\"");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"large\"", "$1size=\"5\"");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"x-large\"", "$1size=\"6\"");
        text = text.replaceAll("(?<=<font color=\"#[a-fA-F0-9]{6}\" )(face=\".*?\" )size=\"xx-large\"", "$1size=\"7\"");
        text = text.replaceAll("<strong>(.*?)</strong>", "<_em>$1</_em>");  // we use strong for bold-face
        text = text.replaceAll("<em>(.*?)</em>", "<strong>$1</strong>");    // and em for italics
        text = text.replaceAll("<_em>(.*?)</_em>", "<em>$1</em>");          // but Android uses em for bold-face
        text = text.replaceAll("<span style=\"background-color: #([a-fA-F0-9]{6}).*?>(.*?)</span>", "<_$1>$2</_$1>");
        text_view.setText(Html.fromHtml(text, null, new Html.TagHandler() {
            private List<Object> _format_stack = new LinkedList<Object>();

            @Override
            public void handleTag(boolean open_tag, String tag, Editable output, XMLReader _) {
                if (tag.startsWith("ul"))
                    processBullet(open_tag, output);
                else if (tag.matches(".[a-fA-F0-9]{6}"))
                    processBackgroundColor(open_tag, output, tag.substring(1));
            }

            private void processBullet(boolean open_tag, Editable output) {
                final int length = output.length();
                if (open_tag) {
                    final Object format = new BulletSpan(BulletSpan.STANDARD_GAP_WIDTH);
                    _format_stack.add(format);
                    output.setSpan(format, length, length, Spanned.SPAN_MARK_MARK);
                } else {
                    applySpan(output, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }

            private void processBackgroundColor(boolean open_tag, Editable output, String color) {
                final int length = output.length();
                if (open_tag) {
                    final Object format = new BackgroundColorSpan(Color.parseColor('#' + color));
                    _format_stack.add(format);
                    output.setSpan(format, length, length, Spanned.SPAN_MARK_MARK);
                } else {
                    applySpan(output, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                }
            }

            private Object getLast(Editable text, Class kind) {
                @SuppressWarnings("unchecked")
                final Object[] spans = text.getSpans(0, text.length(), kind);

                if (spans.length != 0)
                    for (int i = spans.length; i > 0; i--)
                        if (text.getSpanFlags(spans[i-1]) == Spannable.SPAN_MARK_MARK)
                            return spans[i-1];

                return null;
            }

            private void applySpan(Editable output, int length, int flags) {
                if (_format_stack.isEmpty()) return;

                final Object format = _format_stack.remove(0);
                final Object span = getLast(output, format.getClass());
                final int where = output.getSpanStart(span);

                output.removeSpan(span);

                if (where != length)
                    output.setSpan(format, where, length, flags);
            }
        }));

Cela ne semble pour obtenir les balles, la couleur de premier plan, et la couleur d'arrière-plan. Il peut travailler pour la police, mais vous pourriez avoir besoin de fournir les polices comme il ne semble pas que Android prend en charge les polices autres que le Droid/Roboto.

C'est plus une preuve de concept, vous pourriez probablement vouloir convertir les regex en String de traitement, depuis la regex ne prend pas en charge combinant le prétraitement de toute façon, cela prend beaucoup de passages sur l' String. Ce ne pas sembler obtenir la taille de la police pour changer, j'ai essayé de le définir comme "16sp", "moyen" ou "4", sans voir les changements. Si quelqu'un a eu les tailles de travail, l'esprit de partage?

Actuellement, je voudrais être en mesure d'ajouter numérotés et liste ordonnée de soutien à présent, c'est à dire

  1. article
  2. article
  3. article

NOTE: Pour les personnes qui commencent à tout cela, il semble que le "tag" qui est donnée à l' handleTag(...) c'est juste le nom de la balise (comme le "span"), et ne contiennent pas des attributs affectés dans la balise (comme si vous aviez "), vous pouvez voir mon échappatoire autour de ce pour la couleur d'arrière-plan.

0 votes

Aung Pyae vous avez laissé une modification avec une question, je ne peux pas répondre à la raison pour laquelle il vous donne une erreur avec les balises de paragraphe, à moins que l'entrée soit incorrecte (bien que je pensais que Html.fromHtml(..) utilisait TagSoup pour gérer le mauvais HTML). Mon code ne devrait pas du tout traiter les balises <p>, je laissais simplement Html.fromHtml(..) s'en occuper. Je ne peux pas dire qu'il s'agit d'une implémentation complète, si votre entrée fait quelque chose d'intéressant, il se peut que vous perdiez une balise dans le prétraitement quelque part.

0 votes

Si vous recherchez toujours la résolution ol/ul, ajoutez un champ pour le parent, lorsque vous trouvez la balise ul ou ol, définissez-le au nom de la balise, puis lorsque vous obtenez le li, vous pouvez mettre le bullit ou un nombre, que vous pourriez également enregistrer dans une valeur de champ. De cette façon, vous serez couvert.

0 votes

J'ai essayé d'utiliser votre code pour ul et li. Je ne vois qu'un seul bulletpoint, et tous les li sont derrière lui sur la même ligne. Est-ce que quelqu'un a déjà résolu ce problème ?

3voto

Roberto Prato Points 91

Nous avons développé en interne cette bibliothèque https://github.com/square1-io/rich-text-Android depuis un certain temps déjà et nous l'utilisons dans un certain nombre d'applications d'actualités à fort contenu.

La bibliothèque peut analyser les balises html les plus courantes, y compris la vidéo et l'img, avec téléchargement à distance des images. Une vue personnalisée, RichTextView, peut ensuite être utilisée en remplacement de TextView pour afficher le contenu analysé.

Nous l'avons rendu public récemment, la documentation est donc encore incomplète, mais l'exemple fourni devrait être facile à suivre pour voir si cela correspond à vos besoins.

1voto

JosieH Points 85

Bien que je puisse le voir dans l'API Html.java que style et text-align devraient être utilisables avec les balises <p> , <div> etc. Je ne parviens pas à le faire fonctionner avec <p align="center"> o <p style="text-align: center"> et de nombreuses autres variantes. Ne pouvant pas faire cet alignement central du texte, et d'autres styles comme la taille de la police, plusieurs visages de police à partir de mes fichiers ttf, la couleur de fond, j'ai fait mon propre htmlTextView basé sur TextView mais avec ma propre classe tagHandler. À part une ou deux irritations mineures, la plupart des balises fonctionnent bien, sauf mes balises d'alignement personnalisées, gauche , centre , droite ne fonctionnent que dans des conditions particulières (que je ne comprends pas), sinon. ils ne fonctionnent pas ou plantent l'application ! Voici ma poignée de balises d'alignement. Il a la même structure que tous les autres gestionnaires de balises personnalisés mais se comporte vraiment bizarrement ! La forme de base de mes gestionnaires de balises est la même et ne sont pas conçues par moi ! J'ai trouvé le modèle taghandler après de nombreuses heures de recherche sur le web. Je suis reconnaissant à celui qui l'a posté, mais ma mémoire et mes capacités d'organisation sont telles que je ne peux pas vraiment me souvenir de qui ou d'où, donc si vous reconnaissez ce code comme étant le vôtre, faites-le moi savoir. Le seul lien (qui est ici) que j'ai est dans mon code : stackoverflow : Android : Comment utiliser le Html.TagHandler ?

  private void ProcessAlignment(Layout.Alignment align, boolean opening, Editable output) {
    int len = output.length();
    if (opening) {
        output.setSpan(new AlignmentSpan.Standard(align), len, len, Spannable.SPAN_MARK_MARK);
    } else {
        Object obj = getLast(output, AlignmentSpan.Standard.class);
        int where = output.getSpanStart(obj);

        output.removeSpan(obj);

        if (where != len) {
            output.setSpan(new AlignmentSpan.Standard(align), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }
}

Je pense que le problème est que la balise de fin n'est pas connectée à la bonne balise de début.

private Object getLast(Editable text, Class kind) {
            Object[] objs = text.getSpans(0, text.length(), kind);

            if (objs.length == 0) {
                return null;
            } else {
                for (int i = objs.length - 1; i >= 0; --i) {
                    if (text.getSpanFlags(objs[i]) == Spannable.SPAN_MARK_MARK) {
                        return objs[i];
                    }
                }
                return null;
            }
        }

C'est la classe totale et quelque chose ne va pas. Le plus grand composant est ma compréhension ! Peut-être que quelqu'un peut m'aider à mieux comprendre...

public class htmlTextView extends AppCompatTextView {
static Typeface mLogo;
static Typeface mGAMZ;
static Typeface mChalk;
static Typeface mSouvenir;
int GS_PAINTFLAGS = FILTER_BITMAP_FLAG | ANTI_ALIAS_FLAG | SUBPIXEL_TEXT_FLAG | HINTING_ON;

public htmlTextView(Context context) {
    super(context);
    initialise();
}

public htmlTextView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    initialise();
}

public htmlTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initialise();
}

private void initialise() {
    mLogo = Typeface.createFromAsset(theAssetManager, "fonts/logo.ttf");
    mGAMZ = Typeface.createFromAsset(theAssetManager, "fonts/GAMZ One.ttf");
    mChalk = Typeface.createFromAsset(theAssetManager, "fonts/swapfix.ttf");
    mSouvenir = Typeface.createFromAsset(theAssetManager, "fonts/Souvenir Regular.ttf");

    setPaintFlags(GS_PAINTFLAGS);
}

public void setDefaultTypefaceSouvenir() {
    setTypeface(mSouvenir);
}

public void setDefaultTypefaceGAMZ() {
    setTypeface(mGAMZ);
}

public void setDefaultTypefaceChalk() {
    setTypeface(mChalk);
}

/*public myTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}*/

public void setHTML(String htmltext) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Nougat API 24
        setText(Html.fromHtml(htmltext, Html.FROM_HTML_MODE_LEGACY,
                null, new TypefaceTagHandler()));
    } else {
        setText(Html.fromHtml(htmltext, null, new TypefaceTagHandler()));
    }
}

@Override
protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
}

@Override
public Bitmap getDrawingCache(boolean autoScale) {
    return super.getDrawingCache(autoScale);
}

@Override
public void draw(Canvas canvas) {
    super.draw(canvas);
}

// http://stackoverflow.com/questions/4044509/android-how-to-use-the-html-taghandler
private static class TypefaceTagHandler implements Html.TagHandler {

    private void ProcessAlignment(Layout.Alignment align, boolean opening, Editable output) {
        int len = output.length();
        if (opening) {
            output.setSpan(new AlignmentSpan.Standard(align), len, len, Spannable.SPAN_MARK_MARK);
        } else {
            Object obj = getLast(output, AlignmentSpan.Standard.class);
            int where = output.getSpanStart(obj);

            output.removeSpan(obj);

            if (where != len) {
                output.setSpan(new AlignmentSpan.Standard(align), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }

    private void ProcessTypefaceTag(Typeface tf, boolean opening, Editable output) {
        int len = output.length();
        if (opening) {
            output.setSpan(new CustomTypefaceSpan("", tf), len, len,
                    Spannable.SPAN_MARK_MARK);
        } else {
            Object obj = getLast(output, CustomTypefaceSpan.class);
            int where = output.getSpanStart(obj);

            output.removeSpan(obj);

            if (where != len) {
                output.setSpan(new CustomTypefaceSpan("", tf), where, len,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }

    private void ProcessScaleTag(float scalefactor, boolean opening, Editable output) {
        int len = output.length();
        if (opening) {
            output.setSpan(new RelativeSizeSpan(scalefactor), len, len,
                    Spannable.SPAN_MARK_MARK);
        } else {
            Object obj = getLast(output, RelativeSizeSpan.class);
            int where = output.getSpanStart(obj);

            output.removeSpan(obj);

            if (where != len) {
                output.setSpan(new RelativeSizeSpan(scalefactor), where, len,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }

    private void ProcessBox(int colour, boolean opening, Editable output) {
        int len = output.length();
        if (opening) {
            output.setSpan(new BackgroundColorSpan(colour), len, len,
                    Spannable.SPAN_MARK_MARK);
        } else {
            Object obj = getLast(output, BackgroundColorSpan.class);
            int where = output.getSpanStart(obj);

            output.removeSpan(obj);

            if (where != len) {
                output.setSpan(new BackgroundColorSpan(colour), where, len,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }

    private void ProcessTextColour(int colour, boolean opening, Editable output) {
        int len = output.length();
        if (opening) {
            output.setSpan(new ForegroundColorSpan(colour), len, len,
                    Spannable.SPAN_MARK_MARK);
        } else {
            Object obj = getLast(output, ForegroundColorSpan.class);
            int where = output.getSpanStart(obj);

            output.removeSpan(obj);

            if (where != len) {
                output.setSpan(new ForegroundColorSpan(colour), where, len,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }

    final HashMap<String, String> attributes = new HashMap<>();

    @Override
    public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
        String Attr = "";
        //if (!opening) attributes.clear();
        processAttributes(xmlReader);

        if ("txt".equalsIgnoreCase(tag)) {
            Attr = attributes.get("clr");
            System.out.println("clr Attr: " + Attr + ", opening: " + opening);
            if (Attr == null || Attr.isEmpty()
                    || "black".equalsIgnoreCase(Attr)
                    || Attr.charAt(0) == 'k') {
                System.out.println("did black, opening: " + opening);
                ProcessTextColour(parseColor("#000000"), opening, output);
            } else {
                if (Attr.equalsIgnoreCase("g")) {
                    ProcessTextColour(parseColor("#b2b3b3"), opening, output);
                } else {
                    System.out.println("did colour, opening: " + opening);
                    ProcessTextColour(parseColor(Attr), opening, output);
                }
            }
            return;
        }

        if ("box".equalsIgnoreCase(tag)) {
            ProcessBox(parseColor("#d7d6d5"), opening, output);
            return;
        }

        if ("scl".equalsIgnoreCase(tag)) {
            Attr = attributes.get("fac");
            System.out.println("scl Attr: " + Attr);
            if (Attr != null && !Attr.isEmpty()) {
                ProcessScaleTag(parseFloat(Attr), opening, output);
            }
            return;
        }

        if ("left".equalsIgnoreCase(tag)) {
            ProcessAlignment(Layout.Alignment.ALIGN_NORMAL, opening, output);
            return;
        }

        if ("centre".equalsIgnoreCase(tag)) {
            ProcessAlignment(Layout.Alignment.ALIGN_CENTER, opening, output);
            return;
        }

        if ("right".equalsIgnoreCase(tag)) {
            ProcessAlignment(Layout.Alignment.ALIGN_OPPOSITE, opening, output);
            return;
        }

        if ("logo".equalsIgnoreCase(tag)) {
            ProcessTypefaceTag(mLogo, opening, output);
            return;
        }
        if ("gamz".equalsIgnoreCase(tag)) {
            ProcessTypefaceTag(mGAMZ, opening, output);
            return;
        }

        if ("chalk".equalsIgnoreCase(tag)) {
            System.out.println("chalk " + (opening ? "opening" : "closing"));
            ProcessTypefaceTag(mChalk, opening, output);
            return;
        }
    }

    private Object getLast(Editable text, Class kind) {
        Object[] objs = text.getSpans(0, text.length(), kind);

        if (objs.length == 0) {
            return null;
        } else {
            for (int i = objs.length - 1; i >= 0; --i) {
                if (text.getSpanFlags(objs[i]) == Spannable.SPAN_MARK_MARK) {
                    return objs[i];
                }
            }
            return null;
        }
    }

    private void processAttributes(final XMLReader xmlReader) {
        try {
            Field elementField = xmlReader.getClass().getDeclaredField("theNewElement");
            elementField.setAccessible(true);
            Object element = elementField.get(xmlReader);
            Field attsField = element.getClass().getDeclaredField("theAtts");
            attsField.setAccessible(true);
            Object atts = attsField.get(element);
            Field dataField = atts.getClass().getDeclaredField("data");
            dataField.setAccessible(true);
            String[] data = (String[])dataField.get(atts);
            Field lengthField = atts.getClass().getDeclaredField("length");
            lengthField.setAccessible(true);
            int len = (Integer)lengthField.get(atts);

            /**
             * MSH: Look for supported attributes and add to hash map.
             * This is as tight as things can get :)
             * The data index is "just" where the keys and values are stored.
             */
            for(int i = 0; i < len; i++)
                attributes.put(data[i * 5 + 1], data[i * 5 + 4]);
        }
        catch (Exception e) {
            Log.d(TAG, "Exception: " + e);
        }
    }

}

private static class CustomTypefaceSpan extends TypefaceSpan {
    private final Typeface newType;

    public CustomTypefaceSpan(String family, Typeface type) {
        super(family);
        newType = type;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        applyCustomTypeFace(ds, newType);
    }

    @Override
    public void updateMeasureState(TextPaint paint) {
        applyCustomTypeFace(paint, newType);
    }

    private void applyCustomTypeFace(Paint paint, Typeface tf) {
        int oldStyle;
        Typeface old = paint.getTypeface();
        if (old == null) {
            oldStyle = 0;
        } else {
            oldStyle = old.getStyle();
        }

        int fake = oldStyle & ~tf.getStyle();
        if ((fake & Typeface.BOLD) != 0) {
            paint.setFakeBoldText(true);
        }

        if ((fake & Typeface.ITALIC) != 0) {
            paint.setTextSkewX(-0.25f);
        }
        paint.setTypeface(tf);
    }
}

}

Le htmlTextView est créé à partir de l'activité avec :

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    theAssetManager = getAssets();
    htmlTextView tv = new htmlTextView(this);
    tv.setDefaultTypefaceSouvenir();
    tv.setTextColor(BLACK);
    tv.setBackgroundColor(0xfff0f0f0);
    tv.setPadding(4, 4, 4, 4);
    tv.setTextSize(30);
    tv.setMovementMethod(new ScrollingMovementMethod());
    tv.setHTML(getString(R.string.htmljumblies));
    //tv.setHTML(getString(R.string.htmltest));
    RelativeLayout rl = (RelativeLayout) findViewById(R.id.rl);
    rl.addView(tv);
}

et htmljumblies est défini dans strings.xml comme ci-dessous. Cette version particulière fera planter l'application mais si la première version de <centre> , </centre> sont supprimées des lignes 7 et 9, Les Jumblies apparaîtront centralisés ? Confusion et frustration ! Gardez-les et supprimez les <centre> , </centre> balises d'enveloppement Les Jumblies et rien ne se passe. La ligne de l'en-tête n'est pas alignée au centre !

    <string name="htmljumblies">
    <![CDATA[&DoubleLongRightArrow;<logo><scl fac="1.1"><font color="#e5053a">GAMZ</font></scl></logo>
        <chalk><scl fac="1.8"> SWAP </scl></chalk>
        <scl fac="1.00">Set <b>1</b>, Game <b>1</b></scl>
        <br>
        <centre>
        <gamz><font color="#e5053a"><scl fac="1.50">a</scl></font><scl fac="0.90">(9)</scl></gamz>, <gamz><font color="#00a3dd"><scl fac="1.50">e</scl></font><scl fac="0.90">(8)</scl></gamz>, <gamz><font color="#fba311"><scl fac="1.50">i</scl></font><scl fac="0.90">(8)</scl></gamz>, <gamz><font color="#bc5e1e"><scl fac="1.50">o</scl></font><scl fac="0.90">(8)</scl></gamz>, <gamz><font color="#bf30b5"><scl fac="1.50">u</scl></font><scl fac="0.90">(9)</scl></gamz>
        </centre>
        <br>
        This is an example of my custom <b>htmlTextView</b> drawn from HTML format
        text with custom tags to use custom fonts, colouring typeface sizing and highlight boxes.
        The default font is <b><i>Souvenir</i></b>, but 3 other fonts are used:<br>
        The <font color="#e5053a"><b><logo><scl fac="1.1">GAMZ</scl></logo></b></font>
        <font color="#000080"><gamz><scl fac="0.8"><box>letter</box>
        <box>fonts</box><sc></gamz></font>
        and <chalk><scl fac="1.8">swapfix</scl></chalk>, essentially
        <chalk><scl fac="0.9">Staccato 555</scl></chalk>,
        as used in the words <chalk><scl fac="1.2">SWAP</scl></chalk> and
        <chalk><scl fac="1.2">FIX</scl></chalk>
        on the <font color="#e5053a"><b><logo><scl fac="1.1">GAMZ</scl></logo></b></font>
        boxes.
        <br>
        <centre>
        <scl fac="2"><box><b> <u>The Jumblies</u> </b></box></scl><br>
        <font color="#0000ff">
        They went to sea in a Sieve, they did,<br>
        In a Sieve they went to sea:<br>
        In spite of all their friends could say,<br>
        On a winter\'s morn, on a stormy day,<br>
        In a Sieve they went to sea!<br>
        And when the Sieve turned round and round,<br>
        And every one cried, \'You\'ll all be drowned!\'<br>
        They called aloud, \'Our Sieve ain\'t big,<br>
        But we don\'t care a button! we don\'t care a fig!<br>
        In a Sieve we\'ll go to sea!\'<br>
        Far and few, far and few,<br>
        Are the lands where the Jumblies live;<br>
        Their heads are green, and their hands are blue,<br>
        And they went to sea in a Sieve.<br>
        <br>
        They sailed away in a Sieve, they did,<br>
        In a Sieve they sailed so fast,<br>
        With only a beautiful pea-green veil<br>
        Tied with a riband by way of a sail,<br>
        To a small tobacco-pipe mast;<br>
        And every one said, who saw them go,<br>
        \'O won\'t they be soon upset, you know!<br>
        For the sky is dark, and the voyage is long,<br>
        And happen what may, it\'s extremely wrong<br>
        In a Sieve to sail so fast!\'<br>
        Far and few, far and few,<br>
        Are the lands where the Jumblies live;<br>
        Their heads are green, and their hands are blue,<br>
        And they went to sea in a Sieve.<br>
        <br>
        The water it soon came in, it did,<br>
        The water it soon came in;<br>
        So to keep them dry, they wrapped their feet<br>
        In a pinky paper all folded neat,<br>
        And they fastened it down with a pin.<br>
        And they passed the night in a crockery-jar,<br>
        And each of them said, \'How wise we are!<br>
        Though the sky be dark, and the voyage be long,<br>
        Yet we never can think we were rash or wrong,<br>
        While round in our Sieve we spin!\'<br>
        Far and few, far and few,<br>
        Are the lands where the Jumblies live;<br>
        Their heads are green, and their hands are blue,<br>
        And they went to sea in a Sieve.<br>
        <br>
        And all night long they sailed away;<br>
        And when the sun went down,<br>
        They whistled and warbled a moony song<br>
        To the echoing sound of a coppery gong,<br>
        In the shade of the mountains brown.<br>
        \'O Timballo! How happy we are,<br>
        When we live in a Sieve and a crockery-jar,<br>
        And all night long in the moonlight pale,<br>
        We sail away with a pea-green sail,<br>
        In the shade of the mountains brown!\'<br>
        Far and few, far and few,<br>
        Are the lands where the Jumblies live;<br>
        Their heads are green, and their hands are blue,<br>
        And they went to sea in a Sieve.<br>
        <br>
        They sailed to the Western Sea, they did,<br>
        To a land all covered with trees,<br>
        And they bought an Owl, and a useful Cart,<br>
        And a pound of Rice, and a Cranberry Tart,<br>
        And a hive of silvery Bees.<br>
        And they bought a Pig, and some green Jack-daws,<br>
        And a lovely Monkey with lollipop paws,<br>
        And forty bottles of Ring-Bo-Ree,<br>
        And no end of Stilton Cheese.<br>
        Far and few, far and few,<br>
        Are the lands where the Jumblies live;<br>
        Their heads are green, and their hands are blue,<br>
        And they went to sea in a Sieve.<br>
        <br>
        And in twenty years they all came back,<br>
        In twenty years or more,<br>
        And every one said, \'How tall they\'ve grown!<br>
        For they\'ve been to the Lakes, and the Torrible Zone,<br>
        And the hills of the Chankly Bore!\'<br>
        And they drank their health, and gave them a feast<br>
        Of dumplings made of beautiful yeast;<br>
        And every one said, \'If we only live,<br>
        We too will go to sea in a Sieve,---<br>
        To the hills of the Chankly Bore!\'<br>
        Far and few, far and few,<br>
        Are the lands where the Jumblies live;<br>
        Their heads are green, and their hands are blue,<br>
        And they went to sea in a Sieve.</centre></font>
    ]]>
</string>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X