I'm trying to get the exact Y position of a given line of text. I thought I would use i * TextView.getLineHeight() to get the Y position of the ith line, but that doesn't seem to be right.
The reason I think this is wrong is because TextView.getLineHeight() * TextView.getLineCount() != TextView.getHeight() which I assume is due to the same error. The line spacing and line multiplier are both default for this TextView.
What is the proper method to get the y position of the ith line in a TextView?
EDIT ---
It seems even TextView.getLayout().getLineTop(i) isn't correct, although please tell me if I'm overlooking something
private int getTextViewHeight(TextView textView) {
Layout layout = textView.getLayout();
int desired = layout.getLineTop(textView.getLineCount());
int padding = textView.getCompoundPaddingTop() +
textView.getCompoundPaddingBottom();
return desired + padding;
}
This code is helped.Read the TextView SourceCode(about onMeasure) you can know how it worked.
Related
Is it possible to get the x coordinate from a character in a TextView in Android?
I'm not looking for the coordinate of the TextView itself, I need the coordinate of the last character in the TextView (multi line)
Thanks in advance
Java Solution
Here is how to get the x and y coordinates of a specific character. offset is the index of the desired character in the textView's String. These coordinates are relative to the parent container
Layout layout = textView.getLayout();
if (layout == null) { // Layout may be null right after change to the text view
// Do nothing
}
int lineOfText = layout.getLineForOffset(offset);
int xCoordinate = (int) layout.getPrimaryHorizontal(offset);
int yCoordinate = layout.getLineTop(lineOfText);
Kotlin Extension Function
If you expect to use this more than once:
fun TextView.charLocation(offset: Int): Point? {
layout ?: return null // Layout may be null right after change to the text view
val lineOfText = layout.getLineForOffset(offset)
val xCoordinate = layout.getPrimaryHorizontal(offset).toInt()
val yCoordinate = layout.getLineTop(lineOfText)
return Point(xCoordinate, yCoordinate)
}
NOTE: To ensure layout is not null, you can call textview.post(() -> { /* get coordinates */ }) in Java or textview.post { /* get coordinates */ } in Kotlin
Use:
layout.getPrimaryHorizontal(int offset)
It is simple to use. You just iterate through the layout using the length of the text it uses.
It will return the x of the Character . So lines I'm still getting from the layout.getLineTop() . By the way, if you are using the layout.getLineTop() , note that there is some strange behaviour, possibly a bug.
Given a span that has one or more paragraphs, try to get the last character of the entire span dosen't work. Is there another way to get the same result of getPrimaryHorizontal()?
I have a TextView with an OnTouchListener. What I want is the character index the user is pointing to when I get the MotionEvent. Is there any way to get to the underlying font metrics of the TextView?
Have you tried something like this:
Layout layout = this.getLayout();
if (layout != null)
{
int line = layout.getLineForVertical(y);
int offset = layout.getOffsetForHorizontal(line, x);
// At this point, "offset" should be what you want - the character index
}
Hope this helps...
I am not aware of a simple direct way to do this but you should be able to put something together using the Paint object of the TextView via a call to TextView.getPaint()
Once you have the paint object you will have access to the underlying FontMetrices via a call to Paint.getFontMetrics() and have access to other functions like Paint.measureText() Paint.getTextBounds(), and Paint.getTextWidths() for accessing the actual size of the displayed text.
While it generally works I had a few problems with the answer from Tony Blues.
Firstly getOffsetForHorizontal returns an offset even if the x coordinate is way beyond the last character of the line.
Secondly the returned character offset sometimes belongs to the next character, not the character directly underneath the pointer. Apparently the method returns the offset of the nearest cursor position. This may be to the left or to the right of the character depending on what's closer by.
My solution uses getPrimaryHorizontal instead to determine the cursor position of a certain offset and uses binary search to find the offset underneath the pointer's x coordinate.
public static int getCharacterOffset(TextView textView, int x, int y) {
x += textView.getScrollX() - textView.getTotalPaddingLeft();
y += textView.getScrollY() - textView.getTotalPaddingTop();
final Layout layout = textView.getLayout();
final int lineCount = layout.getLineCount();
if (lineCount == 0 || y < layout.getLineTop(0) || y >= layout.getLineBottom(lineCount - 1))
return -1;
final int line = layout.getLineForVertical(y);
if (x < layout.getLineLeft(line) || x >= layout.getLineRight(line))
return -1;
int start = layout.getLineStart(line);
int end = layout.getLineEnd(line);
while (end > start + 1) {
int middle = start + (end - start) / 2;
if (x >= layout.getPrimaryHorizontal(middle)) {
start = middle;
}
else {
end = middle;
}
}
return start;
}
Edit: This updated version works better with unnatural line breaks, when a long word does not fit in a line and gets split somewhere in the middle.
Caveats: In hyphenated texts, clicking on the hyphen at the end of a line return the index of the character next to it. Also this method does not work well with RTL texts.
I'm developing an android application and i need to know the number of characters that could be shown in one line to determine the number of lines of my string with some method .
How could do this ?
tanks a lot .
This should do the job for you (give or take a few mistakes from coding without an ide :-/ )
int countLineBreaks(final TextView view, final String toMeasure) {
final Paint paint = textView.getPaint(); // Get the paint used by the TextView
int startPos = 0;
int breakCount = 0;
final int endPos = toMeasure.length();
// Loop through the string, moving along the number of characters that will
// fit on a line in the TextView. The number of iterations = the number of line breaks
while (startPos < endPos) {
startPos += paint.breakText(toMeasure.substring(startPos, endPos),
true, tv.getWidth(),(float[]) null);
lineCount++;
}
// Line count will now equal the number of line-breaks the string will require
return lineCount;
}
..you get the idea ;-)
Every character has its own width.
As any String which contains 10 characters is not same to another String which also contains 10 char.
u can set it by --> textView.setTypeface(Typeface.MONOSPACE);
Monospace typeface works for making will regular char equal width.
Then u can do any stuff to get that how many characters could be placed in one line?
You can try this
set the Typeface.MONOSPACE as geet suggested. then do the following
Paint.measureText(String s) returns the width of the String s. By using this you can get the required width of 1 character. And from the View.getwidth() method you can get the width of the view. So from these two values you can calculate
try this:
int totalLine = textView.getMeasuredHeight() / textView.getLineHeight();
I have an EditText in Android. It has long content and it scrolls into pages
How can I find the real height of content, not just the visible area?
I tried this, but it just gives height of visible area:
EditText editor=(EditText)findViewById(R.id.ed1);
.
.
.
double H=editor.getHeight();
not H is 1150, not 10000 or something like that which is real height of content.
This is what I do:
EditText tv = ...;
if (Build.VERSION.SDK_INT >= 16) {
totalHeight = Math.round((tv.getLineCount() * (tv.getLineHeight() + tv.getLineSpacingExtra()) *
tv.getLineSpacingMultiplier())) + tv.getCompoundPaddingTop() + tv.getCompoundPaddingBottom();
} else {
totalHeight = tv.getLineCount() * tv.getLineHeight() + tv.getCompoundPaddingTop() + tv.getCompoundPaddingBottom();
}
You can do this in following steps
count the lines in the edit text get help from here
after that calculate the height(includeing top padding) of single line then simply multiply that number to get the real height of the text inside the editText
It was enough for me to call EditText.getLayout().getHeight();
I've just debugged an app where I need this functionality too:
int contentHeight = view.getTextArea().getLayout().getHeight();
int visibleAreaHeight = view.getTextArea().getHeight();
The values are:
contentHeight = 7531
visibleAreaHeight = 1408
I want to know how can I get the x,y position of the selected character or String in
EditText. Is that possible?
Use this code to get the first index of a certain character:
String s = editText.getText().toString();
int position = s.indexOf("C"); // where C is your character to be searched
Here is how to get the x and y coordinates of a specific character in a TextView, should work for EditText as well. offset is the index of the desired character in the view's text.
Layout layout = editView.getLayout();
if (layout == null) { // Layout may be null right after change to the view
// Do nothing
}
int lineOfText = layout.getLineForOffset(offset);
int xCoordinate = (int) layout.getPrimaryHorizontal(offset);
int yCoordinate = layout.getLineTop(lineOfText);