Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用文本跨度将android textview中的一个单词移动到下一个单词上方?_Android_Kotlin_Textview_Spannablestringbuilder - Fatal编程技术网

如何使用文本跨度将android textview中的一个单词移动到下一个单词上方?

如何使用文本跨度将android textview中的一个单词移动到下一个单词上方?,android,kotlin,textview,spannablestringbuilder,Android,Kotlin,Textview,Spannablestringbuilder,我正试图在android文本视图中将一个单词移到下一个单词的上方,如附件中的图像()。我用spannablestringbuilder成功地将单词向上移动(如上标),但我找不到一种方法将文本的右侧部分向左移动以填补空白。有人知道怎么做吗 这是我到目前为止编写的函数: /** * Adds clickable spans for words that are contained between "[" and "]" * * @param imString The string on whi

我正试图在android文本视图中将一个单词移到下一个单词的上方,如附件中的图像()。我用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
}

您可以在TextView中使用HTML来实现这一点,例如,上标符号的HTML/CSS代码是:

<!DOCTYPE html> 
<html> 
<head> 
<style> 
sup { 
    vertical-align: super; 
    font-size: medium; 
    color: red;
    position: relative; left: -2.5em; top: -0.5em; 
} 
</style> 
</head> 
<body> 
<p>word <sup>topword</sup></p> 
</body> 
</html> 

您可以在TextView中使用HTML来实现这一点,例如,上标符号的HTML/CSS代码是:

<!DOCTYPE html> 
<html> 
<head> 
<style> 
sup { 
    vertical-align: super; 
    font-size: medium; 
    color: red;
    position: relative; left: -2.5em; top: -0.5em; 
} 
</style> 
</head> 
<body> 
<p>word <sup>topword</sup></p> 
</body> 
</html> 

我已经使用ReplacementSpan解决了这个问题。我把代码贴在下面

这是custom 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
}

我从一个类似的问题中得到了灵感:

我已经设法用ReplacementSpan解决了这个问题。我把代码贴在下面

这是custom 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
}

我从一个类似的问题的回答中得到了灵感:

屏幕截图显示了您所做的事情或您的期望?您好,欢迎来到SO,请阅读并提供come代码。否则,您的问题可能会被否决而得不到回答。您可能应该在html中定义它,然后将textview内容设置为htmlHello@VirRajpurohit截图显示了我的期望。我提供了到目前为止我编写的处理字符串的函数,并更新了图像以使其更清晰。Hello@Frieder!我已经提供了我编写的用于处理字符串的函数。屏幕截图显示了您所做的或您所期望的?您好,欢迎使用SO,请阅读并提供come代码。否则,您的问题可能会被否决而得不到回答。您可能应该在html中定义它,然后将textview内容设置为htmlHello@VirRajpurohit截图显示了我的期望。我提供了到目前为止我编写的处理字符串的函数,并更新了图像以使其更清晰。Hello@Frieder!我提供了我编写的用于处理字符串的函数。