Updating more spans

Test: N/A
Bug: 72092996
Change-Id: Iecd3595a03cde2a1d58e4be00b7cf9b6783d4e2a
This commit is contained in:
Florina Muntenescu
2018-01-24 15:52:00 +00:00
parent 6e39b9556a
commit 139e1b5c01
19 changed files with 509 additions and 154 deletions

View File

@@ -16,60 +16,100 @@
package android.text.style;
import android.annotation.NonNull;
import android.annotation.Px;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.Spanned;
public class DrawableMarginSpan
implements LeadingMarginSpan, LineHeightSpan
{
public DrawableMarginSpan(Drawable b) {
mDrawable = b;
/**
* A span which adds a drawable and a padding to the paragraph it's attached to.
* <p>
* If the height of the drawable is bigger than the height of the line it's attached to then the
* line height is increased to fit the drawable. <code>DrawableMarginSpan</code> allows setting a
* padding between the drawable and the text. The default value is 0. The span must be set from the
* beginning of the text, otherwise either the span won't be rendered or it will be rendered
* incorrectly.
* <p>
* For example, a drawable and a padding of 20px can be added like this:
* <pre>{@code SpannableString string = new SpannableString("Text with a drawable.");
* string.setSpan(new DrawableMarginSpan(drawable, 20), 0, string.length(),
* Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
* <img src="{@docRoot}reference/android/images/text/style/drawablemarginspan.png" />
* <figcaption>Text with a drawable and a padding.</figcaption>
* <p>
*
* @see IconMarginSpan for working with a {@link android.graphics.Bitmap} instead of
* a {@link Drawable}.
*/
public class DrawableMarginSpan implements LeadingMarginSpan, LineHeightSpan {
private static final int STANDARD_PAD_WIDTH = 0;
@NonNull
private final Drawable mDrawable;
@Px
private final int mPad;
/**
* Creates a {@link DrawableMarginSpan} from a {@link Drawable}. The pad width will be 0.
*
* @param drawable the drawable to be added
*/
public DrawableMarginSpan(@NonNull Drawable drawable) {
this(drawable, STANDARD_PAD_WIDTH);
}
public DrawableMarginSpan(Drawable b, int pad) {
mDrawable = b;
/**
* Creates a {@link DrawableMarginSpan} from a {@link Drawable} and a padding, in pixels.
*
* @param drawable the drawable to be added
* @param pad the distance between the drawable and the text
*/
public DrawableMarginSpan(@NonNull Drawable drawable, int pad) {
mDrawable = drawable;
mPad = pad;
}
@Override
public int getLeadingMargin(boolean first) {
return mDrawable.getIntrinsicWidth() + mPad;
}
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir,
int top, int baseline, int bottom,
CharSequence text, int start, int end,
boolean first, Layout layout) {
@Override
public void drawLeadingMargin(@NonNull 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) {
int st = ((Spanned) text).getSpanStart(this);
int ix = (int)x;
int itop = (int)layout.getLineTop(layout.getLineForOffset(st));
int ix = (int) x;
int itop = (int) layout.getLineTop(layout.getLineForOffset(st));
int dw = mDrawable.getIntrinsicWidth();
int dh = mDrawable.getIntrinsicHeight();
// XXX What to do about Paint?
mDrawable.setBounds(ix, itop, ix+dw, itop+dh);
mDrawable.setBounds(ix, itop, ix + dw, itop + dh);
mDrawable.draw(c);
}
public void chooseHeight(CharSequence text, int start, int end,
int istartv, int v,
Paint.FontMetricsInt fm) {
@Override
public void chooseHeight(@NonNull CharSequence text, int start, int end,
int istartv, int v,
@NonNull Paint.FontMetricsInt fm) {
if (end == ((Spanned) text).getSpanEnd(this)) {
int ht = mDrawable.getIntrinsicHeight();
int need = ht - (v + fm.descent - fm.ascent - istartv);
if (need > 0)
if (need > 0) {
fm.descent += need;
}
need = ht - (v + fm.bottom - fm.top - istartv);
if (need > 0)
if (need > 0) {
fm.bottom += need;
}
}
}
private Drawable mDrawable;
private int mPad;
}

View File

@@ -16,6 +16,9 @@
package android.text.style;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
@@ -24,32 +27,71 @@ import android.graphics.drawable.Drawable;
import java.lang.ref.WeakReference;
/**
* Span that replaces the text it's attached to with a {@link Drawable} that can be aligned with
* the bottom or with the baseline of the surrounding text.
* <p>
* For an implementation that constructs the drawable from various sources (<code>Bitmap</code>,
* <code>Drawable</code>, resource id or <code>Uri</code>) use {@link ImageSpan}.
* <p>
* A simple implementation of <code>DynamicDrawableSpan</code> that uses drawables from resources
* looks like this:
* <pre>
* class MyDynamicDrawableSpan extends DynamicDrawableSpan {
*
* private final Context mContext;
* private final int mResourceId;
*
* public MyDynamicDrawableSpan(Context context, @DrawableRes int resourceId) {
* mContext = context;
* mResourceId = resourceId;
* }
*
* {@literal @}Override
* public Drawable getDrawable() {
* Drawable drawable = mContext.getDrawable(mResourceId);
* drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
* return drawable;
* }
* }</pre>
* The class can be used like this:
* <pre>
* SpannableString string = new SpannableString("Text with a drawable span");
* string.setSpan(new MyDynamicDrawableSpan(context, R.mipmap.ic_launcher), 12, 20, Spanned
* .SPAN_EXCLUSIVE_EXCLUSIVE);</pre>
* <img src="{@docRoot}reference/android/images/text/style/dynamicdrawablespan.png" />
* <figcaption>Replacing text with a drawable.</figcaption>
*/
public abstract class DynamicDrawableSpan extends ReplacementSpan {
private static final String TAG = "DynamicDrawableSpan";
/**
* A constant indicating that the bottom of this span should be aligned
* with the bottom of the surrounding text, i.e., at the same level as the
* lowest descender in the text.
*/
public static final int ALIGN_BOTTOM = 0;
/**
* A constant indicating that the bottom of this span should be aligned
* with the baseline of the surrounding text.
*/
public static final int ALIGN_BASELINE = 1;
protected final int mVerticalAlignment;
private WeakReference<Drawable> mDrawableRef;
/**
* Creates a {@link DynamicDrawableSpan}. The default vertical alignment is
* {@link #ALIGN_BOTTOM}
*/
public DynamicDrawableSpan() {
mVerticalAlignment = ALIGN_BOTTOM;
}
/**
* @param verticalAlignment one of {@link #ALIGN_BOTTOM} or {@link #ALIGN_BASELINE}.
* Creates a {@link DynamicDrawableSpan} based on a vertical alignment.\
*
* @param verticalAlignment one of {@link #ALIGN_BOTTOM} or {@link #ALIGN_BASELINE}
*/
protected DynamicDrawableSpan(int verticalAlignment) {
mVerticalAlignment = verticalAlignment;
@@ -64,22 +106,22 @@ public abstract class DynamicDrawableSpan extends ReplacementSpan {
}
/**
* Your subclass must implement this method to provide the bitmap
* Your subclass must implement this method to provide the bitmap
* to be drawn. The dimensions of the bitmap must be the same
* from each call to the next.
*/
public abstract Drawable getDrawable();
@Override
public int getSize(Paint paint, CharSequence text,
int start, int end,
Paint.FontMetricsInt fm) {
public int getSize(@NonNull Paint paint, CharSequence text,
@IntRange(from = 0) int start, @IntRange(from = 0) int end,
@Nullable Paint.FontMetricsInt fm) {
Drawable d = getCachedDrawable();
Rect rect = d.getBounds();
if (fm != null) {
fm.ascent = -rect.bottom;
fm.descent = 0;
fm.ascent = -rect.bottom;
fm.descent = 0;
fm.top = fm.ascent;
fm.bottom = 0;
@@ -89,12 +131,12 @@ public abstract class DynamicDrawableSpan extends ReplacementSpan {
}
@Override
public void draw(Canvas canvas, CharSequence text,
int start, int end, float x,
int top, int y, int bottom, Paint paint) {
public void draw(@NonNull Canvas canvas, CharSequence text,
@IntRange(from = 0) int start, @IntRange(from = 0) int end, float x,
int top, int y, int bottom, @NonNull Paint paint) {
Drawable b = getCachedDrawable();
canvas.save();
int transY = bottom - b.getBounds().bottom;
if (mVerticalAlignment == ALIGN_BASELINE) {
transY -= paint.getFontMetricsInt().descent;
@@ -109,8 +151,9 @@ public abstract class DynamicDrawableSpan extends ReplacementSpan {
WeakReference<Drawable> wr = mDrawableRef;
Drawable d = null;
if (wr != null)
if (wr != null) {
d = wr.get();
}
if (d == null) {
d = getDrawable();
@@ -119,7 +162,5 @@ public abstract class DynamicDrawableSpan extends ReplacementSpan {
return d;
}
private WeakReference<Drawable> mDrawableRef;
}

View File

@@ -16,57 +16,98 @@
package android.text.style;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Px;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Layout;
import android.text.Spanned;
public class IconMarginSpan
implements LeadingMarginSpan, LineHeightSpan
{
public IconMarginSpan(Bitmap b) {
mBitmap = b;
/**
* Paragraph affecting span, that draws a bitmap at the beginning of a text. The span also allows
* setting a padding between the bitmap and the text. The default value of the padding is 0px. The
* span should be attached from the first character of the text.
* <p>
* For example, an <code>IconMarginSpan</code> with a bitmap and a padding of 30px can be set
* like this:
* <pre>
* SpannableString string = new SpannableString("Text with icon and padding");
* string.setSpan(new IconMarginSpan(bitmap, 30), 0, string.length(),
* Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/iconmarginspan.png" />
* <figcaption>Text with <code>IconMarginSpan</code></figcaption>
* <p>
*
* @see DrawableMarginSpan for working with a {@link android.graphics.drawable.Drawable} instead of
* a {@link Bitmap}.
*/
public class IconMarginSpan implements LeadingMarginSpan, LineHeightSpan {
@NonNull
private final Bitmap mBitmap;
@Px
private final int mPad;
/**
* Creates an {@link IconMarginSpan} from a {@link Bitmap}.
*
* @param bitmap bitmap to be rendered at the beginning of the text
*/
public IconMarginSpan(@NonNull Bitmap bitmap) {
this(bitmap, 0);
}
public IconMarginSpan(Bitmap b, int pad) {
mBitmap = b;
/**
* Creates an {@link IconMarginSpan} from a {@link Bitmap}.
*
* @param bitmap bitmap to be rendered at the beginning of the text
* @param pad padding width, in pixels, between the bitmap and the text
*/
public IconMarginSpan(@NonNull Bitmap bitmap, @IntRange(from = 0) int pad) {
mBitmap = bitmap;
mPad = pad;
}
@Override
public int getLeadingMargin(boolean first) {
return mBitmap.getWidth() + mPad;
}
@Override
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir,
int top, int baseline, int bottom,
CharSequence text, int start, int end,
boolean first, Layout layout) {
int top, int baseline, int bottom,
CharSequence text, int start, int end,
boolean first, Layout layout) {
int st = ((Spanned) text).getSpanStart(this);
int itop = layout.getLineTop(layout.getLineForOffset(st));
if (dir < 0)
if (dir < 0) {
x -= mBitmap.getWidth();
}
c.drawBitmap(mBitmap, x, itop, p);
}
@Override
public void chooseHeight(CharSequence text, int start, int end,
int istartv, int v,
Paint.FontMetricsInt fm) {
int istartv, int v,
Paint.FontMetricsInt fm) {
if (end == ((Spanned) text).getSpanEnd(this)) {
int ht = mBitmap.getHeight();
int need = ht - (v + fm.descent - fm.ascent - istartv);
if (need > 0)
if (need > 0) {
fm.descent += need;
}
need = ht - (v + fm.bottom - fm.top - istartv);
if (need > 0)
if (need > 0) {
fm.bottom += need;
}
}
}
private Bitmap mBitmap;
private int mPad;
}

View File

@@ -17,6 +17,8 @@
package android.text.style;
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -27,18 +29,49 @@ import android.util.Log;
import java.io.InputStream;
/**
* Span that replaces the text it's attached to with a {@link Drawable} that can be aligned with
* the bottom or with the baseline of the surrounding text. The drawable can be constructed from
* varied sources:
* <ul>
* <li>{@link Bitmap} - see {@link #ImageSpan(Context, Bitmap)} and
* {@link #ImageSpan(Context, Bitmap, int)}
* </li>
* <li>{@link Drawable} - see {@link #ImageSpan(Drawable, int)}</li>
* <li>resource id - see {@link #ImageSpan(Context, int, int)}</li>
* <li>{@link Uri} - see {@link #ImageSpan(Context, Uri, int)}</li>
* </ul>
* The default value for the vertical alignment is {@link DynamicDrawableSpan#ALIGN_BOTTOM}
* <p>
* For example, an <code>ImagedSpan</code> can be used like this:
* <pre>
* SpannableString string = SpannableString("Bottom: span.\nBaseline: span.");
* // using the default alignment: ALIGN_BOTTOM
* string.setSpan(ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
* string.setSpan(ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE),
* 22, 23, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/imagespan.png" />
* <figcaption>Text with <code>ImageSpan</code>s aligned bottom and baseline.</figcaption>
*/
public class ImageSpan extends DynamicDrawableSpan {
@Nullable
private Drawable mDrawable;
@Nullable
private Uri mContentUri;
@DrawableRes
private int mResourceId;
@Nullable
private Context mContext;
@Nullable
private String mSource;
/**
* @deprecated Use {@link #ImageSpan(Context, Bitmap)} instead.
*/
@Deprecated
public ImageSpan(Bitmap b) {
public ImageSpan(@NonNull Bitmap b) {
this(null, b, ALIGN_BOTTOM);
}
@@ -46,80 +79,143 @@ public class ImageSpan extends DynamicDrawableSpan {
* @deprecated Use {@link #ImageSpan(Context, Bitmap, int)} instead.
*/
@Deprecated
public ImageSpan(Bitmap b, int verticalAlignment) {
public ImageSpan(@NonNull Bitmap b, int verticalAlignment) {
this(null, b, verticalAlignment);
}
public ImageSpan(Context context, Bitmap b) {
this(context, b, ALIGN_BOTTOM);
/**
* Constructs an {@link ImageSpan} from a {@link Context} and a {@link Bitmap} with the default
* alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}
*
* @param context context used to create a drawable from {@param bitmap} based on the display
* metrics of the resources
* @param bitmap bitmap to be rendered
*/
public ImageSpan(@NonNull Context context, @NonNull Bitmap bitmap) {
this(context, bitmap, ALIGN_BOTTOM);
}
/**
* Constructs an {@link ImageSpan} from a {@link Context}, a {@link Bitmap} and a vertical
* alignment.
*
* @param context context used to create a drawable from {@param bitmap} based on
* the display metrics of the resources
* @param bitmap bitmap to be rendered
* @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
* {@link DynamicDrawableSpan#ALIGN_BASELINE}.
* {@link DynamicDrawableSpan#ALIGN_BASELINE}
*/
public ImageSpan(Context context, Bitmap b, int verticalAlignment) {
public ImageSpan(@NonNull Context context, @NonNull Bitmap bitmap, int verticalAlignment) {
super(verticalAlignment);
mContext = context;
mDrawable = context != null
? new BitmapDrawable(context.getResources(), b)
: new BitmapDrawable(b);
? new BitmapDrawable(context.getResources(), bitmap)
: new BitmapDrawable(bitmap);
int width = mDrawable.getIntrinsicWidth();
int height = mDrawable.getIntrinsicHeight();
mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0);
}
public ImageSpan(Drawable d) {
this(d, ALIGN_BOTTOM);
mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0);
}
/**
* @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
* {@link DynamicDrawableSpan#ALIGN_BASELINE}.
* Constructs an {@link ImageSpan} from a drawable with the default
* alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}.
*
* @param drawable drawable to be rendered
*/
public ImageSpan(Drawable d, int verticalAlignment) {
super(verticalAlignment);
mDrawable = d;
}
public ImageSpan(Drawable d, String source) {
this(d, source, ALIGN_BOTTOM);
public ImageSpan(@NonNull Drawable drawable) {
this(drawable, ALIGN_BOTTOM);
}
/**
* Constructs an {@link ImageSpan} from a drawable and a vertical alignment.
*
* @param drawable drawable to be rendered
* @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
* {@link DynamicDrawableSpan#ALIGN_BASELINE}.
* {@link DynamicDrawableSpan#ALIGN_BASELINE}
*/
public ImageSpan(Drawable d, String source, int verticalAlignment) {
public ImageSpan(@NonNull Drawable drawable, int verticalAlignment) {
super(verticalAlignment);
mDrawable = d;
mDrawable = drawable;
}
/**
* Constructs an {@link ImageSpan} from a drawable and a source with the default
* alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}
*
* @param drawable drawable to be rendered
* @param source drawable's Uri source
*/
public ImageSpan(@NonNull Drawable drawable, @NonNull String source) {
this(drawable, source, ALIGN_BOTTOM);
}
/**
* Constructs an {@link ImageSpan} from a drawable, a source and a vertical alignment.
*
* @param drawable drawable to be rendered
* @param source drawable's uri source
* @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
* {@link DynamicDrawableSpan#ALIGN_BASELINE}
*/
public ImageSpan(@NonNull Drawable drawable, @NonNull String source, int verticalAlignment) {
super(verticalAlignment);
mDrawable = drawable;
mSource = source;
}
public ImageSpan(Context context, Uri uri) {
/**
* Constructs an {@link ImageSpan} from a {@link Context} and a {@link Uri} with the default
* alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}. The Uri source can be retrieved via
* {@link #getSource()}
*
* @param context context used to create a drawable from {@param bitmap} based on the display
* metrics of the resources
* @param uri {@link Uri} used to construct the drawable that will be rendered
*/
public ImageSpan(@NonNull Context context, @NonNull Uri uri) {
this(context, uri, ALIGN_BOTTOM);
}
/**
* Constructs an {@link ImageSpan} from a {@link Context}, a {@link Uri} and a vertical
* alignment. The Uri source can be retrieved via {@link #getSource()}
*
* @param context context used to create a drawable from {@param bitmap} based on
* the display
* metrics of the resources
* @param uri {@link Uri} used to construct the drawable that will be rendered.
* @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
* {@link DynamicDrawableSpan#ALIGN_BASELINE}.
* {@link DynamicDrawableSpan#ALIGN_BASELINE}
*/
public ImageSpan(Context context, Uri uri, int verticalAlignment) {
public ImageSpan(@NonNull Context context, @NonNull Uri uri, int verticalAlignment) {
super(verticalAlignment);
mContext = context;
mContentUri = uri;
mSource = uri.toString();
}
public ImageSpan(Context context, @DrawableRes int resourceId) {
/**
* Constructs an {@link ImageSpan} from a {@link Context} and a resource id with the default
* alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}
*
* @param context context used to retrieve the drawable from resources
* @param resourceId drawable resource id based on which the drawable is retrieved
*/
public ImageSpan(@NonNull Context context, @DrawableRes int resourceId) {
this(context, resourceId, ALIGN_BOTTOM);
}
/**
* Constructs an {@link ImageSpan} from a {@link Context}, a resource id and a vertical
* alignment.
*
* @param context context used to retrieve the drawable from resources
* @param resourceId drawable resource id based on which the drawable is retrieved.
* @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
* {@link DynamicDrawableSpan#ALIGN_BASELINE}.
* {@link DynamicDrawableSpan#ALIGN_BASELINE}
*/
public ImageSpan(Context context, @DrawableRes int resourceId, int verticalAlignment) {
public ImageSpan(@NonNull Context context, @DrawableRes int resourceId,
int verticalAlignment) {
super(verticalAlignment);
mContext = context;
mResourceId = resourceId;
@@ -128,10 +224,10 @@ public class ImageSpan extends DynamicDrawableSpan {
@Override
public Drawable getDrawable() {
Drawable drawable = null;
if (mDrawable != null) {
drawable = mDrawable;
} else if (mContentUri != null) {
} else if (mContentUri != null) {
Bitmap bitmap = null;
try {
InputStream is = mContext.getContentResolver().openInputStream(
@@ -142,7 +238,7 @@ public class ImageSpan extends DynamicDrawableSpan {
drawable.getIntrinsicHeight());
is.close();
} catch (Exception e) {
Log.e("sms", "Failed to loaded content " + mContentUri, e);
Log.e("ImageSpan", "Failed to loaded content " + mContentUri, e);
}
} else {
try {
@@ -150,8 +246,8 @@ public class ImageSpan extends DynamicDrawableSpan {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
} catch (Exception e) {
Log.e("sms", "Unable to find resource: " + mResourceId);
}
Log.e("ImageSpan", "Unable to find resource: " + mResourceId);
}
}
return drawable;
@@ -159,9 +255,12 @@ public class ImageSpan extends DynamicDrawableSpan {
/**
* Returns the source string that was saved during construction.
*
* @return the source string that was saved during construction
* @see #ImageSpan(Drawable, String) and this{@link #ImageSpan(Context, Uri)}
*/
@Nullable
public String getSource() {
return mSource;
}
}

View File

@@ -19,16 +19,42 @@ package android.text.style;
import android.graphics.Paint;
import android.text.TextPaint;
public interface LineHeightSpan
extends ParagraphStyle, WrapTogetherSpan
{
/**
* The classes that affect the height of the line should implement this interface.
*/
public interface LineHeightSpan extends ParagraphStyle, WrapTogetherSpan {
/**
* Classes that implement this should define how the height is being calculated.
*
* @param text the text
* @param start the start of the line
* @param end the end of the line
* @param spanstartv the start of the span
* @param lineHeight the line height
* @param fm font metrics of the paint, in integers
*/
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm);
int spanstartv, int lineHeight,
Paint.FontMetricsInt fm);
/**
* The classes that affect the height of the line with respect to density, should implement this
* interface.
*/
public interface WithDensity extends LineHeightSpan {
/**
* Classes that implement this should define how the height is being calculated.
*
* @param text the text
* @param start the start of the line
* @param end the end of the line
* @param spanstartv the start of the span
* @param lineHeight the line height
* @param paint the paint
*/
public void chooseHeight(CharSequence text, int start, int end,
int spanstartv, int v,
Paint.FontMetricsInt fm, TextPaint paint);
int spanstartv, int lineHeight,
Paint.FontMetricsInt fm, TextPaint paint);
}
}

View File

@@ -18,15 +18,36 @@ package android.text.style;
import android.graphics.MaskFilter;
import android.text.TextPaint;
/**
* Span that allows setting a {@link MaskFilter} to the text it's attached to.
* <p>
* For example, to blur a text, a {@link android.graphics.BlurMaskFilter} can be used:
* <pre>
* MaskFilter blurMask = new BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL);
* SpannableString string = new SpannableString("Text with blur mask");
* string.setSpan(new MaskFilterSpan(blurMask), 10, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/maskfilterspan.png" />
* <figcaption>Text blurred with the <code>MaskFilterSpan</code>.</figcaption>
*/
public class MaskFilterSpan extends CharacterStyle implements UpdateAppearance {
private MaskFilter mFilter;
/**
* Creates a {@link MaskFilterSpan} from a {@link MaskFilter}.
*
* @param filter the filter to be applied to the <code>TextPaint</code>
*/
public MaskFilterSpan(MaskFilter filter) {
mFilter = filter;
}
/**
* Return the mask filter for this span.
*
* @return the mask filter for this span
*/
public MaskFilter getMaskFilter() {
return mFilter;
}

View File

@@ -16,6 +16,7 @@
package android.text.style;
import android.annotation.NonNull;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Parcel;
@@ -24,55 +25,76 @@ import android.text.TextPaint;
import android.text.TextUtils;
/**
*
* Describes a style in a span.
* Span that allows setting the style of the text it's attached to.
* Possible styles are: {@link Typeface#NORMAL}, {@link Typeface#BOLD}, {@link Typeface#ITALIC} and
* {@link Typeface#BOLD_ITALIC}.
* <p>
* Note that styles are cumulative -- if both bold and italic are set in
* separate spans, or if the base style is bold and a span calls for italic,
* you get bold italic. You can't turn off a style from the base style.
*
* <p>
* For example, the <code>StyleSpan</code> can be used like this:
* <pre>
* SpannableString string = new SpannableString("Bold and italic text");
* string.setSpan(new StyleSpan(Typeface.BOLD), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
* string.setSpan(new StyleSpan(Typeface.ITALIC), 9, 15, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/stylespan.png" />
* <figcaption>Text styled bold and italic with the <code>StyleSpan</code>.</figcaption>
*/
public class StyleSpan extends MetricAffectingSpan implements ParcelableSpan {
private final int mStyle;
/**
*
* Creates a {@link StyleSpan} from a style.
*
* @param style An integer constant describing the style for this span. Examples
* include bold, italic, and normal. Values are constants defined
* in {@link android.graphics.Typeface}.
* include bold, italic, and normal. Values are constants defined
* in {@link Typeface}.
*/
public StyleSpan(int style) {
mStyle = style;
}
public StyleSpan(Parcel src) {
/**
* Creates a {@link StyleSpan} from a parcel.
*
* @param src the parcel
*/
public StyleSpan(@NonNull Parcel src) {
mStyle = src.readInt();
}
@Override
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
/** @hide */
@Override
public int getSpanTypeIdInternal() {
return TextUtils.STYLE_SPAN;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
writeToParcelInternal(dest, flags);
}
/** @hide */
public void writeToParcelInternal(Parcel dest, int flags) {
@Override
public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeInt(mStyle);
}
/**
* Returns the style constant defined in {@link android.graphics.Typeface}.
* Returns the style constant defined in {@link Typeface}.
*/
public int getStyle() {
return mStyle;

View File

@@ -16,39 +16,54 @@
package android.text.style;
import android.annotation.IntRange;
import android.annotation.Px;
/**
* Represents a single tab stop on a line.
* Paragraph affecting span that changes the position of the tab with respect to
* the leading margin of the line. <code>TabStopSpan</code> will only affect the first tab
* encountered on the first line of the text.
*/
public interface TabStopSpan
extends ParagraphStyle
{
/**
* Returns the offset of the tab stop from the leading margin of the
* line.
* @return the offset
*/
public int getTabStop();
public interface TabStopSpan extends ParagraphStyle {
/**
* The default implementation of TabStopSpan.
* Returns the offset of the tab stop from the leading margin of the line, in pixels.
*
* @return the offset, in pixels
*/
public static class Standard
implements TabStopSpan
{
int getTabStop();
/**
* The default implementation of TabStopSpan that allows setting the offset of the tab stop
* from the leading margin of the first line of text.
* <p>
* Let's consider that we have the following text: <i>"\tParagraph text beginning with tab."</i>
* and we want to move the tab stop with 100px. This can be achieved like this:
* <pre>
* SpannableString string = new SpannableString("\tParagraph text beginning with tab.");
* string.setSpan(new TabStopSpan.Standard(100), 0, string.length(),
* Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);</pre>
* <img src="{@docRoot}reference/android/images/text/style/tabstopspan.png" />
* <figcaption>Text with a tab stop and a <code>TabStopSpan</code></figcaption>
*/
class Standard implements TabStopSpan {
@Px
private int mTabOffset;
/**
* Constructor.
* Constructs a {@link TabStopSpan.Standard} based on an offset.
*
* @param where the offset of the tab stop from the leading margin of
* the line
* @param offset the offset of the tab stop from the leading margin of
* the line, in pixels
*/
public Standard(int where) {
mTab = where;
public Standard(@IntRange(from = 0) int offset) {
mTabOffset = offset;
}
@Override
public int getTabStop() {
return mTab;
return mTabOffset;
}
private int mTab;
}
}

View File

@@ -16,6 +16,7 @@
package android.text.style;
import android.annotation.NonNull;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.Parcel;
@@ -24,42 +25,59 @@ import android.text.TextPaint;
import android.text.TextUtils;
/**
* Changes the typeface family of the text to which the span is attached.
* Changes the typeface family of the text to which the span is attached. Examples of typeface
* family include "monospace", "serif", and "sans-serif".
* <p>
* For example, change the typeface of a text to "monospace" like this:
* <pre>
* SpannableString string = new SpannableString("Text with typeface span");
* string.setSpan(new TypefaceSpan("monospace"), 10, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/typefacespan.png" />
* <figcaption>Text with "monospace" typeface family.</figcaption>
*/
public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
private final String mFamily;
/**
* @param family The font family for this typeface. Examples include
* "monospace", "serif", and "sans-serif".
* Constructs a {@link TypefaceSpan} based on a font family.
*
* @param family The font family for this typeface. Examples include
* "monospace", "serif", and "sans-serif".
*/
public TypefaceSpan(String family) {
mFamily = family;
}
public TypefaceSpan(Parcel src) {
public TypefaceSpan(@NonNull Parcel src) {
mFamily = src.readString();
}
@Override
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
/** @hide */
@Override
public int getSpanTypeIdInternal() {
return TextUtils.TYPEFACE_SPAN;
}
@Override
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
writeToParcelInternal(dest, flags);
}
/** @hide */
public void writeToParcelInternal(Parcel dest, int flags) {
@Override
public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeString(mFamily);
}
@@ -71,16 +89,16 @@ public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan
}
@Override
public void updateDrawState(TextPaint ds) {
apply(ds, mFamily);
public void updateDrawState(@NonNull TextPaint textPaint) {
apply(textPaint, mFamily);
}
@Override
public void updateMeasureState(TextPaint paint) {
apply(paint, mFamily);
public void updateMeasureState(@NonNull TextPaint textPaint) {
apply(textPaint, mFamily);
}
private static void apply(Paint paint, String family) {
private static void apply(@NonNull Paint paint, String family) {
int oldStyle;
Typeface old = paint.getTypeface();

View File

@@ -16,6 +16,7 @@
package android.text.style;
import android.annotation.NonNull;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@@ -27,40 +28,71 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.View;
/**
* Implementation of the {@link ClickableSpan} that allows setting a url string. When
* selecting and clicking on the text to which the span is attached, the <code>URLSpan</code>
* will try to open the url, by launching an an Activity with an {@link Intent#ACTION_VIEW} intent.
* <p>
* For example, a <code>URLSpan</code> can be used like this:
* <pre>
* SpannableString string = new SpannableString("Text with a url span");
* string.setSpan(new URLSpan("http://www.developer.android.com"), 12, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
* </pre>
* <img src="{@docRoot}reference/android/images/text/style/urlspan.png" />
* <figcaption>Text with <code>URLSpan</code>.</figcaption>
*/
public class URLSpan extends ClickableSpan implements ParcelableSpan {
private final String mURL;
/**
* Constructs a {@link URLSpan} from a url string.
*
* @param url the url string
*/
public URLSpan(String url) {
mURL = url;
}
public URLSpan(Parcel src) {
/**
* Constructs a {@link URLSpan} from a parcel.
*/
public URLSpan(@NonNull Parcel src) {
mURL = src.readString();
}
@Override
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
/** @hide */
@Override
public int getSpanTypeIdInternal() {
return TextUtils.URL_SPAN;
}
@Override
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
writeToParcelInternal(dest, flags);
}
/** @hide */
public void writeToParcelInternal(Parcel dest, int flags) {
@Override
public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeString(mURL);
}
/**
* Get the url string for this span.
*
* @return the url string.
*/
public String getURL() {
return mURL;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB