react-native-highlight-text-view 0.1.32 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -14,6 +14,7 @@ import android.util.TypedValue
|
|
|
14
14
|
import android.view.Gravity
|
|
15
15
|
import androidx.appcompat.widget.AppCompatEditText
|
|
16
16
|
import com.facebook.react.common.assets.ReactFontManager
|
|
17
|
+
import kotlin.math.abs
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Custom EditText that mimics the iOS implementation by drawing per-character
|
|
@@ -141,6 +142,12 @@ class HighlightTextView : AppCompatEditText {
|
|
|
141
142
|
val paint = paint
|
|
142
143
|
val radius = if (highlightBorderRadius > 0f) highlightBorderRadius else cornerRadius
|
|
143
144
|
|
|
145
|
+
// Precompute horizontal alignment flags once per draw pass
|
|
146
|
+
val horizontalGravity = gravity and Gravity.HORIZONTAL_GRAVITY_MASK
|
|
147
|
+
val isLeftAlignedView = horizontalGravity == Gravity.START || horizontalGravity == Gravity.LEFT
|
|
148
|
+
val isRightAlignedView = horizontalGravity == Gravity.END || horizontalGravity == Gravity.RIGHT
|
|
149
|
+
val isCenterAlignedView = horizontalGravity == Gravity.CENTER_HORIZONTAL
|
|
150
|
+
|
|
144
151
|
val length = text.length
|
|
145
152
|
if (length == 0) return
|
|
146
153
|
|
|
@@ -194,14 +201,22 @@ class HighlightTextView : AppCompatEditText {
|
|
|
194
201
|
xStart + paint.measureText(text, i, i + 1)
|
|
195
202
|
}
|
|
196
203
|
|
|
197
|
-
// Vertical bounds based on
|
|
198
|
-
|
|
199
|
-
val
|
|
204
|
+
// Vertical bounds based on font metrics around the baseline, so
|
|
205
|
+
// they are independent from Android's line spacing mechanics.
|
|
206
|
+
val baseline = layout.getLineBaseline(line).toFloat()
|
|
207
|
+
val fm = paint.fontMetrics
|
|
200
208
|
|
|
201
209
|
var left = xStart
|
|
202
210
|
var right = xEnd
|
|
203
|
-
var top =
|
|
204
|
-
var bottom =
|
|
211
|
+
var top = baseline + fm.ascent
|
|
212
|
+
var bottom = baseline + fm.descent
|
|
213
|
+
|
|
214
|
+
// For right-aligned text, ensure the outermost character on each line
|
|
215
|
+
// snaps to the line's visual right edge so the highlight's right side
|
|
216
|
+
// forms a clean vertical column across wrapped lines.
|
|
217
|
+
if (isRightAlignedView && !hasRightNeighbor) {
|
|
218
|
+
right = layout.getLineRight(line)
|
|
219
|
+
}
|
|
205
220
|
|
|
206
221
|
// First shrink by background insets (from the line box)
|
|
207
222
|
top += backgroundInsetTop
|
|
@@ -215,25 +230,6 @@ class HighlightTextView : AppCompatEditText {
|
|
|
215
230
|
top -= charPaddingTop
|
|
216
231
|
bottom += charPaddingBottom
|
|
217
232
|
|
|
218
|
-
if (customLineSpacing < 0f) {
|
|
219
|
-
val originalLineTop = layout.getLineTop(line).toFloat()
|
|
220
|
-
val originalLineBottom = layout.getLineBottom(line).toFloat()
|
|
221
|
-
|
|
222
|
-
if (line > 0 && top < originalLineTop) {
|
|
223
|
-
val prevLineBottom = layout.getLineBottom(line - 1).toFloat()
|
|
224
|
-
if (top < prevLineBottom) {
|
|
225
|
-
top = prevLineBottom
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (line < layout.lineCount - 1 && bottom > originalLineBottom) {
|
|
230
|
-
val nextLineTop = layout.getLineTop(line + 1).toFloat()
|
|
231
|
-
if (bottom > nextLineTop) {
|
|
232
|
-
bottom = nextLineTop
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
233
|
if (right <= left || bottom <= top) continue
|
|
238
234
|
|
|
239
235
|
backgroundRect.set(left, top, right, bottom)
|
|
@@ -242,11 +238,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
242
238
|
val isFirstLineOfParagraph = line == 0 || isLineEmpty(text, layout, line - 1)
|
|
243
239
|
val isLastLineOfParagraph = line == layout.lineCount - 1 || isLineEmpty(text, layout, line + 1)
|
|
244
240
|
|
|
245
|
-
//
|
|
246
|
-
val
|
|
247
|
-
val
|
|
248
|
-
val
|
|
249
|
-
val isCenterAligned = horizontalGravity == Gravity.CENTER_HORIZONTAL
|
|
241
|
+
// Use precomputed text alignment flags
|
|
242
|
+
val isLeftAligned = isLeftAlignedView
|
|
243
|
+
val isRightAligned = isRightAlignedView
|
|
244
|
+
val isCenterAligned = isCenterAlignedView
|
|
250
245
|
|
|
251
246
|
var tl = 0f
|
|
252
247
|
var tr = 0f
|
|
@@ -273,8 +268,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
273
268
|
tr = radius
|
|
274
269
|
} else {
|
|
275
270
|
val prevLineWidth = layout.getLineMax(line - 1)
|
|
276
|
-
// Round Top-Right if
|
|
277
|
-
tr = if (currentLineWidth
|
|
271
|
+
// Round Top-Right only if this line extends further than the line above
|
|
272
|
+
tr = if (!lineWidthsEqual(currentLineWidth, prevLineWidth) &&
|
|
273
|
+
currentLineWidth > prevLineWidth
|
|
274
|
+
) radius else 0f
|
|
278
275
|
}
|
|
279
276
|
|
|
280
277
|
// Bottom-Right
|
|
@@ -282,8 +279,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
282
279
|
br = radius
|
|
283
280
|
} else {
|
|
284
281
|
val nextLineWidth = layout.getLineMax(line + 1)
|
|
285
|
-
// Round Bottom-Right if
|
|
286
|
-
br = if (currentLineWidth
|
|
282
|
+
// Round Bottom-Right only if this line extends further than the line below
|
|
283
|
+
br = if (!lineWidthsEqual(currentLineWidth, nextLineWidth) &&
|
|
284
|
+
currentLineWidth > nextLineWidth
|
|
285
|
+
) radius else 0f
|
|
287
286
|
}
|
|
288
287
|
}
|
|
289
288
|
}
|
|
@@ -307,8 +306,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
307
306
|
tl = radius
|
|
308
307
|
} else {
|
|
309
308
|
val prevLineWidth = layout.getLineMax(line - 1)
|
|
310
|
-
// Round Top-Left if
|
|
311
|
-
tl = if (currentLineWidth
|
|
309
|
+
// Round Top-Left only if this line extends further than the line above
|
|
310
|
+
tl = if (!lineWidthsEqual(currentLineWidth, prevLineWidth) &&
|
|
311
|
+
currentLineWidth > prevLineWidth
|
|
312
|
+
) radius else 0f
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
// Bottom-Left
|
|
@@ -316,8 +317,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
316
317
|
bl = radius
|
|
317
318
|
} else {
|
|
318
319
|
val nextLineWidth = layout.getLineMax(line + 1)
|
|
319
|
-
// Round Bottom-Left if
|
|
320
|
-
bl = if (currentLineWidth
|
|
320
|
+
// Round Bottom-Left only if this line extends further than the line below
|
|
321
|
+
bl = if (!lineWidthsEqual(currentLineWidth, nextLineWidth) &&
|
|
322
|
+
currentLineWidth > nextLineWidth
|
|
323
|
+
) radius else 0f
|
|
321
324
|
}
|
|
322
325
|
}
|
|
323
326
|
}
|
|
@@ -333,8 +336,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
333
336
|
tl = radius
|
|
334
337
|
} else {
|
|
335
338
|
val prevLineWidth = layout.getLineMax(line - 1)
|
|
336
|
-
// Round Top-Left if
|
|
337
|
-
tl = if (currentLineWidth
|
|
339
|
+
// Round Top-Left only if this line extends further than the line above
|
|
340
|
+
tl = if (!lineWidthsEqual(currentLineWidth, prevLineWidth) &&
|
|
341
|
+
currentLineWidth > prevLineWidth
|
|
342
|
+
) radius else 0f
|
|
338
343
|
}
|
|
339
344
|
|
|
340
345
|
// Bottom-Left
|
|
@@ -342,8 +347,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
342
347
|
bl = radius
|
|
343
348
|
} else {
|
|
344
349
|
val nextLineWidth = layout.getLineMax(line + 1)
|
|
345
|
-
// Round Bottom-Left if
|
|
346
|
-
bl = if (currentLineWidth
|
|
350
|
+
// Round Bottom-Left only if this line extends further than the line below
|
|
351
|
+
bl = if (!lineWidthsEqual(currentLineWidth, nextLineWidth) &&
|
|
352
|
+
currentLineWidth > nextLineWidth
|
|
353
|
+
) radius else 0f
|
|
347
354
|
}
|
|
348
355
|
}
|
|
349
356
|
|
|
@@ -354,8 +361,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
354
361
|
tr = radius
|
|
355
362
|
} else {
|
|
356
363
|
val prevLineWidth = layout.getLineMax(line - 1)
|
|
357
|
-
// Round Top-Right if
|
|
358
|
-
tr = if (currentLineWidth
|
|
364
|
+
// Round Top-Right only if this line extends further than the line above
|
|
365
|
+
tr = if (!lineWidthsEqual(currentLineWidth, prevLineWidth) &&
|
|
366
|
+
currentLineWidth > prevLineWidth
|
|
367
|
+
) radius else 0f
|
|
359
368
|
}
|
|
360
369
|
|
|
361
370
|
// Bottom-Right
|
|
@@ -363,8 +372,10 @@ class HighlightTextView : AppCompatEditText {
|
|
|
363
372
|
br = radius
|
|
364
373
|
} else {
|
|
365
374
|
val nextLineWidth = layout.getLineMax(line + 1)
|
|
366
|
-
// Round Bottom-Right if
|
|
367
|
-
br = if (currentLineWidth
|
|
375
|
+
// Round Bottom-Right only if this line extends further than the line below
|
|
376
|
+
br = if (!lineWidthsEqual(currentLineWidth, nextLineWidth) &&
|
|
377
|
+
currentLineWidth > nextLineWidth
|
|
378
|
+
) radius else 0f
|
|
368
379
|
}
|
|
369
380
|
}
|
|
370
381
|
}
|
|
@@ -382,6 +393,11 @@ class HighlightTextView : AppCompatEditText {
|
|
|
382
393
|
}
|
|
383
394
|
}
|
|
384
395
|
|
|
396
|
+
private fun lineWidthsEqual(w1: Float, w2: Float): Boolean {
|
|
397
|
+
// Small tolerance so lines that should visually match are treated as equal
|
|
398
|
+
return abs(w1 - w2) < 0.5f
|
|
399
|
+
}
|
|
400
|
+
|
|
385
401
|
private fun isLineEmpty(text: CharSequence, layout: android.text.Layout, line: Int): Boolean {
|
|
386
402
|
if (line < 0 || line >= layout.lineCount) return false
|
|
387
403
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-highlight-text-view",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
4
4
|
"description": "A native text input for React Native that supports inline text highlighting",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|