You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Jetpack Compose TextField配置仅支持货币正则输入的InputFilter?是否可使用InputFilter列表实现特定货币格式输入限制?

How to Configure InputFilter for Jetpack Compose TextField to Accept Currency Format Matching Regex?

Question:

How can I configure an InputFilter for Jetpack Compose's TextField to only accept currency format inputs that match a regex pattern? Specifically, I want to allow formats like $1,01 or $100,95. Here's how I implemented similar logic using EditText:

class CurrencyFormatInputFilter : InputFilter {
    private val pattern = Pattern.compile(CURRENCY_INPUT_REGEX)
    override fun filter(
        source: CharSequence, start: Int, end: Int, dest: Spanned, dstart: Int, dend: Int
    ): CharSequence? {
        val result = (dest.subSequence(0, dstart).toString() + source.toString() + dest.subSequence(dend, dest.length))
        val matcher = pattern.matcher(result)
        return if (!matcher.matches()) dest.subSequence(dstart, dend) else null
    }
}
// Usage
editText.filters = arrayOf(CurrencyFormatInputFilter(), InputFilter.LengthFilter(8))

Answer:

Great question! In Jetpack Compose, TextField doesn’t expose a direct filters property like EditText, but we have two straightforward ways to replicate this behavior: using a custom TextFilter (Compose’s equivalent of InputFilter) or handling validation directly in the onValueChange callback. Let’s break this down with practical examples.

1. Custom TextFilter (Reusable, Analogous to InputFilter)

Compose provides the TextFilter interface, which works almost identically to Android View's InputFilter. We can build a reusable filter for currency validation:

import androidx.compose.ui.text.input.TextFilter
import android.text.Spanned
import java.util.regex.Pattern

class CurrencyTextFilter(private val pattern: Pattern) : TextFilter {
    override fun filter(
        source: CharSequence,
        start: Int,
        end: Int,
        dest: Spanned,
        dstart: Int,
        dend: Int
    ): CharSequence? {
        // Build the full text that would result from the proposed input
        val newText = dest.subSequence(0, dstart).toString() +
                      source.subSequence(start, end) +
                      dest.subSequence(dend, dest.length)
        
        val matcher = pattern.matcher(newText)
        // Reject the change if the new text doesn't match the pattern
        return if (!matcher.matches()) dest.subSequence(dstart, dend) else null
    }
}

To use this filter, define a regex that supports partial valid inputs (for better user experience) and pass it to your TextField:

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import java.util.regex.Pattern

@Composable
fun CurrencyTextField() {
    // Regex allows incremental input: "$", "$1", "$123,", "$123,95"
    val currencyPattern = Pattern.compile("^\\$\\d{0,3}(,\\d{0,2})?$")
    val textState = remember { mutableStateOf("") }

    Column {
        TextField(
            value = textState.value,
            onValueChange = { textState.value = it },
            filter = CurrencyTextFilter(currencyPattern),
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
            label = { Text("Enter Currency (e.g., $100,95)") },
            maxLines = 1
        )
    }
}

2. Direct Filtering in onValueChange (Simpler, No Reusable Filter)

If you don’t need a reusable filter, handling validation directly in onValueChange is more concise:

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType

@Composable
fun CurrencyTextField() {
    val currencyRegex = Regex("^\\$\\d{0,3}(,\\d{0,2})?$")
    val maxLength = 8 // Matches the LengthFilter from your EditText example
    val textState = remember { mutableStateOf("") }

    Column {
        TextField(
            value = textState.value,
            onValueChange = { newText ->
                // Only update the state if input is valid and within length limit
                if (newText.length <= maxLength && (newText.isEmpty() || currencyRegex.matches(newText))) {
                    textState.value = newText
                }
            },
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
            label = { Text("Enter Currency (e.g., $100,95)") },
            maxLines = 1
        )
    }
}

Key Tips for Better UX:

  • Partial Input Support: The regex ^\\$\\d{0,3}(,\\d{0,2})?$ lets users type incrementally (e.g., start with $, add digits, then the comma and cents). A strict regex like ^\\$\\d{1,3},\\d{2}$ would block partial inputs, making it impossible to build the valid format step-by-step.
  • Length Restriction: We added a maxLength check in the onValueChange example to replicate the InputFilter.LengthFilter(8) from your EditText code.
  • Keyboard Type: Using KeyboardType.Number helps users enter digits quickly, though they’ll still need to type $ and , manually (you could add a visual transformation to auto-inject the $ if needed).

内容的提问来源于stack exchange,提问作者Thracian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:19:07