Merge "Make BulletSpan more flexible and update JavaDoc."
diff --git a/api/current.txt b/api/current.txt
index 5f153e6..a1977bf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -43156,9 +43156,13 @@
ctor public BulletSpan();
ctor public BulletSpan(int);
ctor public BulletSpan(int, int);
+ ctor public BulletSpan(int, int, int);
ctor public BulletSpan(android.os.Parcel);
method public int describeContents();
method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
+ method public int getBulletRadius();
+ method public int getColor();
+ method public int getGapWidth();
method public int getLeadingMargin(boolean);
method public int getSpanTypeId();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/text/style/BulletSpan.java b/core/java/android/text/style/BulletSpan.java
index 43dd0ff..70175c8 100644
--- a/core/java/android/text/style/BulletSpan.java
+++ b/core/java/android/text/style/BulletSpan.java
@@ -16,6 +16,11 @@
package android.text.style;
+import android.annotation.ColorInt;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.Px;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
@@ -26,38 +31,108 @@
import android.text.Spanned;
import android.text.TextUtils;
+/**
+ * A span which styles paragraphs as bullet points (respecting layout direction).
+ * <p>
+ * BulletSpans must be attached from the first character to the last character of a single
+ * paragraph, otherwise the bullet point will not be displayed but the first paragraph encountered
+ * will have a leading margin.
+ * <p>
+ * BulletSpans allow configuring the following elements:
+ * <ul>
+ * <li><b>gap width</b> - the distance, in pixels, between the bullet point and the paragraph.
+ * Default value is 2px.</li>
+ * <li><b>color</b> - the bullet point color. By default, the bullet point color is 0 - no color,
+ * so it uses the TextView's text color.</li>
+ * <li><b>bullet radius</b> - the radius, in pixels, of the bullet point. Default value is
+ * 4px.</li>
+ * </ul>
+ * For example, a BulletSpan using the default values can be constructed like this:
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with\nBullet point");
+ *string.setSpan(new BulletSpan(), 10, 22, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/defaultbulletspan.png" />
+ * <figcaption>BulletSpan constructed with default values.</figcaption>
+ * <p>
+ * <p>
+ * To construct a BulletSpan with a gap width of 40px, green bullet point and bullet radius of
+ * 20px:
+ * <pre>{@code
+ * SpannableString string = new SpannableString("Text with\nBullet point");
+ *string.setSpan(new BulletSpan(40, color, 20), 10, 22, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/custombulletspan.png" />
+ * <figcaption>Customized BulletSpan.</figcaption>
+ */
public class BulletSpan implements LeadingMarginSpan, ParcelableSpan {
- private final int mGapWidth;
- private final boolean mWantColor;
- private final int mColor;
-
// Bullet is slightly bigger to avoid aliasing artifacts on mdpi devices.
- private static final float BULLET_RADIUS = 3 * 1.2f;
- private static Path sBulletPath = null;
+ private static final int STANDARD_BULLET_RADIUS = 4;
public static final int STANDARD_GAP_WIDTH = 2;
+ private static final int STANDARD_COLOR = 0;
+ @Px
+ private final int mGapWidth;
+ @Px
+ private final int mBulletRadius;
+ private Path mBulletPath = null;
+ @ColorInt
+ private final int mColor;
+ private final boolean mWantColor;
+
+ /**
+ * Creates a {@link BulletSpan} with the default values.
+ */
public BulletSpan() {
- mGapWidth = STANDARD_GAP_WIDTH;
- mWantColor = false;
- mColor = 0;
+ this(STANDARD_GAP_WIDTH, STANDARD_COLOR, false, STANDARD_BULLET_RADIUS);
}
+ /**
+ * Creates a {@link BulletSpan} based on a gap width
+ *
+ * @param gapWidth the distance, in pixels, between the bullet point and the paragraph.
+ */
public BulletSpan(int gapWidth) {
- mGapWidth = gapWidth;
- mWantColor = false;
- mColor = 0;
+ this(gapWidth, STANDARD_COLOR, false, STANDARD_BULLET_RADIUS);
}
- public BulletSpan(int gapWidth, int color) {
+ /**
+ * Creates a {@link BulletSpan} based on a gap width and a color integer.
+ *
+ * @param gapWidth the distance, in pixels, between the bullet point and the paragraph.
+ * @param color the bullet point color, as a color integer
+ * @see android.content.res.Resources#getColor(int, Resources.Theme)
+ */
+ public BulletSpan(int gapWidth, @ColorInt int color) {
+ this(gapWidth, color, true, STANDARD_BULLET_RADIUS);
+ }
+
+ /**
+ * Creates a {@link BulletSpan} based on a gap width and a color integer.
+ *
+ * @param gapWidth the distance, in pixels, between the bullet point and the paragraph.
+ * @param color the bullet point color, as a color integer.
+ * @param bulletRadius the radius of the bullet point, in pixels.
+ * @see android.content.res.Resources#getColor(int, Resources.Theme)
+ */
+ public BulletSpan(int gapWidth, @ColorInt int color, @IntRange(from = 0) int bulletRadius) {
+ this(gapWidth, color, true, bulletRadius);
+ }
+
+ private BulletSpan(int gapWidth, @ColorInt int color, boolean wantColor,
+ @IntRange(from = 0) int bulletRadius) {
mGapWidth = gapWidth;
- mWantColor = true;
+ mBulletRadius = bulletRadius;
mColor = color;
+ mWantColor = wantColor;
}
- public BulletSpan(Parcel src) {
+ /**
+ * Creates a {@link BulletSpan} from a parcel.
+ */
+ public BulletSpan(@NonNull Parcel src) {
mGapWidth = src.readInt();
mWantColor = src.readInt() != 0;
mColor = src.readInt();
+ mBulletRadius = src.readInt();
}
@Override
@@ -77,68 +152,97 @@
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
writeToParcelInternal(dest, flags);
}
/** @hide */
@Override
- public void writeToParcelInternal(Parcel dest, int flags) {
+ public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
dest.writeInt(mGapWidth);
dest.writeInt(mWantColor ? 1 : 0);
dest.writeInt(mColor);
+ dest.writeInt(mBulletRadius);
}
@Override
public int getLeadingMargin(boolean first) {
- return (int) (2 * BULLET_RADIUS + mGapWidth);
+ return 2 * mBulletRadius + mGapWidth;
+ }
+
+ /**
+ * Get the distance, in pixels, between the bullet point and the paragraph.
+ *
+ * @return the distance, in pixels, between the bullet point and the paragraph.
+ */
+ public int getGapWidth() {
+ return mGapWidth;
+ }
+
+ /**
+ * Get the radius, in pixels, of the bullet point.
+ *
+ * @return the radius, in pixels, of the bullet point.
+ */
+ public int getBulletRadius() {
+ return mBulletRadius;
+ }
+
+ /**
+ * Get the bullet point color.
+ *
+ * @return the bullet point color
+ */
+ public int getColor() {
+ return mColor;
}
@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 l) {
+ public void drawLeadingMargin(@NonNull Canvas canvas, @NonNull Paint paint, int x, int dir,
+ int top, int baseline, int bottom,
+ @NonNull CharSequence text, int start, int end,
+ boolean first, @Nullable Layout layout) {
if (((Spanned) text).getSpanStart(this) == start) {
- Paint.Style style = p.getStyle();
+ Paint.Style style = paint.getStyle();
int oldcolor = 0;
if (mWantColor) {
- oldcolor = p.getColor();
- p.setColor(mColor);
+ oldcolor = paint.getColor();
+ paint.setColor(mColor);
}
- p.setStyle(Paint.Style.FILL);
+ paint.setStyle(Paint.Style.FILL);
- if (l != null) {
+ if (layout != null) {
// "bottom" position might include extra space as a result of line spacing
// configuration. Subtract extra space in order to show bullet in the vertical
// center of characters.
- final int line = l.getLineForOffset(start);
- bottom = bottom - l.getLineExtra(line);
+ final int line = layout.getLineForOffset(start);
+ bottom = bottom - layout.getLineExtra(line);
}
- final float y = (top + bottom) / 2f;
+ final float yPosition = (top + bottom) / 2f;
+ final float xPosition = x + dir * mBulletRadius;
- if (c.isHardwareAccelerated()) {
- if (sBulletPath == null) {
- sBulletPath = new Path();
- sBulletPath.addCircle(0.0f, 0.0f, BULLET_RADIUS, Direction.CW);
+ if (canvas.isHardwareAccelerated()) {
+ if (mBulletPath == null) {
+ mBulletPath = new Path();
+ mBulletPath.addCircle(0.0f, 0.0f, mBulletRadius, Direction.CW);
}
- c.save();
- c.translate(x + dir * BULLET_RADIUS, y);
- c.drawPath(sBulletPath, p);
- c.restore();
+ canvas.save();
+ canvas.translate(xPosition, yPosition);
+ canvas.drawPath(mBulletPath, paint);
+ canvas.restore();
} else {
- c.drawCircle(x + dir * BULLET_RADIUS, y, BULLET_RADIUS, p);
+ canvas.drawCircle(xPosition, yPosition, mBulletRadius, paint);
}
if (mWantColor) {
- p.setColor(oldcolor);
+ paint.setColor(oldcolor);
}
- p.setStyle(style);
+ paint.setStyle(style);
}
}
}
diff --git a/docs/html/reference/images/text/style/custombulletspan.png b/docs/html/reference/images/text/style/custombulletspan.png
new file mode 100644
index 0000000..251f8a1
--- /dev/null
+++ b/docs/html/reference/images/text/style/custombulletspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/defaultbulletspan.png b/docs/html/reference/images/text/style/defaultbulletspan.png
new file mode 100644
index 0000000..854143f
--- /dev/null
+++ b/docs/html/reference/images/text/style/defaultbulletspan.png
Binary files differ