Une question, espérons-le, rapide, mais je n'arrive pas à trouver d'exemples ... J'aimerais écrire un texte multiligne dans une variable View
personnalisée via une Canvas
, et dans onDraw()
, j'ai:
...
String text = "This is\nmulti-line\ntext";
canvas.drawText(text, 100, 100, mTextPaint);
...
J'espérais que cela entraînerait des sauts de ligne, mais je vois plutôt des caractères cryptés où le \n
serait.
Tous les pointeurs appréciés.
Paul
Malheureusement, Android ne sait pas ce que \n
est. Ce que vous devez faire est de supprimer le \n
puis de décaler le Y pour obtenir votre texte sur la ligne suivante. Donc, quelque chose comme ça:
canvas.drawText("This is", 100, 100, mTextPaint);
canvas.drawText("multi-line", 100, 150, mTextPaint);
canvas.drawText("text", 100, 200, mTextPaint);
J'ai trouvé un autre moyen d'utiliser des dispositions statiques. Le code est là pour que quiconque se réfère:
TextPaint mTextPaint=new TextPaint();
StaticLayout mTextLayout = new StaticLayout(mText, mTextPaint, canvas.getWidth(), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
canvas.save();
// calculate x and y position where your text will be placed
textX = ...
textY = ...
canvas.translate(textX, textY);
mTextLayout.draw(canvas);
canvas.restore();
Il suffit de parcourir chaque ligne:
int x = 100, y = 100;
for (String line: text.split("\n")) {
canvas.drawText(line, x, y, mTextPaint);
y += mTextPaint.descent() - mTextPaint.ascent();
}
Ceci est ma solution qui est basée sur la réponse de @ Dave (merci btw ;-))
import Android.graphics.Canvas;
import Android.graphics.Paint;
public class mdCanvas
{
private Canvas m_canvas;
public mdCanvas(Canvas canvas)
{
m_canvas = canvas;
}
public void drawMultiline(String str, int x, int y, Paint paint)
{
for (String line: str.split("\n"))
{
m_canvas.drawText(line, x, y, Paint);
y += -Paint.ascent() + Paint.descent();
}
}
}
J'ai essayé d'hériter de Canvas, mais cela ne vous laisse pas vraiment. C'est donc un cours intermédiaire!
Je dois ajouter ici ma version qui prend en compte STROKE WIDTH.
void drawMultiLineText(String str, float x, float y, Paint paint, Canvas canvas) {
String[] lines = str.split("\n");
float txtSize = -Paint.ascent() + Paint.descent();
if (Paint.getStyle() == Style.FILL_AND_STROKE || Paint.getStyle() == Style.STROKE){
txtSize += Paint.getStrokeWidth(); //add stroke width to the text size
}
float lineSpace = txtSize * 0.2f; //default line spacing
for (int i = 0; i < lines.length; ++i) {
canvas.drawText(lines[i], x, y + (txtSize + lineSpace) * i, Paint);
}
}
J'ai écrit l'exemple complet
couleurs.xml
<color name="transparentBlack">#64000000</color>
Classe Java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.amit);
ImageView imageView = (ImageView)findViewById(R.id.imageView);
imageView.setImageBitmap(drawTextToBitmap(this, bm, "Name: Kolala\nDate: Dec 23 2016 12:47 PM, \nLocation: 440 Banquets & Restaurents"));
}
public Bitmap drawTextToBitmap(Context gContext,
Bitmap bitmap,
String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Android.graphics.Bitmap.Config bitmapConfig =
bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = Android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
Paint.setColor(Color.WHITE);
// text size in pixels
Paint.setTextSize((int) (25 * scale));
// text shadow
Paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// draw text to the Canvas center
Rect bounds = new Rect();
int noOfLines = 0;
for (String line: gText.split("\n")) {
noOfLines++;
}
Paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = 20;
int y = (bitmap.getHeight() - bounds.height()*noOfLines);
Paint mPaint = new Paint();
mPaint.setColor(getResources().getColor(R.color.transparentBlack));
int left = 0;
int top = (bitmap.getHeight() - bounds.height()*(noOfLines+1));
int right = bitmap.getWidth();
int bottom = bitmap.getHeight();
canvas.drawRect(left, top, right, bottom, mPaint);
for (String line: gText.split("\n")) {
canvas.drawText(line, x, y, Paint);
y += Paint.descent() - Paint.ascent();
}
return bitmap;
}
}
Oui. Utilisez canvas.getFontSpacing()
comme incrément. Je l'ai essayé moi-même par curiosité et cela fonctionne pour toutes les tailles de police.
essaye ça
Paint paint1 = new Paint();
Paint1.setStyle(Paint.Style.FILL);
Paint1.setAntiAlias(true);
Paint1.setColor(Color.BLACK);
Paint1.setTextSize(15);
TextView tv = new TextView(context);
tv.setTextColor(Color.BLACK);
LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
llp.setMargins(5, 2, 0, 0); // llp.setMargins(left, top, right, bottom);
tv.setLayoutParams(llp);
tv.setTextSize(10);
String text="this is good to see you , i am the king of the team";
tv.setText(text);
tv.setDrawingCacheEnabled(true);
tv.measure(MeasureSpec.makeMeasureSpec(canvas.getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(canvas.getHeight(), MeasureSpec.EXACTLY));
tv.layout(0, 0, tv.getMeasuredWidth(), tv.getMeasuredHeight());
canvas.drawBitmap(tv.getDrawingCache(), 5, 10, Paint1);
tv.setDrawingCacheEnabled(false);
J'ai réutilisé la solution proposée par GreenBee et créé une fonction permettant de dessiner du texte multiligne dans des limites spécifiées avec le signe "..." à la fin si un tronçon se produisait:
public static void drawMultiLineEllipsizedText(final Canvas _canvas, final TextPaint _textPaint, final float _left,
final float _top, final float _right, final float _bottom, final String _text) {
final float height = _bottom - _top;
final StaticLayout measuringTextLayout = new StaticLayout(_text, _textPaint, (int) Math.abs(_right - _left),
Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
int line = 0;
final int totalLineCount = measuringTextLayout.getLineCount();
for (line = 0; line < totalLineCount; line++) {
final int lineBottom = measuringTextLayout.getLineBottom(line);
if (lineBottom > height) {
break;
}
}
line--;
if (line < 0) {
return;
}
int lineEnd;
try {
lineEnd = measuringTextLayout.getLineEnd(line);
} catch (Throwable t) {
lineEnd = _text.length();
}
String truncatedText = _text.substring(0, Math.max(0, lineEnd));
if (truncatedText.length() < 3) {
return;
}
if (truncatedText.length() < _text.length()) {
truncatedText = truncatedText.substring(0, Math.max(0, truncatedText.length() - 3));
truncatedText += "...";
}
final StaticLayout drawingTextLayout = new StaticLayout(truncatedText, _textPaint, (int) Math.abs(_right
- _left), Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
_canvas.save();
_canvas.translate(_left, _top);
drawingTextLayout.draw(_canvas);
_canvas.restore();
}
ça va marcher. j'ai testé
public Bitmap drawMultilineTextToBitmap(Context gContext,
int gResId,
String gText) {
// prepare canvas
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);
Android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = Android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialiased Paint
TextPaint Paint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
Paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
Paint.setTextSize((int) (14 * scale));
// text shadow
Paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// set text width to canvas width minus 16dp padding
int textWidth = canvas.getWidth() - (int) (16 * scale);
// init StaticLayout for text
StaticLayout textLayout = new StaticLayout(
gText, Paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// get height of multiline text
int textHeight = textLayout.getHeight();
// get position of text's top left corner
float x = (bitmap.getWidth() - textWidth)/2;
float y = (bitmap.getHeight() - textHeight)/2;
// draw text to the Canvas center
canvas.save();
canvas.translate(x, y);
textLayout.draw(canvas);
canvas.restore();
return bitmap;
}
Source: http://www.skoumal.net/en/Android-drawing-multiline-text-on-bitmap/
Solution sans StaticLayout
//Get post text
String text = post.getText();
//Get weight of space character in px
float spaceWeight = Paint.measureText(" ");
//Start main algorithm of drawing words on canvas
//Split text to words
for (String line : text.split(" ")) {
//If we had empty space just continue
if (line.equals("")) continue;
//Get weight of the line
float lineWeight = Paint.measureText(line);
//If our Word(line) doesn't have any '\n' we do next
if (line.indexOf('\n') == -1) {
//If Word can fit into current line
if (cnv.getWidth() - pxx - defaultMargin >= lineWeight) {
//Draw text
cnv.drawText(line, pxx, pxy, Paint);
//Move start x point to Word weight + space weight
pxx += lineWeight + spaceWeight;
} else {
//If Word can't fit into current line
//Move x point to start
//Move y point to the next line
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
//Draw
cnv.drawText(line, pxx, pxy, Paint);
//Move x point to Word weight + space weight
pxx += lineWeight + spaceWeight;
}
//If line contains '\n'
} else {
//If '\n' is on the start of the line
if (line.indexOf('\n') == 0) {
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
cnv.drawText(line.replaceAll("\n", ""), pxx, pxy, Paint);
pxx += lineWeight + spaceWeight;
} else {
//If '\n' is somewhere in the middle
//and it also can contain few '\n'
//Split line to sublines
String[] subline = line.split("\n");
for (int i = 0; i < subline.length; i++) {
//Get weight of new Word
lineWeight = Paint.measureText(subline[i]);
//If it's empty subline that's mean that we have '\n'
if (subline[i].equals("")) {
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
cnv.drawText(subline[i], pxx, pxy, Paint);
continue;
}
//If we have only one Word
if (subline.length == 1 && i == 0) {
if (cnv.getWidth() - pxx >= lineWeight) {
cnv.drawText(subline[0], pxx, pxy, Paint);
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
} else {
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
cnv.drawText(subline[0], pxx, pxy, Paint);
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
}
continue;
}
//If we have set of words separated with '\n'
//it is the first Word
//Make sure we can put it into current line
if (i == 0) {
if (cnv.getWidth() - pxx >= lineWeight) {
cnv.drawText(subline[0], pxx, pxy, Paint);
pxx = defaultMargin;
} else {
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
cnv.drawText(subline[0], pxx, pxy, Paint);
pxx = defaultMargin;
}
} else {
pxx = defaultMargin;
pxy += Paint.descent() - Paint.ascent();
cnv.drawText(subline[i], pxx, pxy, Paint);
pxx += lineWeight + spaceWeight;
}
}
}
}
}
J'ai travaillé avec ce que j'avais, qui convertissait déjà des lignes simples en toiles, et j'ai travaillé sur la réponse de Lumis, et j'ai fini avec ceci. Les 1.3 et 1.3f sont censés servir de remplissage entre les lignes, par rapport à la taille de la police.
public static Bitmap getBitmapFromString(final String text, final String font, int textSize, final int textColor)
{
String lines[] = text.split("\n");
textSize = getRelX(textSize); //a method in my app that adjusts the font size relative to the screen size
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint.setTextSize(textSize);
Paint.setColor(textColor);
Paint.setTextAlign(Paint.Align.LEFT);
Typeface face = Typeface.createFromAsset(GameActivity.getContext().getAssets(),GameActivity.getContext().getString(R.string.font) + font + GameActivity.getContext().getString(R.string.font_ttf));
Paint.setTypeface(face);
float baseline = -Paint.ascent(); // ascent() is negative
int width = (int) (Paint.measureText(text) + 0.5f); // round
int height = (int) (baseline + Paint.descent() + 0.5f);
Bitmap image = Bitmap.createBitmap(width, (int)(height * 1.3 * lines.length), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
for (int i = 0; i < lines.length; ++i)
{
canvas.drawText(lines[i], 0, baseline + textSize * 1.3f * i, Paint);
}
return image;
}
Mon exemple avec le redimensionnement et l'espacement de texte dynamique, fonctionne très bien pour moi ...
public Bitmap fontTexture(String string, final Context context) {
float text_x = 512;
float text_y = 512;
final float scale = context.getResources().getDisplayMetrics().density;
int mThreshold = (int) (THRESHOLD_DIP * scale + 0.5f);
String[] splited = string.split("\\s+");
double longest = 0;
for(String s:splited){
if (s.length() > longest) {
longest = s.length();
}
}
if(longest > MAX_STRING_LENGTH) {
double ratio = (double) MAX_STRING_LENGTH / longest;
mThreshold = (int) ((THRESHOLD_DIP * ((float) ratio)) * scale + 0.5f);
}
Bitmap bitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Typeface font = Typeface.createFromAsset(context.getAssets(),
"fonts/dotted_font.ttf");
TextPaint mTextPaint=new TextPaint();
mTextPaint.setColor(Color.YELLOW);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextSize(mThreshold);
mTextPaint.setTypeface(font);
StaticLayout mTextLayout = new StaticLayout(string, mTextPaint, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
canvas.save();
canvas.translate(text_x, text_y);
mTextLayout.draw(canvas);
canvas.restore();
return bitmap;
}