Create round text view
This commit is contained in:
parent
1531588453
commit
d93a5f8ee6
1
markwon-round-textview/.gitignore
vendored
Normal file
1
markwon-round-textview/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
52
markwon-round-textview/build.gradle
Normal file
52
markwon-round-textview/build.gradle
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
plugins {
|
||||||
|
id 'com.android.library'
|
||||||
|
id 'kotlin-android'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 31
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 21
|
||||||
|
targetSdkVersion 31
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '1.8'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
api project(':markwon-core')
|
||||||
|
|
||||||
|
deps.with {
|
||||||
|
// add a compileOnly dependency, so if this artifact is present
|
||||||
|
// we will try to obtain a SpanFactory for a Strikethrough node and use
|
||||||
|
// it to be consistent with markdown (please note that we do not use markwon plugin
|
||||||
|
// for that in case if different implementation is used)
|
||||||
|
compileOnly it['commonmark-strikethrough']
|
||||||
|
|
||||||
|
testImplementation it['ix-java']
|
||||||
|
}
|
||||||
|
|
||||||
|
deps.test.with {
|
||||||
|
testImplementation it['junit']
|
||||||
|
testImplementation it['robolectric']
|
||||||
|
}
|
||||||
|
}
|
0
markwon-round-textview/consumer-rules.pro
Normal file
0
markwon-round-textview/consumer-rules.pro
Normal file
21
markwon-round-textview/proguard-rules.pro
vendored
Normal file
21
markwon-round-textview/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,24 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
fun useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals("io.noties.markdown.boundarytext.test", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
5
markwon-round-textview/src/main/AndroidManifest.xml
Normal file
5
markwon-round-textview/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="io.noties.markdown.boundarytext">
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
import android.graphics.Canvas
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* author : NeXT
|
||||||
|
* time : 2018/12/11
|
||||||
|
* desc :
|
||||||
|
* copy from: androidx.core.graphics.Canvas.kt
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline fun Canvas.withTranslation(
|
||||||
|
x: Float = 0.0f,
|
||||||
|
y: Float = 0.0f,
|
||||||
|
block: Canvas.() -> Unit
|
||||||
|
) {
|
||||||
|
val checkpoint = save()
|
||||||
|
translate(x, y)
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} finally {
|
||||||
|
restoreToCount(checkpoint)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
import android.os.Build
|
||||||
|
import android.text.Layout
|
||||||
|
|
||||||
|
// Extension functions for Layout object
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Android system default line spacing extra
|
||||||
|
*/
|
||||||
|
private const val DEFAULT_LINESPACING_EXTRA = 0f
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Android system default line spacing multiplier
|
||||||
|
*/
|
||||||
|
private const val DEFAULT_LINESPACING_MULTIPLIER = 1f
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the line bottom discarding the line spacing added.
|
||||||
|
*/
|
||||||
|
fun Layout.getLineBottomWithoutSpacing(line: Int): Int {
|
||||||
|
val lineBottom = getLineBottom(line)
|
||||||
|
val lastLineSpacingNotAdded = Build.VERSION.SDK_INT >= 19
|
||||||
|
val isLastLine = line == lineCount - 1
|
||||||
|
|
||||||
|
val lineBottomWithoutSpacing: Int
|
||||||
|
val lineSpacingExtra = spacingAdd
|
||||||
|
val lineSpacingMultiplier = spacingMultiplier
|
||||||
|
val hasLineSpacing = lineSpacingExtra != DEFAULT_LINESPACING_EXTRA
|
||||||
|
|| lineSpacingMultiplier != DEFAULT_LINESPACING_MULTIPLIER
|
||||||
|
|
||||||
|
if (!hasLineSpacing || isLastLine && lastLineSpacingNotAdded) {
|
||||||
|
lineBottomWithoutSpacing = lineBottom
|
||||||
|
} else {
|
||||||
|
val extra: Float
|
||||||
|
if (lineSpacingMultiplier.compareTo(DEFAULT_LINESPACING_MULTIPLIER) != 0) {
|
||||||
|
val lineHeight = getLineHeight(line)
|
||||||
|
extra = lineHeight - (lineHeight - lineSpacingExtra) / lineSpacingMultiplier
|
||||||
|
} else {
|
||||||
|
extra = lineSpacingExtra
|
||||||
|
}
|
||||||
|
|
||||||
|
lineBottomWithoutSpacing = (lineBottom - extra).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
return lineBottomWithoutSpacing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the line height of a line.
|
||||||
|
*/
|
||||||
|
fun Layout.getLineHeight(line: Int): Int {
|
||||||
|
return getLineTop(line + 1) - getLineTop(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the top of the Layout after removing the extra padding applied by the Layout.
|
||||||
|
*/
|
||||||
|
fun Layout.getLineTopWithoutPadding(line: Int): Int {
|
||||||
|
var lineTop = getLineTop(line)
|
||||||
|
if (line == 0) {
|
||||||
|
lineTop -= topPadding
|
||||||
|
}
|
||||||
|
return lineTop
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the bottom of the Layout after removing the extra padding applied by the Layout.
|
||||||
|
*/
|
||||||
|
fun Layout.getLineBottomWithoutPadding(line: Int): Int {
|
||||||
|
var lineBottom = getLineBottomWithoutSpacing(line)
|
||||||
|
if (line == lineCount - 1) {
|
||||||
|
lineBottom -= bottomPadding
|
||||||
|
}
|
||||||
|
return lineBottom
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.text.Spanned
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.widget.TextView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A TextView that can draw rounded background to the portions of the text. See
|
||||||
|
* [TextRoundedBgHelper] for more information.
|
||||||
|
*
|
||||||
|
* See [TextRoundedBgAttributeReader] for supported attributes.
|
||||||
|
*/
|
||||||
|
class RoundedBgTextView @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = android.R.attr.textViewStyle
|
||||||
|
) : TextView(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private lateinit var textRoundedBgHelper: TextRoundedBgHelper
|
||||||
|
private lateinit var attributeReader : TextRoundedBgAttributeReader
|
||||||
|
|
||||||
|
private lateinit var mAttrs : AttributeSet
|
||||||
|
private var mTheme : String
|
||||||
|
|
||||||
|
init {
|
||||||
|
mTheme = "light"
|
||||||
|
if (attrs != null) {
|
||||||
|
mAttrs = attrs
|
||||||
|
attributeReader = TextRoundedBgAttributeReader(context, mAttrs, mTheme)
|
||||||
|
textRoundedBgHelper = TextRoundedBgHelper(
|
||||||
|
horizontalPadding = attributeReader.horizontalPadding,
|
||||||
|
verticalPadding = attributeReader.verticalPadding,
|
||||||
|
drawable = attributeReader.drawable,
|
||||||
|
drawableLeft = attributeReader.drawableLeft,
|
||||||
|
drawableMid = attributeReader.drawableMid,
|
||||||
|
drawableRight = attributeReader.drawableRight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setThemeChange(theme : String) {
|
||||||
|
mTheme = theme
|
||||||
|
attributeReader = TextRoundedBgAttributeReader(context, mAttrs, mTheme)
|
||||||
|
textRoundedBgHelper = TextRoundedBgHelper(
|
||||||
|
horizontalPadding = attributeReader.horizontalPadding,
|
||||||
|
verticalPadding = attributeReader.verticalPadding,
|
||||||
|
drawable = attributeReader.drawable,
|
||||||
|
drawableLeft = attributeReader.drawableLeft,
|
||||||
|
drawableMid = attributeReader.drawableMid,
|
||||||
|
drawableRight = attributeReader.drawableRight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTextColorWith (textColor : Int){
|
||||||
|
this.setTextColor(textColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
// need to draw bg first so that text can be on top during super.onDraw()
|
||||||
|
if (text is Spanned && layout != null) {
|
||||||
|
canvas.withTranslation(totalPaddingLeft.toFloat(), totalPaddingTop.toFloat()) {
|
||||||
|
textRoundedBgHelper.draw(canvas, text as Spanned, layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onDraw(canvas)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.util.AttributeSet
|
||||||
|
|
||||||
|
class TextRoundedBgAttributeReader(context: Context, attrs: AttributeSet?, theme : String) {
|
||||||
|
|
||||||
|
val horizontalPadding: Int
|
||||||
|
val verticalPadding: Int
|
||||||
|
val drawable: Drawable
|
||||||
|
val drawableLeft: Drawable
|
||||||
|
val drawableMid: Drawable
|
||||||
|
val drawableRight: Drawable
|
||||||
|
|
||||||
|
init {
|
||||||
|
var typedArray = context.obtainStyledAttributes(
|
||||||
|
attrs,
|
||||||
|
R.styleable.TextRoundedBgHelper,
|
||||||
|
0,
|
||||||
|
R.style.RoundedBgTextView
|
||||||
|
)
|
||||||
|
if(theme.equals("dark")){
|
||||||
|
typedArray = context.obtainStyledAttributes(
|
||||||
|
attrs,
|
||||||
|
R.styleable.TextRoundedBgHelper,
|
||||||
|
0,
|
||||||
|
R.style.RoundedBgTextDarkView
|
||||||
|
)
|
||||||
|
}
|
||||||
|
horizontalPadding = typedArray.getDimensionPixelSize(
|
||||||
|
R.styleable.TextRoundedBgHelper_roundedTextHorizontalPadding,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
verticalPadding = typedArray.getDimensionPixelSize(
|
||||||
|
R.styleable.TextRoundedBgHelper_roundedTextVerticalPadding,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
drawable = typedArray.getDrawable(
|
||||||
|
R.styleable.TextRoundedBgHelper_roundedTextDrawable
|
||||||
|
)!!
|
||||||
|
drawableLeft = typedArray.getDrawable(
|
||||||
|
R.styleable.TextRoundedBgHelper_roundedTextDrawableLeft
|
||||||
|
)!!
|
||||||
|
drawableMid = typedArray.getDrawable(
|
||||||
|
R.styleable.TextRoundedBgHelper_roundedTextDrawableMid
|
||||||
|
)!!
|
||||||
|
drawableRight = typedArray.getDrawable(
|
||||||
|
R.styleable.TextRoundedBgHelper_roundedTextDrawableRight
|
||||||
|
)!!
|
||||||
|
typedArray.recycle()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.text.Layout
|
||||||
|
import android.text.Spanned
|
||||||
|
import io.noties.markwon.core.spans.CodeSpan
|
||||||
|
|
||||||
|
class TextRoundedBgHelper(
|
||||||
|
val horizontalPadding: Int,
|
||||||
|
verticalPadding: Int,
|
||||||
|
drawable: Drawable,
|
||||||
|
drawableLeft: Drawable,
|
||||||
|
drawableMid: Drawable,
|
||||||
|
drawableRight: Drawable
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val singleLineRenderer: TextRoundedBgRenderer by lazy {
|
||||||
|
SingleLineRenderer(
|
||||||
|
horizontalPadding = horizontalPadding,
|
||||||
|
verticalPadding = verticalPadding,
|
||||||
|
drawable = drawable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val multiLineRenderer: TextRoundedBgRenderer by lazy {
|
||||||
|
MultiLineRenderer(
|
||||||
|
horizontalPadding = horizontalPadding,
|
||||||
|
verticalPadding = verticalPadding,
|
||||||
|
drawableLeft = drawableLeft,
|
||||||
|
drawableMid = drawableMid,
|
||||||
|
drawableRight = drawableRight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call this function during onDraw of another widget such as TextView.
|
||||||
|
*
|
||||||
|
* @param canvas Canvas to draw onto
|
||||||
|
* @param text
|
||||||
|
* @param layout Layout that contains the text
|
||||||
|
*/
|
||||||
|
fun draw(canvas: Canvas, text: Spanned, layout: Layout) {
|
||||||
|
// ideally the calculations here should be cached since they are not cheap. However, proper
|
||||||
|
// invalidation of the cache is required whenever anything related to text has changed.
|
||||||
|
// val spans = text.getSpans(0, text.length, Annotation::class.java)
|
||||||
|
val spans = text.getSpans(0, text.length, CodeSpan::class.java)
|
||||||
|
spans.forEach { span ->
|
||||||
|
// if (span.value.equals("rounded")) {
|
||||||
|
val spanStart = text.getSpanStart(span)
|
||||||
|
val spanEnd = text.getSpanEnd(span)
|
||||||
|
val startLine = layout.getLineForOffset(spanStart)
|
||||||
|
val endLine = layout.getLineForOffset(spanEnd)
|
||||||
|
|
||||||
|
// start can be on the left or on the right depending on the language direction.
|
||||||
|
val startOffset = (layout.getPrimaryHorizontal(spanStart)
|
||||||
|
+ -1 * layout.getParagraphDirection(startLine) * horizontalPadding).toInt()
|
||||||
|
// end can be on the left or on the right depending on the language direction.
|
||||||
|
val endOffset = (layout.getPrimaryHorizontal(spanEnd)
|
||||||
|
+ layout.getParagraphDirection(endLine) * horizontalPadding).toInt()
|
||||||
|
|
||||||
|
val renderer = if (startLine == endLine) singleLineRenderer else multiLineRenderer
|
||||||
|
renderer.draw(canvas, layout, startLine, endLine, startOffset, endOffset)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,194 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.text.Layout
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for single and multi line rounded background renderers.
|
||||||
|
*
|
||||||
|
* @param horizontalPadding the padding to be applied to left & right of the background
|
||||||
|
* @param verticalPadding the padding to be applied to top & bottom of the background
|
||||||
|
*/
|
||||||
|
internal abstract class TextRoundedBgRenderer(
|
||||||
|
val horizontalPadding: Int,
|
||||||
|
val verticalPadding: Int
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the background that starts at the {@code startOffset} and ends at {@code endOffset}.
|
||||||
|
*
|
||||||
|
* @param canvas Canvas to draw onto
|
||||||
|
* @param layout Layout that contains the text
|
||||||
|
* @param startLine the start line for the background
|
||||||
|
* @param endLine the end line for the background
|
||||||
|
* @param startOffset the character offset that the background should start at
|
||||||
|
* @param endOffset the character offset that the background should end at
|
||||||
|
*/
|
||||||
|
abstract fun draw(
|
||||||
|
canvas: Canvas,
|
||||||
|
layout: Layout,
|
||||||
|
startLine: Int,
|
||||||
|
endLine: Int,
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the top offset of the line and add padding into account so that there is a gap between
|
||||||
|
* top of the background and top of the text.
|
||||||
|
*
|
||||||
|
* @param layout Layout object that contains the text
|
||||||
|
* @param line line number
|
||||||
|
*/
|
||||||
|
protected fun getLineTop(layout: Layout, line: Int): Int {
|
||||||
|
return layout.getLineTopWithoutPadding(line) - verticalPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bottom offset of the line and add padding into account so that there is a gap between
|
||||||
|
* bottom of the background and bottom of the text.
|
||||||
|
*
|
||||||
|
* @param layout Layout object that contains the text
|
||||||
|
* @param line line number
|
||||||
|
*/
|
||||||
|
protected fun getLineBottom(layout: Layout, line: Int): Int {
|
||||||
|
return layout.getLineBottomWithoutPadding(line) + verticalPadding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the background for text that starts and ends on the same line.
|
||||||
|
*
|
||||||
|
* @param horizontalPadding the padding to be applied to left & right of the background
|
||||||
|
* @param verticalPadding the padding to be applied to top & bottom of the background
|
||||||
|
* @param drawable the drawable used to draw the background
|
||||||
|
*/
|
||||||
|
internal class SingleLineRenderer(
|
||||||
|
horizontalPadding: Int,
|
||||||
|
verticalPadding: Int,
|
||||||
|
val drawable: Drawable
|
||||||
|
) : TextRoundedBgRenderer(horizontalPadding, verticalPadding) {
|
||||||
|
|
||||||
|
override fun draw(
|
||||||
|
canvas: Canvas,
|
||||||
|
layout: Layout,
|
||||||
|
startLine: Int,
|
||||||
|
endLine: Int,
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int
|
||||||
|
) {
|
||||||
|
val lineTop = getLineTop(layout, startLine)
|
||||||
|
val lineBottom = getLineBottom(layout, startLine)
|
||||||
|
// get min of start/end for left, and max of start/end for right since we don't
|
||||||
|
// the language direction
|
||||||
|
val left = min(startOffset, endOffset)
|
||||||
|
val right = max(startOffset, endOffset)
|
||||||
|
drawable.setBounds(left, lineTop, right, lineBottom)
|
||||||
|
drawable.draw(canvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the background for text that starts and ends on different lines.
|
||||||
|
*
|
||||||
|
* @param horizontalPadding the padding to be applied to left & right of the background
|
||||||
|
* @param verticalPadding the padding to be applied to top & bottom of the background
|
||||||
|
* @param drawableLeft the drawable used to draw left edge of the background
|
||||||
|
* @param drawableMid the drawable used to draw for whole line
|
||||||
|
* @param drawableRight the drawable used to draw right edge of the background
|
||||||
|
*/
|
||||||
|
internal class MultiLineRenderer(
|
||||||
|
horizontalPadding: Int,
|
||||||
|
verticalPadding: Int,
|
||||||
|
val drawableLeft: Drawable,
|
||||||
|
val drawableMid: Drawable,
|
||||||
|
val drawableRight: Drawable
|
||||||
|
) : TextRoundedBgRenderer(horizontalPadding, verticalPadding) {
|
||||||
|
|
||||||
|
override fun draw(
|
||||||
|
canvas: Canvas,
|
||||||
|
layout: Layout,
|
||||||
|
startLine: Int,
|
||||||
|
endLine: Int,
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int
|
||||||
|
) {
|
||||||
|
// draw the first line
|
||||||
|
val paragDir = layout.getParagraphDirection(startLine)
|
||||||
|
val lineEndOffset = if (paragDir == Layout.DIR_RIGHT_TO_LEFT) {
|
||||||
|
layout.getLineLeft(startLine) - horizontalPadding
|
||||||
|
} else {
|
||||||
|
layout.getLineRight(startLine) + horizontalPadding
|
||||||
|
}.toInt()
|
||||||
|
|
||||||
|
var lineBottom = getLineBottom(layout, startLine)
|
||||||
|
var lineTop = getLineTop(layout, startLine)
|
||||||
|
drawStart(canvas, startOffset, lineTop, lineEndOffset, lineBottom)
|
||||||
|
|
||||||
|
// for the lines in the middle draw the mid drawable
|
||||||
|
for (line in startLine + 1 until endLine) {
|
||||||
|
lineTop = getLineTop(layout, line)
|
||||||
|
lineBottom = getLineBottom(layout, line)
|
||||||
|
drawableMid.setBounds(
|
||||||
|
(layout.getLineLeft(line).toInt() - horizontalPadding),
|
||||||
|
lineTop,
|
||||||
|
(layout.getLineRight(line).toInt() + horizontalPadding),
|
||||||
|
lineBottom
|
||||||
|
)
|
||||||
|
drawableMid.draw(canvas)
|
||||||
|
}
|
||||||
|
|
||||||
|
val lineStartOffset = if (paragDir == Layout.DIR_RIGHT_TO_LEFT) {
|
||||||
|
layout.getLineRight(startLine) + horizontalPadding
|
||||||
|
} else {
|
||||||
|
layout.getLineLeft(startLine) - horizontalPadding
|
||||||
|
}.toInt()
|
||||||
|
|
||||||
|
// draw the last line
|
||||||
|
lineBottom = getLineBottom(layout, endLine)
|
||||||
|
lineTop = getLineTop(layout, endLine)
|
||||||
|
|
||||||
|
drawEnd(canvas, lineStartOffset, lineTop, endOffset, lineBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the first line of a multiline annotation. Handles LTR/RTL.
|
||||||
|
*
|
||||||
|
* @param canvas Canvas to draw onto
|
||||||
|
* @param start start coordinate for the background
|
||||||
|
* @param top top coordinate for the background
|
||||||
|
* @param end end coordinate for the background
|
||||||
|
* @param bottom bottom coordinate for the background
|
||||||
|
*/
|
||||||
|
private fun drawStart(canvas: Canvas, start: Int, top: Int, end: Int, bottom: Int) {
|
||||||
|
if (start > end) {
|
||||||
|
drawableRight.setBounds(end, top, start, bottom)
|
||||||
|
drawableRight.draw(canvas)
|
||||||
|
} else {
|
||||||
|
drawableLeft.setBounds(start, top, end, bottom)
|
||||||
|
drawableLeft.draw(canvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw the last line of a multiline annotation. Handles LTR/RTL.
|
||||||
|
*
|
||||||
|
* @param canvas Canvas to draw onto
|
||||||
|
* @param start start coordinate for the background
|
||||||
|
* @param top top position for the background
|
||||||
|
* @param end end coordinate for the background
|
||||||
|
* @param bottom bottom coordinate for the background
|
||||||
|
*/
|
||||||
|
private fun drawEnd(canvas: Canvas, start: Int, top: Int, end: Int, bottom: Int) {
|
||||||
|
if (start > end) {
|
||||||
|
drawableLeft.setBounds(end, top, start, bottom)
|
||||||
|
drawableLeft.draw(canvas)
|
||||||
|
} else {
|
||||||
|
drawableRight.setBounds(start, top, end, bottom)
|
||||||
|
drawableRight.draw(canvas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
markwon-round-textview/src/main/res/drawable/rounded_text_bg.xml
Executable file
21
markwon-round-textview/src/main/res/drawable/rounded_text_bg.xml
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
<corners android:radius="@dimen/roundedTextBorderRadius"/>
|
||||||
|
</shape>
|
21
markwon-round-textview/src/main/res/drawable/rounded_text_bg_dark.xml
Executable file
21
markwon-round-textview/src/main/res/drawable/rounded_text_bg_dark.xml
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundDarkColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
<corners android:radius="@dimen/roundedTextBorderRadius"/>
|
||||||
|
</shape>
|
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_left.xml
Executable file
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_left.xml
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
<corners android:topLeftRadius="@dimen/roundedTextBorderRadius"
|
||||||
|
android:bottomLeftRadius="@dimen/roundedTextBorderRadius"/>
|
||||||
|
</shape>
|
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_left_dark.xml
Executable file
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_left_dark.xml
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundDarkColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
<corners android:topLeftRadius="@dimen/roundedTextBorderRadius"
|
||||||
|
android:bottomLeftRadius="@dimen/roundedTextBorderRadius"/>
|
||||||
|
</shape>
|
20
markwon-round-textview/src/main/res/drawable/rounded_text_bg_mid.xml
Executable file
20
markwon-round-textview/src/main/res/drawable/rounded_text_bg_mid.xml
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
</shape>
|
20
markwon-round-textview/src/main/res/drawable/rounded_text_bg_mid_dark.xml
Executable file
20
markwon-round-textview/src/main/res/drawable/rounded_text_bg_mid_dark.xml
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundDarkColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
</shape>
|
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_right.xml
Executable file
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_right.xml
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
<corners android:topRightRadius="@dimen/roundedTextBorderRadius"
|
||||||
|
android:bottomRightRadius="@dimen/roundedTextBorderRadius"/>
|
||||||
|
</shape>
|
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_right_dark.xml
Executable file
22
markwon-round-textview/src/main/res/drawable/rounded_text_bg_right_dark.xml
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 The Android Open Source Project
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/codeBackgroundDarkColor"/>
|
||||||
|
<!--<stroke android:width="@dimen/roundedTextBorderWidth" android:color="@color/roundedTextBorder"/>-->
|
||||||
|
<corners android:topRightRadius="@dimen/roundedTextBorderRadius"
|
||||||
|
android:bottomRightRadius="@dimen/roundedTextBorderRadius"/>
|
||||||
|
</shape>
|
11
markwon-round-textview/src/main/res/values/attrs.xml
Normal file
11
markwon-round-textview/src/main/res/values/attrs.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="TextRoundedBgHelper">
|
||||||
|
<attr name="roundedTextHorizontalPadding" format="dimension"/>
|
||||||
|
<attr name="roundedTextVerticalPadding" format="dimension"/>
|
||||||
|
<attr name="roundedTextDrawable" format="reference"/>
|
||||||
|
<attr name="roundedTextDrawableLeft" format="reference"/>
|
||||||
|
<attr name="roundedTextDrawableMid" format="reference"/>
|
||||||
|
<attr name="roundedTextDrawableRight" format="reference"/>
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
6
markwon-round-textview/src/main/res/values/colors.xml
Normal file
6
markwon-round-textview/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="codeTextColor">#EE6A6C</color>
|
||||||
|
<color name="codeBackgroundColor">#F1F2F3</color>
|
||||||
|
<color name="codeBackgroundDarkColor">#252627</color>
|
||||||
|
</resources>
|
8
markwon-round-textview/src/main/res/values/dimens.xml
Normal file
8
markwon-round-textview/src/main/res/values/dimens.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<dimen name="roundedBorderRadius">6dp</dimen>
|
||||||
|
<dimen name="roundedBorderWidth">2dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="roundedTextBorderRadius">4dp</dimen>
|
||||||
|
<dimen name="roundedTextBorderWidth">1dp</dimen>
|
||||||
|
</resources>
|
31
markwon-round-textview/src/main/res/values/styles.xml
Normal file
31
markwon-round-textview/src/main/res/values/styles.xml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<style name="Widget.RoundedBackground" parent="android:Widget"/>
|
||||||
|
<style name="Widget.RoundedBackground.SampleTextView">
|
||||||
|
<item name="roundedTextHorizontalPadding">0dp</item>
|
||||||
|
<item name="roundedTextVerticalPadding">1dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="Widget.RoundedBackground.Divider">
|
||||||
|
<item name="android:background">#CCC</item>
|
||||||
|
<item name="android:padding">2dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="RoundedBgTextView" parent="@android:style/Widget.TextView">
|
||||||
|
<item name="roundedTextHorizontalPadding">0dp</item>
|
||||||
|
<item name="roundedTextVerticalPadding">1dp</item>
|
||||||
|
<item name="roundedTextDrawable">@drawable/rounded_text_bg</item>
|
||||||
|
<item name="roundedTextDrawableLeft">@drawable/rounded_text_bg_left</item>
|
||||||
|
<item name="roundedTextDrawableMid">@drawable/rounded_text_bg_mid</item>
|
||||||
|
<item name="roundedTextDrawableRight">@drawable/rounded_text_bg_right</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="RoundedBgTextDarkView" parent="@android:style/Widget.TextView">
|
||||||
|
<item name="roundedTextHorizontalPadding">0dp</item>
|
||||||
|
<item name="roundedTextVerticalPadding">1dp</item>
|
||||||
|
<item name="roundedTextDrawable">@drawable/rounded_text_bg_dark</item>
|
||||||
|
<item name="roundedTextDrawableLeft">@drawable/rounded_text_bg_left_dark</item>
|
||||||
|
<item name="roundedTextDrawableMid">@drawable/rounded_text_bg_mid_dark</item>
|
||||||
|
<item name="roundedTextDrawableRight">@drawable/rounded_text_bg_right_dark</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
@ -0,0 +1,17 @@
|
|||||||
|
package io.noties.markdown.boundarytext
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
fun addition_isCorrect() {
|
||||||
|
assertEquals(4, 2 + 2)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user