1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.text.style; 18 19 import android.annotation.NonNull; 20 import android.annotation.Px; 21 import android.graphics.Canvas; 22 import android.graphics.Paint; 23 import android.graphics.drawable.Drawable; 24 import android.text.Layout; 25 import android.text.Spanned; 26 27 /** 28 * A span which adds a drawable and a padding to the paragraph it's attached to. 29 * <p> 30 * If the height of the drawable is bigger than the height of the line it's attached to then the 31 * line height is increased to fit the drawable. <code>DrawableMarginSpan</code> allows setting a 32 * padding between the drawable and the text. The default value is 0. The span must be set from the 33 * beginning of the text, otherwise either the span won't be rendered or it will be rendered 34 * incorrectly. 35 * <p> 36 * For example, a drawable and a padding of 20px can be added like this: 37 * <pre>{@code SpannableString string = new SpannableString("Text with a drawable."); 38 * string.setSpan(new DrawableMarginSpan(drawable, 20), 0, string.length(), 39 * Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre> 40 * <img src="{@docRoot}reference/android/images/text/style/drawablemarginspan.png" /> 41 * <figcaption>Text with a drawable and a padding.</figcaption> 42 * <p> 43 * 44 * @see IconMarginSpan for working with a {@link android.graphics.Bitmap} instead of 45 * a {@link Drawable}. 46 */ 47 public class DrawableMarginSpan implements LeadingMarginSpan, LineHeightSpan { 48 private static final int STANDARD_PAD_WIDTH = 0; 49 50 @NonNull 51 private final Drawable mDrawable; 52 @Px 53 private final int mPad; 54 55 /** 56 * Creates a {@link DrawableMarginSpan} from a {@link Drawable}. The pad width will be 0. 57 * 58 * @param drawable the drawable to be added 59 */ DrawableMarginSpan(@onNull Drawable drawable)60 public DrawableMarginSpan(@NonNull Drawable drawable) { 61 this(drawable, STANDARD_PAD_WIDTH); 62 } 63 64 /** 65 * Creates a {@link DrawableMarginSpan} from a {@link Drawable} and a padding, in pixels. 66 * 67 * @param drawable the drawable to be added 68 * @param pad the distance between the drawable and the text 69 */ DrawableMarginSpan(@onNull Drawable drawable, int pad)70 public DrawableMarginSpan(@NonNull Drawable drawable, int pad) { 71 mDrawable = drawable; 72 mPad = pad; 73 } 74 75 @Override getLeadingMargin(boolean first)76 public int getLeadingMargin(boolean first) { 77 return mDrawable.getIntrinsicWidth() + mPad; 78 } 79 80 @Override drawLeadingMargin(@onNull Canvas c, @NonNull Paint p, int x, int dir, int top, int baseline, int bottom, @NonNull CharSequence text, int start, int end, boolean first, @NonNull Layout layout)81 public void drawLeadingMargin(@NonNull Canvas c, @NonNull Paint p, int x, int dir, 82 int top, int baseline, int bottom, 83 @NonNull CharSequence text, int start, int end, 84 boolean first, @NonNull Layout layout) { 85 int st = ((Spanned) text).getSpanStart(this); 86 int ix = (int) x; 87 int itop = (int) layout.getLineTop(layout.getLineForOffset(st)); 88 89 int dw = mDrawable.getIntrinsicWidth(); 90 int dh = mDrawable.getIntrinsicHeight(); 91 92 // XXX What to do about Paint? 93 mDrawable.setBounds(ix, itop, ix + dw, itop + dh); 94 mDrawable.draw(c); 95 } 96 97 @Override chooseHeight(@onNull CharSequence text, int start, int end, int istartv, int v, @NonNull Paint.FontMetricsInt fm)98 public void chooseHeight(@NonNull CharSequence text, int start, int end, 99 int istartv, int v, 100 @NonNull Paint.FontMetricsInt fm) { 101 if (end == ((Spanned) text).getSpanEnd(this)) { 102 int ht = mDrawable.getIntrinsicHeight(); 103 104 int need = ht - (v + fm.descent - fm.ascent - istartv); 105 if (need > 0) { 106 fm.descent += need; 107 } 108 109 need = ht - (v + fm.bottom - fm.top - istartv); 110 if (need > 0) { 111 fm.bottom += need; 112 } 113 } 114 } 115 116 @Override toString()117 public String toString() { 118 return "DrawableMarginSpan{drawable=" + mDrawable + ", padding=" + mPad + '}'; 119 } 120 121 /** 122 * Returns the drawable used. 123 * @return a drawable 124 */ getDrawable()125 @NonNull public Drawable getDrawable() { 126 return mDrawable; 127 } 128 129 /** 130 * Returns a distance between the drawable and text in pixel. 131 * @return a distance pixel from the text 132 */ getPadding()133 @Px public int getPadding() { 134 return mPad; 135 } 136 } 137