web-dev-qa-db-fra.com

Comment StaticLayout est-il utilisé dans Android?

J'ai besoin de créer ma propre variable TextView pour apprendre StaticLayout à dessiner du texte sur une toile. Ceci est préférable à l’utilisation de Canvas.drawText() directement, du moins le documentation indique. Cependant, la documentation ne donne aucun exemple pour expliquer comment procéder. Il n'y a qu'une vague référence à StaticLayout.Builder étant le moyen le plus récent de le faire.

J'ai trouvé un exemple ici mais il semble un peu daté.

Finalement, j’ai travaillé sur la manière de procéder, j’ajoute donc mon explication ci-dessous.

13
Suragch

StaticLayout ( similaire à DynamicLayout et BoringLayout ) est utilisé pour mettre en forme et dessiner du texte sur une toile. Il est couramment utilisé pour les tâches suivantes:

  • Mesurer la taille d'un texte multiligne après sa mise en forme.
  • Dessiner du texte sur une image bitmap.
  • Création d'une vue personnalisée gérant sa propre disposition de texte (par opposition à la création d'une vue composite avec une TextView incorporée). TextView utilise lui-même une StaticLayouten interne

Mesurer la taille du texte

Une seule ligne

Si vous n'avez qu'une seule ligne de texte, vous pouvez le mesurer avec Paint ou TextPaint

String text = "This is some text."

TextPaint myTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
mTextPaint.setColor(0xFF000000);

float width = mTextPaint.measureText(text);
float height = -mTextPaint.ascent() + mTextPaint.descent();

Multiligne

Cependant, s'il existe un retour à la ligne et que vous avez besoin de la hauteur, il est préférable d'utiliser une variable StaticLayout. Vous fournissez la largeur et vous pouvez ensuite obtenir la hauteur à partir de StaticLayout

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";

TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
myTextPaint.setColor(0xFF000000);

int width = 200;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;

StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding);

float height = myStaticLayout.getHeight(); 

Nouvelle API

