当前位置: 首页 > 知识库问答 >
问题:

如何用占位符填充编辑文本,直到它没有被填充

计和顺
2023-03-14

我遇到了以下问题:当手机应该输入EditText时,我需要实现这种情况的解决方案。这部手机应该有不可移动的部分,最后四个数字应该在开头填写下划线,然后当用户键入下划线时,应该将其更改为数字,例如:

< code> 12345____ -

我实现了不可移除的部分。我是这样做的:

binding.etPhoneNumber.filters = arrayOf(InputFilter.LengthFilter(args.phoneNumber?.length ?: 0))

binding.etPhoneNumber.doAfterTextChanged {
            val symbolsLeft = it?.toString()?.length ?: 0
            if (symbolsLeft < phoneNumberUi.length) {
                binding.etPhoneNumber.setText(phoneNumberUi)
                binding.etPhoneNumber.setSelection(symbolsLeft + 1)
            }
        }

但现在我不明白,如何处理下划线的逻辑。我尝试在< code>doAfterTextChanged中添加下划线,比如if ((args.phoneNumber?。长度?: 0)


共有3个答案

邬英武
2023-03-14

我认为富国有一个好主意,将文本视图与编辑文本相结合,以产生您正在寻找的内容。您可以将这些字段作为单独的字段放置在布局中,也可以将它们放置在复合视图中。无论哪种方式,效果都是一样的,你可以实现你想要的。

您已经弄清楚了如何处理字段开头的静态文本。我在下面介绍的是如何处理下划线,以便输入的字符看起来会覆盖下划线。

在演示中,我将带有静态文本的文本放在自定义编辑文本旁边。真正感兴趣的是自定义编辑文本。使用自定义视图时,onDraw() 函数将被覆盖,以将下划线写入背景。尽管这些下划线将像字段中的任何其他字符一样显示,但不能以任何方式选择、删除、跳过或操作它们,除非在用户键入时,下划线会逐个覆盖。对自定义视图的末尾填充进行操作,以便为下划线和文本提供空间。

以下是自定义视图:

EditTextFillInBlanks.kt

class EditTextFillInBlanks @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : androidx.appcompat.widget.AppCompatEditText(context, attrs, defStyleAttr) {

    // Right padding before we manipulate it
    private var mBaseRightPadding = 0

    // Width of text that has been entered
    private var mTextWidth = 0f

    // Mad length of data that can be entered in characters
    private var mMaxLength = 0

    // The blanks (underscores) that we will show
    private lateinit var mBlanks: String

    // MeasureSpec for measuring width of entered characters.
    private val mUnspecifiedWidthHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)

    init {
        mBaseRightPadding = paddingRight
        doOnTextChanged { text, _, _, _ ->
            measure(mUnspecifiedWidthHeight, mUnspecifiedWidthHeight)
            mTextWidth = measuredWidth.toFloat() - paddingStart - paddingEnd
            updatePaddingForBlanks(text)
        }
        setText("", BufferType.EDITABLE)
    }

    /*
        Make sure that the end padding is sufficient to hold the blanks that we are showing.
        The blanks (underscores) are written into the expanded padding.
     */
    private fun updatePaddingForBlanks(text: CharSequence?) {
        if (mMaxLength <= 0) {
            mMaxLength = determineMaxLen()
            check(mMaxLength > 0) { "Maximum length must be > 0" }
        }
        text?.apply {
            val blanksCount = max(0, mMaxLength - length)
            mBlanks = "_".repeat(blanksCount).apply {
                updatePadding(right = mBaseRightPadding + paint.measureText(this).toInt())
            }
        }
    }

    /*
        Draw the underscores on the canvas. They will appear as characters in the field but
        cannot be manipulated by the user.
     */
    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        if (mBlanks.isNotEmpty()) {
            canvas?.withSave {
                drawText(mBlanks, paddingStart + mTextWidth, baseline.toFloat(), paint)
            }
        }
    }

    fun setMaxLen(maxLen: Int) {
        mMaxLength = maxLen
    }

    private fun determineMaxLen(): Int {
        // Before Lollipop, we can't get max for InputFilter.LengthFilter
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return 0

        return filters.firstOrNull { it is InputFilter.LengthFilter }
            ?.let {
                it as InputFilter.LengthFilter
                it.max
            } ?: 0
    }
}

