android - 如何使用文本跨度将 android textview 中的单词移动到下一个单词上方?
问题描述
我正在尝试将一个单词移动到 android textview 中的下一个单词上方,就像附加的图片(示例图片)一样。我已经设法使用 spannablestringbuilder 将单词向上移动(如上标),但我找不到将文本的右侧部分向左移动以填补空白的方法。有谁知道如何做到这一点?
这是我到目前为止编写的函数:
/**
* Adds clickable spans for words that are contained between "[" and "]"
*
* @param imString The string on which to apply clickable spans
*/
private fun addClickablePart(imString: String): SpannableStringBuilder
{
var string = imString
val spannableStringBuilder = SpannableStringBuilder((string.replace("[", "")).replace("]", ""))
var startIndex = string.indexOf("[")
while (startIndex != -1)
{
string = string.replaceFirst("[", "")
val endIndex = string.indexOf("]", startIndex)
string = string.replaceFirst("]", "")
val clickString = string.substring(startIndex, endIndex)
spannableStringBuilder.setSpan(
object: ClickableSpan()
{
override fun onClick(view: View)
{
HelperFunction.showToast(this@SongActivity, clickString)
}
override fun updateDrawState(text: TextPaint)
{
super.updateDrawState(text)
text.isUnderlineText = false
text.color = ContextCompat.getColor(this@SongActivity, R.color.colorAccent)
text.textSize = HelperFunction.spToPx(this@SongActivity, 12).toFloat()
text.baselineShift += (text.ascent()).toInt() // move chord upwards
text.typeface = Typeface.create(ResourcesCompat.getFont(this@SongActivity, R.font.roboto_mono), Typeface.BOLD) // set text to bold
}
},
startIndex, endIndex, 0)
startIndex = string.indexOf("[", endIndex)
}
return spannableStringBuilder
}
解决方案
我已经设法使用 ReplacementSpan 解决了这个问题。我在下面发布代码。
这是自定义 ReplacementSpan 类,它在画布上的所需位置绘制单词:
inner class ChordSpan: ReplacementSpan()
{
override fun getSize(paint: Paint, text: CharSequence?, start: Int, end: Int, fm: FontMetricsInt?): Int
{
val mText = text!!.subSequence(start, end).toString().replace("[", "")
var chordString = ""
var regularString = mText
if (mText.contains("]"))
{
chordString = mText.substringBefore("]")
regularString = mText.substringAfter("]")
}
val chordStringTextPaint = getChordStringTextPaint(paint)
val regularStringTextPaint = getRegularStringTextPaint(paint)
return max(chordStringTextPaint.measureText(chordString), regularStringTextPaint.measureText(regularString)).toInt()
}
private fun getChordStringTextPaint(paint: Paint): TextPaint
{
val textPaint = TextPaint(paint)
textPaint.textSize = textPaint.textSize / 1.5F
textPaint.typeface = Typeface.DEFAULT_BOLD
textPaint.color = ContextCompat.getColor(this@SongActivity, R.color.colorAccent)
return textPaint
}
private fun getRegularStringTextPaint(paint: Paint): TextPaint
{
return TextPaint(paint)
}
override fun draw(canvas: Canvas, text: CharSequence?, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint)
{
val mText = text!!.subSequence(start, end).toString().replace("[", "")
var chordString = ""
var regularString = mText
if (mText.contains("]"))
{
chordString = mText.substringBefore("]")
regularString = mText.substringAfter("]")
}
val chordStringTextPaint = getChordStringTextPaint(paint)
val regularStringTextPaint = getRegularStringTextPaint(paint)
canvas.drawText(chordString, x, y.toFloat(), chordStringTextPaint)
canvas.drawText(regularString, x, y.toFloat() + (bottom - top) / 2.5F, regularStringTextPaint)
}
}
这是在孔文本上应用跨度的函数:
private fun formatDisplayOfLyricsWithChords(string: String): SpannableString
{
val mString = "$string\n\n"
val endOfStringIndex = mString.length
val spannableString = SpannableString(mString)
var startIndex = 0
while (startIndex != -1 && startIndex != endOfStringIndex)
{
var possibleEndIndex = mString.indexOf("[", startIndex + 1)
if (possibleEndIndex == -1)
{
possibleEndIndex = endOfStringIndex + 1
}
var endOfRowIndex = mString.indexOf("\n", startIndex + 1)
if (endOfRowIndex == -1)
{
endOfRowIndex = endOfStringIndex + 1
}
val endIndex = minOf(possibleEndIndex, endOfRowIndex, endOfStringIndex)
spannableString.setSpan(ChordSpan(), startIndex, endIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
if (mString[startIndex] == '[')
{
val startIndexClick = startIndex
val endIndexClick = mString.indexOf("]", startIndex + 1)
val chord = mString.substring(startIndexClick + 1, endIndexClick)
spannableString.setSpan(
object: ClickableSpan()
{
override fun onClick(view: View)
{
handleClickOnChord(chord)
}
},
startIndexClick, endIndexClick, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
}
startIndex = endIndex
if (startIndex == endOfRowIndex)
{
startIndex++
}
}
return spannableString
}
我从类似问题的答案中获得灵感:https ://stackoverflow.com/a/24091284/8211969
推荐阅读
- angularjs - 从 url 参数打开 data-ng-click 功能
- mysql - 同步两个数据库的增量
- python - Python/numpy - 张量表示法和正规矩阵的效率
- authentication - nginx通过用户登录重定向
- javascript - 在 React 中渲染异步组件
- webkit - HTMLMediaElement.play() 可以准确安排吗?
- azure - 针对特定存储帐户运行 azure cli
- angular - Angular CLI(7.0.5)用于开发和生产的不同资产?
- java - 带有 apache 插件的 HTML 到 PDF
- android - 当从活动发送数据到广播接收器时,应用程序在 startActivity 上崩溃