Si vous souhaitez utiliser le plus récent StaticLayout.Builder (disponible à partir de l'API 23), vous pouvez obtenir votre mise en page comme suit:

StaticLayout.Builder builder = StaticLayout.Builder.obtain(text, 0, text.length(), myTextPaint, width);
StaticLayout myStaticLayout = builder.build();

Vous pouvez ajouter des paramètres d’ajout en utilisant la notation par points

StaticLayout.Builder builder = StaticLayout.Builder.obtain(text, 0, text.length(), myTextPaint, width)
        .setAlignment(Layout.Alignment.ALIGN_NORMAL)
        .setLineSpacing(spacingMultiplier, spacingAddition)
        .setIncludePad(includePadding)
        .setMaxLines(5);
StaticLayout myStaticLayout = builder.build();

Écrire du texte sur une image

Je pourrai développer cela davantage à l'avenir, mais pour l'instant, voyez cet article pour un exemple de méthode qui utilise StaticLayout et renvoie un bitmap.

Créer une vue de gestion de texte personnalisée

Voici un exemple d’une vue personnalisée utilisant une StaticLayout. Il se comporte comme un simple TextView. Lorsque le texte est trop long pour tenir à l'écran, il passe automatiquement à la ligne et augmente sa hauteur.

enter image description here

Code 

MyView.Java

public class MyView extends View {

    String mText = "This is some text.";
    TextPaint mTextPaint;
    StaticLayout mStaticLayout;

    // use this constructor if creating MyView programmatically
    public MyView(Context context) {
        super(context);
        initLabelView();
    }

    // this constructor is used when created from xml
    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initLabelView();
    }

    private void initLabelView() {
        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
        mTextPaint.setColor(0xFF000000);

        // default to a single line of text
        int width = (int) mTextPaint.measureText(mText);
        mStaticLayout = new StaticLayout(mText, mTextPaint, (int) width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false);

        // New API alternate
        //
        // StaticLayout.Builder builder = StaticLayout.Builder.obtain(mText, 0, mText.length(), mTextPaint, width)
        //        .setAlignment(Layout.Alignment.ALIGN_NORMAL)
        //        .setLineSpacing(1, 0) // multiplier, add
        //        .setIncludePad(false);
        // mStaticLayout = builder.build();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Tell the parent layout how big this view would like to be
        // but still respect any requirements (measure specs) that are passed down.

        // determine the width
        int width;
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthRequirement = MeasureSpec.getSize(widthMeasureSpec);
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthRequirement;
        } else {
            width = mStaticLayout.getWidth() + getPaddingLeft() + getPaddingRight();
            if (widthMode == MeasureSpec.AT_MOST) {
                if (width > widthRequirement) {
                    width = widthRequirement;
                    // too long for a single line so relayout as multiline
                    mStaticLayout = new StaticLayout(mText, mTextPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false);
                }
            }
        }

        // determine the height
        int height;
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightRequirement = MeasureSpec.getSize(heightMeasureSpec);
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightRequirement;
        } else {
            height = mStaticLayout.getHeight() + getPaddingTop() + getPaddingBottom();
            if (heightMode == MeasureSpec.AT_MOST) {
                height = Math.min(height, heightRequirement);
            }
        }

        // Required call: set width and height
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // do as little as possible inside onDraw to improve performance

        // draw the text on the canvas after adjusting for padding
        canvas.save();
        canvas.translate(getPaddingLeft(), getPaddingTop());
        mStaticLayout.draw(canvas);
        canvas.restore();
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/activity_main"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:padding="@dimen/activity_vertical_margin"
    tools:context="com.example.layoutpractice.MainActivity">

    <com.example.layoutpractice.MyView
        Android:layout_centerHorizontal="true"
        Android:background="@color/colorAccent"
        Android:padding="10dp"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"/>
</RelativeLayout>

Remarques

  • This , this et this ont été utiles pour apprendre à créer une vue de traitement de texte personnalisée.

  • Voir Création d'une classe de vue si vous souhaitez ajouter des attributs personnalisés pouvant être définis à partir de code ou xml.

64
Suragch

Voici mon explication pour dessiner un texte multiligne sur une toile.

Déclarez l'objet Paint. Utilisez TextPaint qui est une extension de Paint.

TextPaint textPaint;

Initialiser l'objet Paint. Définissez votre propre couleur, taille, etc.

textPaint = new TextPaint();
textPaint.setAntiAlias(true);
textPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
textPaint.setColor(Color.YELLOW);

Ajouter la fonction getTextHeight

private float getTextHeight(String text, Paint paint) {
    Rect rect = new Rect();
    Paint.getTextBounds(text, 0, text.length(), rect);
    return rect.height();
}

dans votre fonction onDraw, mettez les lignes suivantes comme ceci

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

    String text = "This is a lengthy text. We have to render this properly. If layout mess users review will mess. Is that so ? ";

    Rect bounds = canvas.getClipBounds();

    StaticLayout sl = new StaticLayout(text, textPaint, bounds.width(),
            Layout.Alignment.ALIGN_CENTER, 1, 1, true);

    canvas.save();

    //calculate X and Y coordinates - In this case we want to draw the text in the
    //center of canvas so we calculate
    //text height and number of lines to move Y coordinate to center.
    float textHeight = getTextHeight(text, textPaint);
    int numberOfTextLines = sl.getLineCount();
    float textYCoordinate = bounds.exactCenterY() -
            ((numberOfTextLines * textHeight) / 2);

    //text will be drawn from left
    float textXCoordinate = bounds.left;

    canvas.translate(textXCoordinate, textYCoordinate);

    //draws static layout on canvas
    sl.draw(canvas);
    canvas.restore();
}

La courtoisie va à Le post de KOC

0
Nalin