android TextView onDraw IndexOutOfBounds - android

I have a TextView containing text from a file. I apply and remove spans from it to style it depending on the contents. A file has come up that, when scrolling to that spot/line in the file, throws an IndexOutOfBounds from within the TextView onDraw only if I have applied spans(just syntax highlighting spans).
java.lang.IndexOutOfBoundsException: getChars (4255 ... 4211) has end before start
at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:947)
What in my spans could be causing this and how could I go about preventing it form doing this?
http://code.google.com/p/droidde/source/browse/src/com/eyecreate/droidde/RichEditText.java#63
EDIT:This doesn't seem to happen on ICS, just Honeycomb it seems.
EDIT2: These lines seem to be near the root of the issue. These are in android.text.Layout.java
private float getLineExtent(int line, boolean full) {
int start = getLineStart(line);
int end = full ? getLineEnd(line) : getLineVisibleEnd(line);
at this point, start and end are the wrong numbers and full is false. Also, this doesn't crash if I comment out lines 71-77 in the source I linked.(but removes functionality)

Related

Android - How do I make sure a widget is the last in that line?

I'm trying to export all widgets on screen to a text. To do that, I'm cycling through all widgets inside the RelativeLayout I have on screen. How do I make sure the view I'm currently looking at is the rightmost (or last) in that line?
for(int i = 0; i < relLayout.getChildCount(); i++) {
View view = relLayout.getChildAt(i);
(...)
}
And then I'm checking if the view I'm looking at is a TextView, EditText, Spinner, etc. So far, so good. But in order to append the new lines to the string, I'd like to programmatically check if that view is the last in that row. Is there a clear/simple way to do that (other than enumerating the id's of those widgets, which I'm doing right now? :D)
Thanks in advance!
PS1: For the purpose of the question, assume there are no compilation errors in the code. I just don't know how to achieve this.
Fixed, but in a curious way.
In my case, all the last fields on screen had Align Parent End flagged. So I found online this would be the way to do it:
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
int[] rules = params.getRules();
if ((rules[RelativeLayout.ALIGN_PARENT_END] == RelativeLayout.TRUE)) {
// Do something about it
}
Where RelativeLayout.ALIGN_PARENT_END stands for 21, according to http://developer.android.com/reference/android/widget/RelativeLayout.html
However, my code was returning false for that check. So I started displaying the value for the property, and it really was false. I tried this for a while, then I saw one of my edittexts returned true for it. But the activity xml showed this
android:layout_alignParentRight="true"
in addition to alignParentEnd. Which didn't make sense, since alignParentRight is supposed to be rule 11, according to the same link above.
So I devised this code to expose which rules where true, and put it in my code:
for(int x = 0; x < 22; x++) {
if (rules[x] == RelativeLayout.TRUE) Log.i("Property true:", String.valueOf(x));
}
Which gave me 11 for all fields, and 11 and 21 for the field that responded TRUE before. Remember, all fields had android:layout_alignParentEnd="true" in the activity xml.
So to fix my code, I'm now checking rules[RelativeLayout.ALIGN_PARENT_RIGHT] and it works, but I strongly believe those two properties are switched somehow. Can anybody confirm? Or please englighten me on where I screwed up, which is more likely :)

How to extend a complex Android view like the GridView?

Background:
I'm looking for a way to extend the GridView I need implement a col- and row-span like in HTML. I have hunderds of elements so I cannot use e.g. a TableLayout. However that would be too localized. So far I reduce the question to how to extend the GridView?
What I have tried and where I have failed:
My first approach was to look which methods I need to replace and I found some private methods which cannot be overriden. So I tried to copy the hole source code from the GridView to a new class called CustomGrid. That was a terrible failure since I cannot access the com.android.internal.R class.
Then I dropped that idea and looked if I can normal extend the class and replace all the private methods with custom copies. I took a pen and build a huge tree where all methods are used.
After I found all references I tried to extend the class normal and I added the first method:
private View fillDown(int pos, int nextTop) {
View selectedView = null;
int end = (mBottom - mTop);
if((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
end -= mListPadding.bottom;
}
// ...
Here is my next problem that member variables mBottom and mTop are unknown. I digged a little through the sources and found them finally in the View class, but unfortunately they are hidden.
/**
* The distance in pixels from the top edge of this view's parent
* to the bottom edge of this view.
* {#hide}
*/
#ViewDebug.ExportedProperty(category = "layout")
protected int mBottom;
Question:
How can I extend the GridView without hitting that lamentations and without the usage of massive reflection? I mean it seems to be impossible to write that as a pure custom control.
How can I extend the GridView without hiting that limentations and without the usage of massive reflection?
Most likely, you don't. You copy the code into your project and modify to suit, including all requisite superclasses (up to ViewGroup). I will be stunned if you can achieve your aims by a simple subclass of GridView. You may even have to completely write your desired widget from scratch.
That was a terrible failior due I cannot access the com.android.internal.R class.
You will also need to copy over relevant resources, then fix up R references to point to your own resources.
but unforcantly they are hidden.
You find other ways of getting this data. mBottom, for example, can be changed to getBottom().

TextView.setMaxLines not working?

In my app I have a screen where I display some text and then a photo. The text is variable in length (sometimes none at all, sometimes a lot), so I wanted to have it set up so the text never takes up more than a few lines (but can be scrolled) leaving enough room for the image below.
My view component for this part is created programatically, and I've adjusted the code to have the following (currently in my text-setting method, but the same thing happens if it's in the initial view-create code)
public void SetDescription(String description)
{
mTxtDescription.setText(Html.fromHtml(description));
mTxtDescription.setClickable(true);
mTxtDescription.setMaxLines(5);
mTxtDescription.setLines(5); //this makes no difference either!
mTxtDescription.setSingleLine(false);
mTxtDescription.setScrollbarFadingEnabled(true);
mTxtDescription.setScrollBarStyle(VERTICAL);
mTxtDescription.setMovementMethod(ScrollingMovementMethod.getInstance());
mTxtDescription.invalidate(); //adding this made no difference...
}
However it doesn't work- long text still fills the whole screen and the image has vanished due to being pushed down to a height of 0. How can I get the text to never be more than 5 lines?
Try removing the call to setSingleLine. And use setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE). It'd also put this call before the setMaxLines and setLines call to be sure.
Note: setLines overrides the settings of setMaxLines and setMinLines.
The TextView has many issues surrounding the various calls to how it should display multiple, ellipses, etc.
The setSingleLine(false) seemes to reset the setMaxLines command. Try to move the setSingleLine command before the setText. That worked for me.
The below code is working fine for me
txt = (TextView)findViewById(R.id.textview);
txt.setMaxLines(5);
txt.setMovementMethod(new ScrollingMovementMethod());
txt.setScrollContainer(true);
txt.setText("Example Text");
txt.setTextColor(Color.WHITE);
txt.setScrollbarFadingEnabled(true);
in xml inside textview
android:scrollbars="vertical"

Android TextView Slow Using append() Hundreds of Times - Solution?

I have a source code editor for Android, and I have a line numbers counter that's to the left of the main EditText with source code inside it.
I have the following function I use for updating the line numbers text view:
String lineDelimiter = "\n";
public void updateLineNumbers(){
int lines = textBox.getLineCount();
lineNums.setText(1 + lineDelimiter);
for(int i = 2; i < lines; i++){
lineNums.append(i + lineDelimiter);
}
}
All this is fine, but the problem is when you have a document with say 200 odd lines you start to notice a little delay when adding lines. Is this cause Android TextView's setText/append methods are a little slow? Or is it the concatination that's causing the delay?
I've also made a similar function that appends a line number when the user adds a line number, and vice versa, as opposed to clearing the TextView and adding each line numbers again like the function above does. But this function still lags the app when the user adds/removes line(s).
How can I stop this? I can't think of what to do and it's stressing me out because it's lagging my app and rendering it unusable for large files! :(
Thanks for looking!
SOLUTION
I've found a way to have fast line numbers, which is to use a custom TextView with onDraw(Canvas canvas) overriden and to draw them that way which results in lag-free line numbers :).
Is this cause Android TextView's setText/append methods are a little slow? Or is it the concatination that's causing the delay?
Use Traceview and find out.
Off the cuff, I would imagine that calling append() a whole bunch of times on a TextView will be vastly slower than calling append() a bunch of times on a StringBuilder, then calling setText() once on the TextView.
How can I stop this?
Don't handle line numbers that way. For example, put a TextView to the left of the EditText, and put your line numbers in the TextView, one per line.

How to disable the TextView maxLines programmatically?

I'm having a hard time reseting the maxLines attribute of a TextView programmatically.
Just tried setting to 0 and it doesn't work. -1 crashes the application. I could use a simpler workaround and set the maxLines to 5000 but I don't want to do that.
Any ideas how to do that?
UPDATED
Well, I've found one problem.. I've set the Ellipsize as well... I'm just going to use the following workaround:
TextView questionDetail = (TextView) mQuestionDetailHeader.findViewById(R.id.desc);
questionDetail.setText(mCurrentQuestion.getQuestion());
questionDetail.setMaxLines(Integer.MAX_VALUE); //As in the android sourcecode
questionDetail.setEllipsize(null);
As there isn't yet an approved answer - the proper way to reset the maxlines property of the TextView is:
textView.setMaxLines(Integer.MAX_VALUE);
As per Valdemar's comment and this stackoverflow answer. Using -1 will cause an ArrayIndexOutOfBoundsException.
Keep in mind only END and MARQEE setEllipsize() settings will be respected for maxlines >= 2 according to the documentation:
If setMaxLines(int) has been used to set two or more lines, END and
MARQUEE* are only supported (other ellipsizing types will not do
anything).
For setting the maxLines for a text use mTextView.setMaxLines(0) or you have to programmatic-ally measure of the height text and multiply with the number of max line
The result should set as the height of the textView
if you want to have just a single line , then why don't you use:
txtView.setSingleLine(true);
The -1 should not crash your application. This actually what is used inside TextView by default:
case com.android.internal.R.styleable.TextView_maxLines:
setMaxLines(a.getInt(attr, -1));
break;
This piece of code shows, that when android:maxLines is not specified, then code uses -1 to set the value via setMaxLines() function.
I also made test application to verify my conclusions. And it works fine without crashing:
public class HelloWorld extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
TextView text = (TextView)findViewById(R.id.text);
text.setMaxLines(-1);
}
}

Categories

Resources