Android - Add Margin for SpannableStringBuilder using ReplacementSpan

前端 未结 3 1364
面向向阳花
面向向阳花 2021-02-09 19:51

I\'m trying to format Hashtags inside a TextView/EditText (Say like Chips mentioned in the Material Design Specs). I\'m able to format the background using ReplacementSpan

3条回答
  •  情话喂你
    2021-02-09 20:25

    Text markup in Android is so poorly documented, writing this code is like feeling your way through the dark.

    I've done a little bit of it, so I will share what I know.

    You can handle line spacing by wrapping your chip spans inside a LineHeightSpan. LineHeightSpan is an interface that extends the ParagraphStyle marker interface, so this tells you it affects appearance at a paragraph level. Maybe a good way to explain it is to compare your ReplacementSpan subclass to an HTML , whereas a ParagraphStyle span like LineHeightSpan is like an HTML

    .

    The LineHeightSpan interface consists of one method:

    public void chooseHeight(CharSequence text, int start, int end,
                             int spanstartv, int v,
                             Paint.FontMetricsInt fm);
    

    This method is called for each line in your paragraph

    • text is your Spanned string.
    • start is the index of the character at the start of the current line
    • end is the index of the character at the end of the current line
    • spanstartv is (IIRC) the vertical offset of the entire span itself
    • v is (IIRC) the vertical offset of the current line
    • fm is the FontMetrics object, which is actually a returned (in/out) parameter. Your code will make changes to fm and TextView will use those when drawing.

    So what the TextView will do is call this method once for every line it processes. Based on the parameters, along with your Spanned string, you set up the FontMetrics to render the line with the values of your choosing.

    Here's an example I did for a bullet item in a list (think

    1. ) where I wanted some separation between each list item:

          @Override
          public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fm) {
      
              int incr = Math.round(.36F * fm.ascent); // note: ascent is negative
      
              // first line: add space to the top
              if (((Spanned) text).getSpanStart(this) == start) {
                  fm.ascent += incr;
                  fm.top = fm.ascent + 1;
              }
      
              // last line: add space to the bottom
              if (((Spanned) text).getSpanEnd(this) == end) {
                  fm.bottom -= incr;
              }
      
          }
      

      Your version will probably be even simpler, just changing the FontMetrics the same way for each line that it's called.

      When it comes to deciphering the FontMetrics, the logger and debugger are your friends. You'll just have to keep tweaking values until you get something you like.

提交回复
热议问题