1

I'm trying to make a textview that scales the contents so that it all shows, no cropping, multi lines or elipsis.

I'll quickly run through the layout just to put it into context.

*There's a gridview with several rows and columns. *The items for the gridview are provided by an adapter which returns (pseudo markup :) ):-

<LinearLayout Orientation=vertical> <MyCustomTextview name='titletext' Not multiline /> <MyCustomTextview name='itemtext' Not multiline /> </LinearLayout> 

I've tried overriding onSizeChanged as this is where several google results pointed me and I started with:-

... if (this.getLinecount() > 1) { this.setTextSize(... currentsize -10); } ... 

and this gave me really small text where it would have appeared on more than one line, so I knew I could resize and find out if the TextView had more than one line correctly.

so I progressed to:-

while (this.getLinecount() > 1) { this.setTextSize(... currentsize - 1); } 

which I expected to run until the text was small enough, but after the call to setTextSize getLineCount() returns 0, I believe this is because it needs to recalculate the text size so I tried various combinations of refreshLayout(), forceLayout() and invalidate() to no avail.

I've an idea for perhaps a better approach, but I don't know if it's easily attainable:-

onSizeChanged is called after it is put into the Gridview by the Adapter so I will execute my code there, but is the following possible and how:-

  • The TextView is set to a width of fill parent, can I accurately tell a pixel size of the width of available space for text? (I believe there may be padding and such applied)
  • I then intend to use measureText(String) to see if the text will fit, if not decrease size and check again.

I believe that would be a good solution, but I'm not sure on the accurate measurement of available space, and if the event I've chosen would be best.

Any assistance would be appreciated.

  • Anthony
1

2 Answers 2

1

You do not need to create Custom Text View for this. Use ViewTreeObserver to get the required functionality.

TextView tv = (TextView)findViewById(R.id.mytextview); ViewTreeObserver vto = tv.getViewTreeObserver(); vto.addOnGlobalLayoutListener(this); @Override public void onGlobalLayout() { if (1 < tv.getLineCount()) { tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() - 2); } } 
Sign up to request clarification or add additional context in comments.

6 Comments

Will this code also "loop", i.e. onGlobalLayout gets called over and over until the test fits?
Yes it will, the reason is that unless the views are drawn you will never get the actual size. This code works dynamically in that it reduces the size iteratively till it fits a single line.
Does this code result in the text being painted on screen several times before the correct size is reached?
Theoretically it does but would be very difficult to discern for the Human Eye. It gets done very quickly for you to notice.
I just tried this, and although it works, it is definitely noticeable to the user. I tried on a Galaxy Nexus running 4.2.2, without logcat hooked up.
|
0

Why don't you try the same sort of approach, but use measureText instead?

while (mPaint.measureText(MyTextString)>mTextView.getWidth() ) //maybe adjust for padding/margins etc { mPaint.setTextSize(... currentsize - 1); } 

6 Comments

Sorry -- just saw you've mentioned this already. But that would be my approach.
Hi, this is the preferred aproach for me, the specific issue I have with this method is I'm unsure how to adjust for margins and padding (My understanding is getWidth() returns the external size of the TextView not the internal usable space) I see your code is commented with this in mind, do you happen to know what would be the best / most accurate way to determine usable space within a textbox? (In hindsight, I should have titled my question as such).
I'm not sure, actually :) But I also like @PravinCG's answer. However, I'm thinking a hybrid approach might be best. You use the ViewTreeObserver to trigger the resizing if ever the text changes, but you use MeasureText to calculate the right fontsize once and for all. BTW You obviously also have to check for the case where even at font-size 1, it still doesn't fit on one line and make some other plan there
int availableWidth = (int) (textWidth - tv.getPaddingLeft() - tv.getPaddingRight()); seems to be the best way to measure the available space:- My understanding is that onSizeChanged should fire if the area available to the TextView changes, for example an orientation change. So if I override onSizeChanged, and within that get the painter, use that to measure text, decrease size, repeat if required, then once the right size is found set the textview's size to that, I think that would do it, though I'm sure I'm going to find it won't work when I try :)
Sorry, int availableWidth = (int) (tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight());
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.