android - How to fit multiline text inside a TextView using a custom font? -


i'm using api 10.

i stuck days. searched stackoverflow , tried ton of classes.

i wanted fit multiline text inside textview bounds default font. used class below , worked wonders, , not 1 one device, on all devices. same. code this, found in stackoverflow:

/**  * class builds new android widget named autofittext can used instead of textview  * have text font size in automatically fit match screen width. credits go largely  * dunni, gjpc, gregm , speedplane stackoverflow, method has been (style-) optimized ,  * rewritten match android coding standards , our mbc. version upgrades original  * "autofittextview" adaptable height , accept different textview types  * (button, textclock etc.)  *  * @author pheuschk  * @createdate: 18.04.2013  */ @suppresswarnings("unused") public class autofittext extends textview {      /** global min , max text size. remember: values in pixels! */     private final int min_text_size = 10;     private final int max_text_size = 400;      /** flag singleline */     private boolean msingleline = false;      /**      * dummy {@link textview} test text size without showing user      */     private textview mtestview;      /**      * dummy {@link paint} test text size without showing user      */     private paint mtestpaint;      /**      * scaling factor fonts. it's method of calculating independently (!) actual      * density of screen used users have same experience on different devices.      * use displaymetrics in constructor value of factor , calculate      * sp pixel values      */     private final float mscaleddensityfactor;      /**      * defines how close want to factual size of text-field. lower values mean      * higher precision exponentially higher computing cost (more loop runs)      */     private final float mthreshold = 0.5f;      /**      * constructor call without attributes --> invoke constructor attributeset null      *      * @param context      */     public autofittext(context context) {         this(context, null);     }      public autofittext(context context, attributeset attrs) {         super(context, attrs);          mscaleddensityfactor = context.getresources().getdisplaymetrics().scaleddensity;         mtestview = new textview(context);          mtestpaint = new paint();         mtestpaint.set(this.getpaint());          this.getviewtreeobserver().addongloballayoutlistener(new ongloballayoutlistener() {              @suppresswarnings("deprecation")             @override             public void ongloballayout() {                 // make initial call onsizechanged make sure refittext triggered                 onsizechanged(autofittext.this.getwidth(), autofittext.this.getheight(), 0, 0);                 // remove layoutlistener don't run infinite loop                 autofittext.this.getviewtreeobserver().removeglobalonlayoutlistener(this);             }         });     }      /**      * main method of widget. resizes font specified text fits in text box      * assuming text box has specified width. done via dummy text view      * refit until matches real target width , height threshold factor      *      * @param targetfieldwidth      *            width textview has , wants filled      * @param targetfieldheight      *            width textview has , wants filled      */     private void refittext(string text, int targetfieldwidth, int targetfieldheight) {          // variables need visible outside loops later use. remember size in pixels         float lowertextsize = min_text_size;         float uppertextsize = max_text_size;          // force text wrap. in principle not necessary since dummy textview         // in rare cases adding line can prevent flickering         this.setmaxwidth(targetfieldwidth);          // padding should not issue since never define programmatically in app         // to sure cut off here         targetfieldwidth = targetfieldwidth - this.getpaddingleft() - this.getpaddingright();         targetfieldheight = targetfieldheight - this.getpaddingtop() - this.getpaddingbottom();          // initialize dummy params (that largely ignored anyway,         // mandatory not nullpointerexception)         mtestview.setlayoutparams(new layoutparams(targetfieldwidth, targetfieldheight));          // maxwidth crucial! otherwise text never line wrap blow width         mtestview.setmaxwidth(targetfieldwidth);          if (msingleline) {             // user requested single line. easy since need             // respect width, don't have break, don't have measure...              /*************************** converging algorithm 1 ***********************************/             (float testsize; (uppertextsize - lowertextsize) > mthreshold;) {                  // go mean value...                 testsize = (uppertextsize + lowertextsize) / 2;                  mtestview.settextsize(typedvalue.complex_unit_sp, testsize / mscaleddensityfactor);                 mtestview.settext(text);                 mtestview.measure(measurespec.unspecified, measurespec.unspecified);                  if (mtestview.getmeasuredwidth() >= targetfieldwidth) {                     uppertextsize = testsize; // font big, decrease uppersize                 }                 else {                     lowertextsize = testsize; // font small, increase lowersize                 }             }             /**************************************************************************************/              // in rare cases little letters , width > height have vertical overlap!             mtestview.measure(measurespec.unspecified, measurespec.unspecified);              if (mtestview.getmeasuredheight() > targetfieldheight) {                 uppertextsize = lowertextsize;                 lowertextsize = min_text_size;                  /*************************** converging algorithm 1.5 *****************************/                 (float testsize; (uppertextsize - lowertextsize) > mthreshold;) {                      // go mean value...                     testsize = (uppertextsize + lowertextsize) / 2;                      mtestview.settextsize(typedvalue.complex_unit_sp, testsize                             / mscaleddensityfactor);                     mtestview.settext(text);                     mtestview.measure(measurespec.unspecified, measurespec.unspecified);                      if (mtestview.getmeasuredheight() >= targetfieldheight) {                         uppertextsize = testsize; // font big, decrease uppersize                     }                     else {                         lowertextsize = testsize; // font small, increase lowersize                     }                 }                 /**********************************************************************************/             }         }         else {              /*********************** converging algorithm 2 ***************************************/             // upper , lower size converge on time. they're close enough loop             // stops             // todo probe algorithm cost (atm possibly o(n^2)) , optimize if possible             (float testsize; (uppertextsize - lowertextsize) > mthreshold;) {                  // go mean value...                 testsize = (uppertextsize + lowertextsize) / 2;                  // ... inflate dummy textview setting scaled textsize , text...                 mtestview.settextsize(typedvalue.complex_unit_sp, testsize / mscaleddensityfactor);                 mtestview.settext(text);                  // ... call measure find current values text wants occupy                 mtestview.measure(measurespec.unspecified, measurespec.unspecified);                 int tempheight = mtestview.getmeasuredheight();                 // int tempwidth = mtestview.getmeasuredwidth();                  // log.debug("measured: " + tempwidth + "x" + tempheight);                 // log.debug("textsize: " + testsize / mscaleddensityfactor);                  // ... decide whether values appropriate.                 if (tempheight >= targetfieldheight) {                     uppertextsize = testsize; // font big, decrease uppersize                 }                 else {                     lowertextsize = testsize; // font small, increase lowersize                 }             }             /**************************************************************************************/              // possible single word wider box. android system             // wrap us. if want decide fo break or             // add hyphen or you're going want implement this:             mtestpaint.settextsize(lowertextsize);             list<string> words = new arraylist<string>();              (string s : text.split(" ")) {                 log.i("tag", "word: " + s);                 words.add(s);             }                         (string word : words) {                 if (mtestpaint.measuretext(word) >= targetfieldwidth) {                     list<string> pieces = new arraylist<string>();                     // pieces = breakword(word, mtestpaint.measuretext(word), targetfieldwidth);                      // add code handle pieces here...                 }             }         }          /**          * @ value of threshold away actual size. rather undershoot          * overshoot use lower value. match different screens convert sp first. see          * {@link http://developer.android.com/guide/topics/resources/more-resources.html#dimension}          * more details          */         this.settextsize(typedvalue.complex_unit_sp, lowertextsize / mscaleddensityfactor);         return;     }      /**      * method receives call upon change in text content of textview. unfortunately      * called - among others - upon text size change means must never call      * {@link #refittext(string)} method! doing result in endless loop      * result in stack overflow , termination of application      *      * time being method absolutely nothing. if want notify view of      * changed text call {@link #settext(charsequence)}      */     @override     protected void ontextchanged(charsequence text, int start, int lengthbefore, int lengthafter) {         // super implementation intentionally empty absolutely nothing here         super.ontextchanged(text, start, lengthbefore, lengthafter);     }      @override     protected void onsizechanged(int width, int height, int oldwidth, int oldheight) {         if (width != oldwidth && height != oldheight) {             refittext(this.gettext().tostring(), width, height);         }     }      /**      * method guaranteed called {@link textview#settext(charsequence)} immediately.      * therefore can safely add our modifications here , have parent class resume      * work. if text has changed should call {@link textview#settext(charsequence)} or      * {@link textview#settext(charsequence, buffertype)} if know whether {@link buffertype}      * normal, editable or spannable. note: method default {@link buffertype#normal}      * if don't pass argument.      */     @override     public void settext(charsequence text, buffertype type) {          int targetfieldwidth = this.getwidth();         int targetfieldheight = this.getheight();          if (targetfieldwidth <= 0 || targetfieldheight <= 0 || text.equals("")) {             // log.v("tag", "some values empty, autofittext not able construct properly");         }         else {             refittext(text.tostring(), targetfieldwidth, targetfieldheight);         }         super.settext(text, type);     }      /**      * todo add sensibility {@link #setmaxlines(int)} invocations      */     @override     public void setmaxlines(int maxlines) {         // todo implement support this. relatively easy. idea         // manipulate targetheight in refittext-method , have algorithm         // job business usual. nonetheless, remember height have lowered         // dynamically font size shrinks won't walk in park still         if (maxlines == 1) {             this.setsingleline(true);         }         else {             throw new unsupportedoperationexception(                     "maxlines != 1 not implemented in autofittext yet, use textview instead");         }     }      @override     public void setsingleline(boolean singleline) {         // save requested value in instance variable able decide later         msingleline = singleline;         super.setsingleline(singleline);     } } 

the text shrunk needed fit textview bounds.

but want use custom font. imported custom font , went wrong. can see in image below doesn't fit anymore. text doesn't shrink fit.

custom font auto fix problem

so, have idea how handle this? have faced similar problem custom fonts?

please enough reputation, enable image.

you need set current fontface testtextview. solved problem.

private void refittext(string text, int targetfieldwidth, int targetfieldheight) {          //         // bla bla bla codes         //          //         // fix         // put current typeface of textview test-textview         mtestview.settypeface(gettypeface());          // initialize dummy params (that largely ignored anyway,         // mandatory not nullpointerexception)         mtestview.setlayoutparams(new layoutparams(targetfieldwidth, targetfieldheight));          // maxwidth crucial! otherwise text never line wrap blow width         mtestview.setmaxwidth(targetfieldwidth);          if (msingleline) { 

Comments

Popular posts from this blog

SPSS keyboard combination alters encoding -

Add new record to the table by click on the button in Microsoft Access -

javascript - jQuery .height() return 0 when visible but non-0 when hidden -