activity_main.xml(活动_主.xml)

<androidx.constraintlayout.widget.ConstraintLayout 
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_blue_light"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:paddingStart="8dp"
        android:paddingTop="8dp"
        android:text="+12345"
        android:textColor="@android:color/black"
        android:textSize="36sp"
        app:layout_constraintBaseline_toBaselineOf="@id/editableSuffix"
        app:layout_constraintEnd_toStartOf="@+id/editableSuffix"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintStart_toStartOf="@+id/guideline2" />

    <com.example.edittextwithblanks.EditTextFillInBlanks
        android:id="@+id/editableSuffix"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/edittext_background"
        android:inputType="number"
        android:maxLength="@integer/blankFillLen"
        android:paddingTop="8dp"
        android:paddingEnd="8dp"
        android:textColor="@android:color/black"
        android:textSize="36sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="____">

        <requestFocus />
    </com.example.edittextwithblanks.EditTextFillInBlanks>

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="92dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private val mStaticStart = "+12345"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (BuildConfig.VERSION_CODE < Build.VERSION_CODES.P) {
            val maxLen = resources.getInteger(R.integer.blankFillLen)
            findViewById<EditTextFillInBlanks>(R.id.editableSuffix).setMaxLen(maxLen)
        }
    }
}

很可能您可以将静态文本处理合并到自定义视图中,以获得完整的解决方案

丁均
2023-03-14
匿名用户

此方法具有以下条件分支

  • 用户添加其输入的位置(不可移动部件或可更改部件)
  • 输入的字符(数字或退格)

的工作原理是在 onTextChanged() 及其索引(第二个参数)中获取输入的字符(数字/退格),并根据这两个值设置新的 EditText 值。

此外,编辑文本的值由当前文本变量跟踪。因此,我们一次只能替换一个字符,这是用户完成的输入,以避免操纵整个文本的负担。

您可以通过代码通过下面的注释找到其余的解释:

attachTextWatcher(findViewById(R.id.edittext))

fun attachTextWatcher(editText: EditText) {

    // set the cursor to the first underscore
    editText.setSelection(editText.text.indexOf("_"))

    var currentText = editText.text.toString() // which is "+12345____"

    val watcher: TextWatcher = object : TextWatcher {

        override fun onTextChanged(
            s: CharSequence,
            newCharIndex: Int, // "newCharIndex" is the index of the new entered char
            before: Int,
            count: Int
        ) {

            // New entered char by the user that triggers the TextWatcher callbacks
            val newChar = s.subSequence(newCharIndex, newCharIndex + count).toString().trim()

            /* Stop the listener in order to programmatically
            change the EditText Without triggering the TextWatcher*/
            editText.removeTextChangedListener(this)

            // Setting the new text of the EditText upon examining the user input
            currentText =
                if (newChar.isEmpty()) { // User entered backspace to delete a char
                    if (newCharIndex in 0..5) { // The backspace is pressed in the non-removable part
                        "+12345" + currentText.substring(6)

                    } else { // The backspace is pressed in the changeable part
                        val sb = StringBuilder(currentText)
                        // replace the the number at which backspace pressed with underscore
                        sb.setCharAt(newCharIndex, '_')
                        sb.toString()
                    }

                } else { // User entered a number
                    if (newCharIndex in 0..5) { // The number is entered in the non-removable part
                        // replace the first underscore with the entered number
                        val sb = StringBuilder(currentText)
                        sb.setCharAt(sb.indexOf("_"), newChar[0])
                        sb.toString()

                    } else { // The number is entered in the changeable part
                        if (newCharIndex < 10) { // Avoid ArrayOutOfBoundsException as the number length should not exceed 10
                            val sb = StringBuilder(currentText)
                            // replace the the number at which the number is entered with the new number
                            sb.setCharAt(newCharIndex, newChar[0])
                            sb.toString()
                        } else currentText
                    }
                }

            // Set the adjusted text to the EditText
            editText.setText(currentText)

            // Set the current cursor place
            if (editText.text.contains("_"))
                editText.setSelection(editText.text.indexOf("_"))
            else
                editText.setSelection(editText.text.length)

            // Re-add the listener, so that the EditText can intercept the number by the user
            editText.addTextChangedListener(this)
        }

        override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
        }

        override fun afterTextChanged(s: Editable) {
        }
    }

    editText.addTextChangedListener(watcher)
}

