Skip to content

Commit 69b1d11

Browse files
feat(android): enriched text lineHeight
1 parent bfc1ceb commit 69b1d11

5 files changed

Lines changed: 67 additions & 7 deletions

File tree

android/src/main/java/com/swmansion/enriched/text/EnrichedTextView.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.swmansion.enriched.common.pixelFromSpOrDp
3030
import com.swmansion.enriched.text.spans.EnrichedTextImageSpan
3131
import com.swmansion.enriched.text.spans.interfaces.EnrichedTextClickableSpan
3232
import com.swmansion.enriched.text.spans.interfaces.EnrichedTextSpan
33+
import com.swmansion.enriched.textinput.spans.EnrichedLineHeightSpan
3334
import kotlin.math.ceil
3435

3536
class EnrichedTextView : AppCompatTextView {
@@ -41,13 +42,15 @@ class EnrichedTextView : AppCompatTextView {
4142
private var fontWeight: Int = ReactConstants.UNSET
4243
private var fontSize: Float = EnrichedConstants.TEXT_DEFAULT_FONT_SIZE
4344
private var fontSizeRaw: Float? = null
45+
private var lineHeight: Float? = null
4446
private var htmlStyleMap: ReadableMap? = null
4547
var allowFontScaling: Boolean = EnrichedConstants.ALLOW_FONT_SCALING_DEFAULT
4648
set(value) {
4749
if (field == value) return
4850
field = value
4951
fontSizeRaw?.let { setFontSize(it) }
5052
htmlStyleMap?.let { setHtmlStyle(it) }
53+
applyLineSpacing()
5154
}
5255

5356
private var enrichedStyle: EnrichedTextStyle? = null
@@ -185,6 +188,7 @@ class EnrichedTextView : AppCompatTextView {
185188
parsedText = null
186189
this.text = text
187190
}
191+
applyLineSpacing()
188192
}
189193

190194
private fun parseText(
@@ -305,6 +309,33 @@ class EnrichedTextView : AppCompatTextView {
305309
setTextSize(TypedValue.COMPLEX_UNIT_PX, sizeInt)
306310
}
307311

312+
fun setLineHeight(height: Float) {
313+
lineHeight = if (height == 0f) null else height
314+
applyLineSpacing()
315+
}
316+
317+
private fun applyLineSpacing() {
318+
val currentText = text ?: return
319+
val spannable =
320+
currentText as? Spannable ?: SpannableString(currentText)
321+
spannable
322+
.getSpans(0, spannable.length, EnrichedLineHeightSpan::class.java)
323+
.forEach { spannable.removeSpan(it) }
324+
325+
lineHeight?.let {
326+
spannable.setSpan(
327+
EnrichedLineHeightSpan(it, allowFontScaling),
328+
0,
329+
spannable.length,
330+
Spannable.SPAN_INCLUSIVE_INCLUSIVE,
331+
)
332+
}
333+
334+
if (spannable !== currentText) {
335+
setText(spannable, BufferType.SPANNABLE)
336+
}
337+
}
338+
308339
fun setFontFamily(family: String?) {
309340
if (family != fontFamily) {
310341
fontFamily = family

android/src/main/java/com/swmansion/enriched/text/EnrichedTextViewManager.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ class EnrichedTextViewManager :
5353
view?.setFontSize(value)
5454
}
5555

56+
override fun setLineHeight(
57+
view: EnrichedTextView?,
58+
value: Float,
59+
) {
60+
view?.setLineHeight(value)
61+
}
62+
5663
override fun setFontFamily(
5764
view: EnrichedTextView?,
5865
value: String?,

android/src/main/java/com/swmansion/enriched/text/MeasurementStore.kt

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import android.content.Context
44
import android.graphics.Typeface
55
import android.graphics.text.LineBreaker
66
import android.os.Build
7+
import android.text.Spannable
8+
import android.text.SpannableString
79
import android.text.StaticLayout
810
import android.text.TextPaint
911
import android.text.TextUtils
@@ -21,6 +23,7 @@ import com.swmansion.enriched.common.GumboNormalizer
2123
import com.swmansion.enriched.common.allowFontScalingFromProps
2224
import com.swmansion.enriched.common.parser.EnrichedParser
2325
import com.swmansion.enriched.common.pixelFromSpOrDp
26+
import com.swmansion.enriched.textinput.spans.EnrichedLineHeightSpan
2427
import kotlin.math.ceil
2528

2629
object MeasurementStore {
@@ -134,6 +137,13 @@ object MeasurementStore {
134137
return props.getBoolean("useHtmlNormalizer")
135138
}
136139

140+
private fun lineHeightFromProps(props: ReadableMap?): Float {
141+
if (props == null || !props.hasKey("lineHeight") || props.isNull("lineHeight")) {
142+
return 0f
143+
}
144+
return props.getDouble("lineHeight").toFloat()
145+
}
146+
137147
private fun getInitialFontSize(props: ReadableMap?): Float {
138148
val propsFontSize = props?.getDouble("fontSize")?.toFloat() ?: EnrichedConstants.TEXT_DEFAULT_FONT_SIZE
139149
val fontSize =
@@ -151,15 +161,31 @@ object MeasurementStore {
151161
props: ReadableMap?,
152162
): Long {
153163
val fontSize = getInitialFontSize(props)
154-
val text = getInitialText(context, fontSize.toInt(), props)
164+
val rawText = getInitialText(context, fontSize.toInt(), props)
165+
val lineHeight = lineHeightFromProps(props)
166+
val allowFontScaling = allowFontScalingFromProps(props)
167+
168+
val measuredText: CharSequence =
169+
if (lineHeight > 0f) {
170+
val spannable = SpannableString(rawText)
171+
spannable.setSpan(
172+
EnrichedLineHeightSpan(lineHeight, allowFontScaling),
173+
0,
174+
spannable.length,
175+
Spannable.SPAN_INCLUSIVE_INCLUSIVE,
176+
)
177+
spannable
178+
} else {
179+
rawText
180+
}
155181

156182
val fontFamily = props?.getString("fontFamily")
157183
val numberOfLines = props?.getInt("numberOfLines") ?: 0
158184
val ellipsizeMode = props?.getString("ellipsizeMode")
159185
val fontStyle = parseFontStyle(props?.getString("fontStyle"))
160186
val fontWeight = parseFontWeight(props?.getString("fontWeight"))
161187
val typeface = applyStyles(null, fontStyle, fontWeight, fontFamily, context.assets)
162-
val size = measure(width, text, typeface, fontSize, numberOfLines, ellipsizeMode)
188+
val size = measure(width, measuredText, typeface, fontSize, numberOfLines, ellipsizeMode)
163189

164190
return size
165191
}

android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedLineHeightSpan.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ class EnrichedLineHeightSpan(
2929
v: Int,
3030
fm: Paint.FontMetricsInt,
3131
) {
32-
val spannable = text as? Spannable ?: return
33-
// Do not modify line height for headings
34-
// In the future we may consider adding custom lineHeight support for each paragraph style
35-
if (spannable.getSpans(start, end, EnrichedHeadingSpan::class.java).isNotEmpty()) return
36-
3732
val lineHeightPx = pixelFromSpOrDp(lineHeight, allowFontScaling)
3833
val currentHeight = (fm.descent - fm.ascent).toFloat()
3934
if (lineHeightPx <= currentHeight) return

android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/conversions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ inline folly::dynamic toDynamic(const EnrichedTextViewProps &props) {
3434
serializedProps["fontWeight"] = props.fontWeight;
3535
serializedProps["fontStyle"] = props.fontStyle;
3636
serializedProps["fontFamily"] = props.fontFamily;
37+
serializedProps["lineHeight"] = props.lineHeight;
3738
serializedProps["numberOfLines"] = props.numberOfLines;
3839
serializedProps["ellipsizeMode"] = props.ellipsizeMode;
3940
serializedProps["allowFontScaling"] = props.allowFontScaling;

0 commit comments

Comments
 (0)