From 9fb49dd1914a39cc53e8c43dbcff338dc214a7fa Mon Sep 17 00:00:00 2001 From: root Date: Tue, 18 Aug 2026 22:55:17 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Fix=20initial=20Android?= =?UTF-8?q?=20TextInput=20underline=20color?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../react/views/textinput/ReactEditText.kt | 38 +++++++++++++++++++ .../views/textinput/ReactTextInputManager.kt | 24 +----------- .../textinput/ReactTextInputPropertyTest.kt | 15 ++++++++ 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt index e27330c87149..da13e14bfef2 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt @@ -13,8 +13,10 @@ import android.content.res.Configuration import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint +import android.graphics.PorterDuff import android.graphics.Rect import android.graphics.Typeface +import android.graphics.drawable.Drawable import android.os.Build import android.os.Bundle import android.text.Editable @@ -66,6 +68,7 @@ import com.facebook.react.uimanager.PixelUtil.toDIPFromPixel import com.facebook.react.uimanager.ReactAccessibilityDelegate import com.facebook.react.uimanager.StateWrapper import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.drawable.CompositeBackgroundDrawable import com.facebook.react.uimanager.events.EventDispatcher import com.facebook.react.uimanager.style.BorderRadiusProp import com.facebook.react.uimanager.style.BorderStyle @@ -138,6 +141,8 @@ public open class ReactEditText public constructor(context: Context) : AppCompat private var fontFamily: String? = null private var fontWeight = ReactConstants.UNSET private var fontStyle = ReactConstants.UNSET + private var hasUnderlineColor = false + private var underlineColor: Int? = null internal var parsedFontVariationSettings: String? = null private set @@ -1058,6 +1063,39 @@ public open class ReactEditText public constructor(context: Context) : AppCompat setBackgroundColor(this, color) } + internal fun setUnderlineColor(color: Int?) { + hasUnderlineColor = true + underlineColor = color + applyUnderlineColor() + } + + override fun setBackgroundDrawable(background: Drawable?) { + super.setBackgroundDrawable(background) + if (hasUnderlineColor) { + applyUnderlineColor() + } + } + + private fun applyUnderlineColor() { + var drawableToMutate = + (background as? CompositeBackgroundDrawable)?.originalBackground ?: background ?: return + + if (drawableToMutate.constantState != null) { + try { + drawableToMutate = checkNotNull(drawableToMutate.mutate()) + } catch (e: NullPointerException) { + FLog.e(TAG, "NullPointerException when setting underlineColorAndroid for TextInput", e) + } + } + + if (underlineColor == null) { + drawableToMutate.clearColorFilter() + } else { + @Suppress("DEPRECATION") + drawableToMutate.setColorFilter(checkNotNull(underlineColor), PorterDuff.Mode.SRC_IN) + } + } + public fun setBorderWidth(position: Int, width: Float) { setBorderWidth(this, LogicalEdge.entries[position], toDIPFromPixel(width)) } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt index 49a75f012c62..966ee5ee122d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt @@ -524,29 +524,7 @@ public open class ReactTextInputManager public constructor() : @ReactProp(name = "underlineColorAndroid", customType = "Color") public fun setUnderlineColor(view: ReactEditText, underlineColor: Int?) { - // Drawable.mutate() can sometimes crash due to an AOSP bug: - // See https://code.google.com/p/android/issues/detail?id=191754 for more info - val background = view.background - var drawableToMutate = background - - if (background == null) { - return - } - - if (background.constantState != null) { - try { - drawableToMutate = checkNotNull(background.mutate()) - } catch (e: NullPointerException) { - FLog.e(TAG, "NullPointerException when setting underlineColorAndroid for TextInput", e) - } - } - - if (underlineColor == null) { - drawableToMutate.clearColorFilter() - } else { - @Suppress("DEPRECATION") - drawableToMutate.setColorFilter(underlineColor, PorterDuff.Mode.SRC_IN) - } + view.setUnderlineColor(underlineColor) } @SuppressLint("WrongConstant") diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt index 4a6f6cc7560d..9d1640fe9a93 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.kt @@ -12,6 +12,7 @@ package com.facebook.react.views.textinput import android.graphics.Color +import android.graphics.drawable.ColorDrawable import android.os.Build import android.text.InputFilter import android.text.InputFilter.AllCaps @@ -96,6 +97,20 @@ class ReactTextInputPropertyTest { assertThat(view.inputType and InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS).isZero } + @Test + fun testUnderlineColorAppliedWhenBackgroundBecomesAvailable() { + view.background = null + + manager.setUnderlineColor(view, Color.RED) + + val background = ColorDrawable(Color.WHITE) + view.background = background + assertThat(background.colorFilter).isNotNull() + + manager.setUnderlineColor(view, null) + assertThat(background.colorFilter).isNull() + } + @Test fun testAutoCapitalize() { manager.updateProperties(view, buildStyles())