作者:冰weiter | 来源:互联网 | 2023-01-03 18:57
1> Cheticamp..:
基本问题是没有设置高度ReplacementSpan
.正如以下来源所述ReplacementSpan
:
如果跨度覆盖整个文本,并且未设置高度,则不会为span调用draw(Canvas,CharSequence,int,int,float,int,int,int,Paint)}.
这是Archit Sureja发布的重复内容.在我的原始帖子中,我更新了ReplacementSpan
in 的高度,getSize()
但我现在实现了LineHeightSpan.WithDensity
接口来做同样的事情.(感谢vovahost 在这里获取此信息.)
但是,您提出的其他问题需要解决.
您提供的项目引发的问题是该点不适合TextView
它必须驻留的范围.你看到的是点的截断.如果点的大小超过文本宽度或高度,该怎么办?
首先,关于高度,chooseHeight()
界面方法通过将点的大小添加到字体的有效高度来LineHeightSpan.WithDensity
调整被认为是TextView
字体底部的内容.为此,点的高度将添加到字体的底部:
fontMetricsInt.bottom = fm.bottom + mDotSize.toInt();
(这是对这个使用了TextView
填充的答案的最后一次迭代的改变.由于这个改变,类TextView
不再需要了UnderDotSpan
.虽然我已经添加了TextView
,但它并不是真的需要.)
最后一个问题是,如果点宽于文本,则点在开始和结束处被截断.clipToPadding="false"
在这里不起作用,因为点被截断不是因为它被剪裁到填充,而是因为它被剪切到我们所说的文本宽度所在getSize()
.为了解决这个问题,我修改了getSize()
方法以检测点何时比文本测量宽,并增加返回值以匹配点的宽度.调用的新值mStartShim
是必须应用于文本绘图的数量和用于使事物适合的点.
最后一个问题是点的中心是文本底部下方点的半径而不是直径,因此绘制点的代码更改draw()
为:
canvas.drawCircle(x + textSize / 2, bottom.toFloat(), mDotSize / 2, paint)
(我也改变了代码来进行Canvas
翻译而不是添加偏移量.效果是一样的.)
结果如下:
activity_main.xml中
MainActivity.java
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val text = "1"
val spannable = SpannableString(text)
spannable.setSpan(UnderDotSpan(this@MainActivity, 0xFF039BE5.toInt(), textView.currentTextColor),
0, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
textView.setText(spannable, TextView.BufferType.SPANNABLE)
}
}
UnderDotSpan.kt
// From the original UnderDotSpan: Also implement the LineHeightSpan.WithDensity interface to
// compute the height of our "dotted" font.
class UnderDotSpan(private val mDotSize: Float, private val mDotColor: Int, private val mTextColor: Int) : ReplacementSpan(), LineHeightSpan.WithDensity {
companion object {
@JvmStatic
private val DEFAULT_DOT_SIZE_IN_DP = 16
}
// Additional horizontal space to the start, if needed, to fit the dot
var mStartShim = 0;
constructor(context: Context, dotColor: Int, textColor: Int)
: this(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_DOT_SIZE_IN_DP.toFloat(),
context.resources.displayMetrics), dotColor, textColor)
// ReplacementSpan override to determine the size (length) of the text.
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
val baseTextWidth = paint.measureText(text, start, end)
// If the width of the text is less than the width of our dot, increase the text width
// to match the dot's width; otherwise, just return the width of the text.
mStartShim = if (baseTextWidth
对于在文本下放置一个小的drawable的更一般情况,以下类是有效的,并且基于UnderDotSpan
:
UnderDrawableSpan.java
public class UnderDrawableSpan extends ReplacementSpan implements LineHeightSpan.WithDensity {
final private Drawable mDrawable;
final private int mDrawableWidth;
final private int mDrawableHeight;
final private int mMargin;
// How much we need to jog the text to line up with a larger-than-text-width drawable.
private int mStartShim = 0;
UnderDrawableSpan(Context context, Drawable drawable, int drawableWidth, int drawableHeight,
int margin) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
mDrawable = drawable;
mDrawableWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) drawableWidth, metrics);
mDrawableHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) drawableHeight, metrics);
mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
(float) margin, metrics);
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
int bottom, @NonNull Paint paint) {
if (TextUtils.isEmpty(text)) {
return;
}
float textWidth = paint.measureText(text, start, end);
float offset = mStartShim + x + (textWidth - mDrawableWidth) / 2;
mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight);
canvas.save();
canvas.translate(offset, bottom - mDrawableHeight);
mDrawable.draw(canvas);
canvas.restore();
canvas.save();
canvas.translate(mStartShim, 0);
canvas.drawText(text, start, end, x, y, paint);
canvas.restore();
}
// ReplacementSpan override to determine the size (length) of the text.
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
float baseTextWidth = paint.measureText(text, start, end);
// If the width of the text is less than the width of our drawable, increase the text width
// to match the drawable's width; otherwise, just return the width of the text.
mStartShim = (baseTextWidth
使用以下可绘制的XML UnderDrawableSpan
会产生以下结果:(drawable的宽度和高度设置为12dp
.文本的字体大小为24sp
.)
gradient_drawable.xml