MY code is
Paint paint= new Paint();
paint.setTextSize(size);
int iRet = 0;
if (str != null && str.length() > 0) {
int len = str.length();
float[] widths = new float[len];
paint.getTextWidths(str, widths);
for (int j = 0; j < len; j++) {
iRet += (int) Math.ceil(widths[j]);
}
}
return iRet;
I want to get the width of string ,but the return result has errors with TextView.
Don't know the right way.
thanks.
I show it in the virtual machine.
To calculate text width you should use:
public float measureText (String text)
method in class Paint, it will return measured width of text in paint.
you can try to use canvas,Once a time I found the Textview can't show my text in right size ,so I use Canvas draw the text out ,the I get the width I want,that's maybe some wrong cause by dp,sp or px.
you can use:
int width = paint.measureText("this text");
measureText(String text) will return width of text.
you can measure it by calling the measureText() of paint class here is the code for that-
Paint p=new paint();
int value = p.measureText("give input string to measure");
Related
I am working on an android watermarking project, and I need to make a method to generate 2D arrays for R,G and B and recreate the image after getting it back from the WM method that is done by someone else.(I don't have this method, so I can't change it).
Here is how I created the R,G, B from the bitmap:
Bitmap image = BitmapFactory.decodeFile("/sdcard/Watermarking/WM_20151208_183746_1282108897-1.jpg");
int height = image.getHeight();
int width = image.getWidth();
short [][] red = new short[height][width];
short [][] green = new short[height][width];
short [][] blue = new short[height][width];
int column = 0;
int row = 0;
while(row < height)
{
while(column < width)
{
int pixel = image.getPixel(column, row);
red[row][column] = (short) Color.red(pixel);
green[row][column] = (short) Color.green(pixel);
blue[row][column] = (short) Color.blue(pixel);
column++;
}
row++;
}
displayImage(red, green, blue);
And here is the method that I am doing to test that what I did was correct:
public void displayImage(short [][] red, short [][] green, short [][] blue)
{
short height = (short) red.length;
short width = (short) red[0].length;
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int column = 0;
int row = 0;
while(row < height)
{
while(column < width)
{
image.setPixel(column, row, Color.rgb(red[row][column], green[row][column], blue[row][column]));
column++;
}
row++;
}
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap (image);
}
The image that appears is a black image, even though it should be correct. Any help is appreciated.
by simply debugging your code, you are only filling the first row of the array repeatedly by not resetting the column variable
add:
column = 0;
after both loops (in filling and reading the array);
I just wrote some code which grabs an image, stores it's pixels into an array and displays every pixel again, so that finally the grabbed image should be shown.
I took following image:
It's an 32x32 png image that I chose to use as an example.
That's my output:
As You might see, the result has far more pixels than 32x32.
Here's how my code looks:
First, an array was created that should get all the pixel informations of the image:
private Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.test);
private int w = b.getWidth;
private int h = b.getHeight;
private int pixels = w*h;
Then I used a method to store the bitmap's pixels into the array:
b.getPixels(pixels, 0, w, 0, 0, w, h);
I thought this should be it, now I can draw the pixels to my View:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint p = new Paint();
for(int i = 0; i < w; i++) {
for(int j = 0; j < h; j++) {
p.setColor(Color.parseColor(String.format("#%06X", (0xFFFFFF & pixelImage.pixels[i+i*j]))));
canvas.drawRect(i, j, i+1, j+1, paint);
}
}
}
I have no idea where my error is, maybe somebody can help me?
Your algorithm is wrong, and frequently a bit wtf-y. There's no reason for String.format to even come into it, I'm not even sure where you're going there. And drawRect is not the way to do it. Try:
for(int i = 0; i < w; i++) {
for(int j = 0; j < h; j++) {
p.setColor(pixels[i*bmp.getWidth()+j]);
canvas.drawPoint(j, i, paint);
}
}
There is a problem with some Paint class methods. I should get the width of spanned string given to the TextView. Let's say I'm measuring text at first row. When I measure it programmatically it gives 286, but the width of the screen is 240? Maybe someone had such a problem?Any help will be appreciated...
The code for calculating width of spanned text:
private int calcWidthSize(CharSequence spannedString, int currentSize) {
int res = 0;
Paint paint = new Paint();
float[] a= new float[444];
paint.setTextSize(currentSize);
paint.getTextWidths(spannedString,0,spannedString.length(),a);
for (int num=0;num<a.length;num++){
res+=(int)a[num];
}
return res;
}
Solved.The width of display is in pixels format and equals to 240.Text measure gives us result in dp format
I have a TextView in which I want to place a solid color block over given words of the TextView, for example:
"This is a text string, I want to put a rectangle over this WORD" - so, "WORD" would have a rectangle with a solid color over it.
To do this, I am thinking about overriding the onDraw(Canvas canvas) method, in order to draw a block over the text. My only problem is to find an efficient way to get the absolute position of a given word or character.
Basically, I am looking for something that does the exact opposite of the getOffsetForPosition(float x, float y) method
Based on this post: How get coordinate of a ClickableSpan inside a TextView?, I managed to use this code in order to put a rectangle on top of the text:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
// Initialize global value
TextView parentTextView = this;
Rect parentTextViewRect = new Rect();
// Find where the WORD is
String targetWord = "WORD";
int startOffsetOfClickedText = this.getText().toString().indexOf(targetWord);
int endOffsetOfClickedText = startOffsetOfClickedText + targetWord.length();
// Initialize values for the computing of clickedText position
Layout textViewLayout = parentTextView.getLayout();
double startXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int)startOffsetOfClickedText);
double endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int)endOffsetOfClickedText);
// Get the rectangle of the clicked text
int currentLineStartOffset = textViewLayout.getLineForOffset((int)startOffsetOfClickedText);
int currentLineEndOffset = textViewLayout.getLineForOffset((int)endOffsetOfClickedText);
boolean keywordIsInMultiLine = currentLineStartOffset != currentLineEndOffset;
textViewLayout.getLineBounds(currentLineStartOffset, parentTextViewRect);
// Update the rectangle position to his real position on screen
int[] parentTextViewLocation = {0,0};
parentTextView.getLocationOnScreen(parentTextViewLocation);
double parentTextViewTopAndBottomOffset = (
//parentTextViewLocation[1] -
parentTextView.getScrollY() +
parentTextView.getCompoundPaddingTop()
);
parentTextViewRect.top += parentTextViewTopAndBottomOffset;
parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;
// In the case of multi line text, we have to choose what rectangle take
if (keywordIsInMultiLine){
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int screenHeight = display.getHeight();
int dyTop = parentTextViewRect.top;
int dyBottom = screenHeight - parentTextViewRect.bottom;
boolean onTop = dyTop > dyBottom;
if (onTop){
endXCoordinatesOfClickedText = textViewLayout.getLineRight(currentLineStartOffset);
}
else{
parentTextViewRect = new Rect();
textViewLayout.getLineBounds(currentLineEndOffset, parentTextViewRect);
parentTextViewRect.top += parentTextViewTopAndBottomOffset;
parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;
startXCoordinatesOfClickedText = textViewLayout.getLineLeft(currentLineEndOffset);
}
}
parentTextViewRect.left += (
parentTextViewLocation[0] +
startXCoordinatesOfClickedText +
parentTextView.getCompoundPaddingLeft() -
parentTextView.getScrollX()
);
parentTextViewRect.right = (int) (
parentTextViewRect.left +
endXCoordinatesOfClickedText -
startXCoordinatesOfClickedText
);
canvas.drawRect(parentTextViewRect, paint);
}
You can use spans for that.
First you create a spannable for your text, like this:
Spannable span = new SpannableString(text);
Then you put a span around the word that you want to highlight, somewhat like this:
span.setSpan(new UnderlineSpan(), start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Unfortunately I don't know of an existing span that puts a border around a word. I found UnderlineSpan, and also BackgroundColorSpan, perhaps these are also useful for you, or you can have a look at the code and see if you can create a BorderSpan based on one of those.
Instead of drawing a rectangle over the WORD, you could simply replace its characters with an appropriate unicode symbol like U+25AE (▮ Black vertical rectangle).
So you'd get
"This is a text string, I want to put a rectangle over this ▮▮▮▮"
If that is sufficient. See for example Wikipedia for a wast list of unicode symbols.
If you actually need to paint that black box you can do the following as long as your text is in a single line:
Calculate the width of the text part before 'WORD' as explained here to find the left edge of the box and calcuate the width of 'WORD' using the same method to find the width of the box.
For a multiline text the explained method might also work but I think you'll have to do quite a lot of work here.
use getLayout().getLineBottom and textpaint.measureText to manually do the reverse calculation of getOffsetForPosition.
below is an example of using the calculated x,y for some textOffset to position the handle drawable when the textview gets clicked.
class TextViewCustom extends TextView{
float lastX,lastY;
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean ret = super.onTouchEvent(event);
lastX=event.getX();
lastY=event.getY();
return ret;
}
BreakIterator boundary;
Drawable handleLeft;
private void init() {// call it in constructors
boundary = BreakIterator.getWordInstance();
handleLeft=getResources().getDrawable(R.drawable.abc_text_select_handle_left_mtrl_dark);
setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
int line = getLayout().getLineForVertical((int) lastY);
int offset = getLayout().getOffsetForHorizontal(line, lastX);
int wordEnd = boundary.following(offset);
int wordStart = boundary.previous();
CMN.Log(getText().subSequence(wordStart, wordEnd));
int y = getLayout().getLineBottom(line);
int trimA = getLayout().getLineStart(line);
float x = getPaddingLeft()+getPaint().measureText(getText(), trimA, wordStart);
x-=handleLeft.getIntrinsicWidth()*1.f*9/12;
handleLeft.setBounds((int)x,y,(int)(x+handleLeft.getIntrinsicWidth()),y+handleLeft.getIntrinsicHeight());
invalidate();
}
});
}
#Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
if(boundary!=null)
boundary.setText(text.toString());
}
}
I would like to get height too if possible.
You can use the getTextBounds(String text, int start, int end, Rect bounds) method of a Paint object. You can either use the paint object supplied by a TextView or build one yourself with your desired text appearance.
Using a Textview you Can do the following:
Rect bounds = new Rect();
Paint textPaint = textView.getPaint();
textPaint.getTextBounds(text, 0, text.length(), bounds);
int height = bounds.height();
int width = bounds.width();
If you just need the width you can use:
float width = paint.measureText(string);
http://developer.android.com/reference/android/graphics/Paint.html#measureText(java.lang.String)
There are two different width measures for a text. One is the number of pixels which has been drawn in the width, the other is the number of 'pixels' the cursor should be advanced after drawing the text.
paint.measureText and paint.getTextWidths returns the number of pixels (in float) which the cursor should be advanced after drawing the given string. For the number of pixels painted use paint.getTextBounds as mentioned in other answer. I believe this is called the 'Advance' of the font.
For some fonts these two measurements differ (alot), for instance the font Black Chancery have letters which extend past the other letters (overlapping) - see the capital 'L'. Use paint.getTextBounds as mentioned in other answer to get pixels painted.
I have measured width in this way:
String str ="Hiren Patel";
Paint paint = new Paint();
paint.setTextSize(20);
Typeface typeface = Typeface.createFromAsset(getAssets(), "Helvetica.ttf");
paint.setTypeface(typeface);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
Rect result = new Rect();
paint.getTextBounds(str, 0, str.length(), result);
Log.i("Text dimensions", "Width: "+result.width());
This would help you.
Most likely you want to know the painted dimensions for a given string of text with a given font (i.e. a particular Typeface such as the “sans-serif” font family with a BOLD_ITALIC style, and particular size in sp or px).
Rather than inflating a full-blown TextView, you can go lower level and work with a Paint object directly for single-line text, for example:
// Maybe you want to construct a (possibly static) member for repeated computations
Paint paint = new Paint();
// You can load a font family from an asset, and then pick a specific style:
//Typeface plain = Typeface.createFromAsset(assetManager, pathToFont);
//Typeface bold = Typeface.create(plain, Typeface.DEFAULT_BOLD);
// Or just reference a system font:
paint.setTypeface(Typeface.create("sans-serif",Typeface.BOLD));
// Don't forget to specify your target font size. You can load from a resource:
//float scaledSizeInPixels = context.getResources().getDimensionPixelSize(R.dimen.mediumFontSize);
// Or just compute it fully in code:
int spSize = 18;
float scaledSizeInPixels = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
spSize,
context.getResources().getDisplayMetrics());
paint.setTextSize(scaledSizeInPixels);
// Now compute!
Rect bounds = new Rect();
String myString = "Some string to measure";
paint.getTextBounds(myString, 0, myString.length(), bounds);
Log.d(TAG, "width: " + bounds.width() + " height: " + bounds.height());
For multi-line or spanned text (SpannedString), consider using a StaticLayout, in which you provide the width and derive the height. For
a very elaborate answer on measuring and drawing text to a canvas in a custom view doing that, see: https://stackoverflow.com/a/41779935/954643
Also worth noting #arberg's reply below about the pixels painted vs the advance width ("number of pixels (in float) which the cursor should be advanced after drawing the given string"), in case you need to deal with that.
I'd like to share a better way (more versatile then the current accepted answer) of getting the exact width of a drawn text (String) with the use of static class StaticLayout:
StaticLayout.getDesiredWidth(text, textPaint))
this method is more accurate than textView.getTextBounds(), since you can calculate width of a single line in a multiline TextView, or you might not use TextView to begin with (for example in a custom View implementation).
This way is similar to textPaint.measureText(text), however it seems to be more accurate in rare cases.
simplay i tack max charcter in the line and defieded it with max space and create new line
v_y = v_y + 30;
String tx = "مبلغ وقدرة : "+ AmountChar+" لا غير";
myPaint.setTextAlign(Paint.Align.RIGHT);
int pxx = 400;
int pxy = v_y ;
int word_no = 1;
int word_lng = 0;
int max_word_lng = 45;
int new_line = 0;
int txt_lng = tx.length();
int words_lng =0;
String word_in_line = "" ;
for (String line : tx.split(" "))
{
word_lng = line.length() ;
words_lng += line.length() + 1;
if (word_no == 1 )
{word_in_line = line;
word_no += 1;
}
else
{ word_in_line += " " + line;
word_no += 1;
}
if (word_in_line.length() >= max_word_lng)
{
canvas.drawText(word_in_line, pxx, pxy, myPaint);
new_line += 1;
pxy = pxy + 30;
word_no = 1;
word_in_line = "";
}
if (txt_lng <= words_lng )
{ canvas.drawText(word_in_line, pxx, pxy, myPaint); }
}
v_y = pxy;