这是我正在测试的布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/edittext"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"
        android:maxLength="11"
        android:text="+12345____"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

注意:确保在配置更改时< code>currentText的值不变。

预览

穆智刚
2023-03-14

您可以删除长度过滤器并检查长度在 do 之后文本已更改

    val phoneNumberUi = "+12345"
    val length = 10

    binding.etPhoneNumber.doAfterTextChanged {
        when {
            it == null -> {
            }
            // missing / incomplete prefix
            it.length < phoneNumberUi.length -> {
                it.replace(0, it.length, phoneNumberUi)
            }
            // prefix was edited
            !it.startsWith(phoneNumberUi) -> {
                it.replace(0, phoneNumberUi.length, phoneNumberUi)
            }
            // too short
            it.length < length -> {
                it.append("_".repeat(length - it.length))
            }
            // too long
            it.length > length -> {
                it.replace(length, it.length, "")
            }
            // set the cursor at the first _
            it.indexOf("_") >= 0 -> {
                binding.etPhoneNumber.setSelection(it.indexOf("_"))
            }
        }
    }

注意:这使用 when,因为每个更改都会立即触发递归调用 do后文本已更改

 类似资料:
  • 因此,我试图在我的JavaFX应用程序中创建一个自定义节点,它从扩展而来,因此可以自己进行渲染。我一开始只是试着画一个文本“Hello world”在画布上,但可惜它没有出现,即使我可以通过鼠标事件处理程序确认应用程序中是否存在自定义节点。 简而言之,如果我将这个的一个新实例添加到一个

  • Telegram机器人向我发送了一条带有文本片段的消息,我想对其进行编辑,并将其发送回机器人进行进一步处理。 复制和粘贴需要时间。重新键入消息需要时间。 理想情况下,我想按下机器人消息上的内联按钮“编辑”,并让消息文本出现在我的回复输入框中进行编辑。(以某种方式附加到我的回复的消息ID将是一个加号)。 我试着使用除/start*之外的参数的深度链接,但这似乎不起作用。 我可以使用机器人API(或任

  • 问题内容: 如何从文本文件填充? 问题答案: 非常模糊的问题。您是说要每行输入一个吗?如果是这样,则要使用BufferedReader之类的东西,请读取所有行,并将它们保存为String数组。创建一个新的JComboBox传入该String构造函数。

  • 假设我有这样一个模型 和这样的文档。 如果我执行以下操作,页面将永远不会加载。 如果里面有一个实际的ObjectID,它可以正常工作,但当它是空白的时候就不行了。 如果值中没有ObjectID,是否有一种方法可以默认为null?

  • 假设我有一个整数数组,如和一个简单的字符串,如。我如何循环通过数组和填充每一个值。假设是这样的: 输出: 到目前为止,我已经尝试了以下内容: 但是,它在print语句中给出了。解决这个问题最好的方法是什么?

  • 我可以用以下代码填充文本框注释,但文本不会出现在某些阅读器中,比如Adobe Acrobat,尽管它确实出现在Chrome和其他基于Webkit的浏览器中。我试图填写的PDF文件不使用AcroForms或FDF。我使用的是ApachePDFBox,但我认为PDF库中没有太大差异,即使是跨语言/平台。 我尝试过将我的PDF输出与填充Chrome的文档进行比较,但我看到的唯一区别是默认外观(DA)属性