Ordered lists inside an Android TextView

前端 未结 7 1189
星月不相逢
星月不相逢 2020-12-30 06:47

I want to display an ordered list inside a TextView, for example:
1) item 1
2) item 2

Using the following layout:



        
7条回答
  •  北荒
    北荒 (楼主)
    2020-12-30 07:14

    This class handles numbering in TextView and EditText and scales the number depending on the size of the text:

    import android.graphics.Canvas
    import android.graphics.Paint
    import android.text.Layout
    import android.text.Spanned
    import android.text.style.AbsoluteSizeSpan
    import android.text.style.LeadingMarginSpan
    
    /**
     * Paragraph numbering.
     *
     *
     * Android seems to add the leading margin for an empty paragraph to the previous paragraph
     * (]0, 4][4, 4] --> the leading margin of the second span is added to the ]0, 4] paragraph
     * regardless of the Spanned.flags) --> therefore we ignore the leading margin for the last,
     * empty paragraph unless it's the only one
     */
    class NumberSpan(nr: Int, gapWidth: Int, isEmpty: Boolean, isFirst: Boolean, isLast: Boolean)
        : LeadingMarginSpan {
    
        private val mNr: Int = nr
        private val mGapWidth: Int = gapWidth
        private val mIgnoreSpan: Boolean = isEmpty && isLast && !isFirst
    
        private var mWidth: Float = 0.toFloat()
    
        val value: Boolean?
            get() = java.lang.Boolean.TRUE
    
        override fun getLeadingMargin(first: Boolean): Int {
            return if (mIgnoreSpan) 0 else Math.max(Math.round(mWidth + 2), mGapWidth)
        }
    
        override fun drawLeadingMargin(c: Canvas, p: Paint, x: Int, dir: Int, top: Int, baseline: Int, bottom: Int,
                                       text: CharSequence, start: Int, end: Int, first: Boolean, l: Layout) {
    
            val spanned = text as Spanned
            if (!mIgnoreSpan && spanned.getSpanStart(this) == start) {
                // set paint
                val oldStyle = p.style
                val oldTextSize = p.textSize
                p.style = Paint.Style.FILL
                val textSize = determineTextSize(spanned, start, end, oldTextSize)
                p.textSize = textSize
                mWidth = p.measureText(mNr.toString() + ".")
    
                // draw the number
                c.drawText(mNr.toString() + ".", x.toFloat(), baseline.toFloat(), p)
    
                // restore paint
                p.style = oldStyle
                p.textSize = oldTextSize
            }
        }
    
        private fun determineTextSize(spanned: Spanned, start: Int, end: Int, defaultTextSize: Float): Float {
            // If the text size is different from default use that to determine the indicator size
            // That is determined by finding the first visible character within the list item span
            // and checking its size
            val position = firstVisibleCharIndex(spanned, start, end)
            if (position >= 0) {
                val absoluteSizeSpans = spanned.getSpans(position, position, AbsoluteSizeSpan::class.java)
                if (absoluteSizeSpans.isNotEmpty()) {
                    val absoluteSizeSpan = absoluteSizeSpans[absoluteSizeSpans.size - 1]
                    return absoluteSizeSpan.size.toFloat()
                }
            }
    
            // If there are no spans or no visible characters yet use the default calculation
            return defaultTextSize
        }
    
        private fun firstVisibleCharIndex(spanned: Spanned, start: Int, end: Int): Int {
            var newStart = start
            while (newStart < end) {
                if (isVisibleChar(spanned[newStart])) {
                    return newStart
                }
                newStart++
            }
    
            return -1
        }
    
        private fun isVisibleChar(c: Char): Boolean {
            return when (c) {
                '\u200B', '\uFFEF' -> false
                else -> true
            }
        }
    
    }
    

    The code is from this library https://github.com/1gravity/Android-RTEditor (translated from Java to Kotlin). I'm the author of that library.

提交回复
热议问题