So, having spent the obligatory five hours trying to figure out how
android wanted me to do it (other than just "don't do that!"), I ended
up writing this bit of code to do what I actually WANTED.

It's not too bad except for the one section which needs to be made a
lot more efficient.

In case it helps anyone else, I post it here.  I would still like to
hear about the 'right way' to do it.

        public void drawTextInRect( Canvas canvas, Paint paint, Rect r,
CharSequence text ) {
                // ok, I have to do it all myself, pity me!

                // initial text range and starting position
                int start = 0;
                int end   = text.length() - 1;
                float     x = r.left;
                float     y = r.top;
                int allowedWidth = r.width();   // constrain text block within 
this
width in pixels
                if( allowedWidth < 30 ) {
                        return;  // you have got to be kidding me!  I can't 
work with
this!  You deserve worse!
                }

                // get the distance in pixels between two lines of text
                int lineHeight = paint.getFontMetricsInt( null );

                // emit one line at a time, as much as will fit, with word wrap 
on
whitespace.
                while( start < end ) {
                        int charactersRemaining                 = end - start + 
1;
                        int charactersToRenderThisPass  = charactersRemaining;  
//
optimism!
                        int extraSkip                   = 0;

                        // This 'while' is nothing to be proud of.
                        // This should probably be a binary search or more 
googling to
                        // find "character index at distance N pixels in string"
                        while( charactersToRenderThisPass > 0
                           && paint.measureText(text, start, start
+charactersToRenderThisPass ) > allowedWidth ) {
                                // remaining text won't fit, cut one character 
from the end and
check again
                                charactersToRenderThisPass--;
                        }

                        // charactersToRenderThisPass would definitely fit, but 
could be in
the middle of a word
                        int thisManyWouldDefinitelyFit = 
charactersToRenderThisPass;
                        if( charactersToRenderThisPass < charactersRemaining ) {
                                while( charactersToRenderThisPass > 0
                                        && !Character.isWhitespace( 
text.charAt( start
+charactersToRenderThisPass-1) ) ) {
                                        charactersToRenderThisPass--;   // good 
bye character that would
have fit!
                                }
                        }

                        // Now wouldn't it be nice to be able to put in line 
breaks?
                        int i;
                        for( i=0; i<charactersToRenderThisPass; i++ ) {
                                if( text.charAt( start+i ) == '\n' ) {  // um, 
what's unicode for
'isLineBreak' or '\n'?
                                        // cool, lets stop this line early
                                        charactersToRenderThisPass = i;
                                        extraSkip = 1;  // so we don't start 
next line with the lineBreak
character
                                        break;
                                }
                        }

                        if( charactersToRenderThisPass < 1 && (extraSkip == 0)) 
{
                                // no spaces found, must be a really long word.
                                // Panic and show as much as would fit, 
breaking the word in the
middle
                                charactersToRenderThisPass = 
thisManyWouldDefinitelyFit;
                        }

                        // Emit this line of characters and advance our offsets 
for the
next line
                        if( charactersToRenderThisPass > 0 ) {
                                canvas.drawText( text, start, 
start+charactersToRenderThisPass, x,
y, paint );
                        }
                        start    += charactersToRenderThisPass + extraSkip;
                        y        += lineHeight;

                        // start had better advance each time through the 
while, or we've
invented an infinite loop
                        if( (charactersToRenderThisPass + extraSkip) < 1 ) {
                                return; // better than freezing, I guess.  I am 
a coward.
                        }
                }

                // write google a letter asking why I couldn't find this as an
existing function
                // after doing a LOT of googling.  Is my phone going to explode?
        }
-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to