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.
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:
TextView
incorporée). TextView
utilise lui-même une StaticLayout
en interne . 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();
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.
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.
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.
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