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

自定义ScanInputView的OnEditorActionListener无法触发问题求助

自定义ScanInputView的OnEditorActionListener无法触发问题求助

大家好,我现在遇到一个头疼的问题——我给自定义的ScanInputView设置了OnEditorActionListener,但无论按回车键还是点击软键盘的完成按钮,这个监听器都触发不了。我已经试过改imeOptions,比如从actionDone改成actionGo,但完全没用,希望各位能帮我看看问题出在哪!

先给大家贴一下相关代码:

使用ScanInputView的Fragment代码

class WMScanEmpfaengerFragment : TransactionNavigationFragment<WMScanEmpfaengerViewModel>() {
    private lateinit var binding: FragmentScanEmpfaengerBinding

    override fun getViewModelClass() = WMScanEmpfaengerViewModel::class
    override fun getContentLayoutResId() = R.layout.fragment_scan_empfaenger
    override fun isTransactionRoot() = true
    override var barcodeScannerEnabled = true

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        binding = FragmentScanEmpfaengerBinding.inflate(layoutInflater)
        
        binding.scaninputView.setOnEditorActionListener(
            OnEditorActionListener { v, actionId, event ->
                if (event != null && event.keyCode == KeyEvent.KEYCODE_ENTER 
                    || actionId == EditorInfo.IME_ACTION_DONE && v.text.isNotBlank()) {
                    setEmpfaenger(v.text.toString().trim())
                    true
                }
                false
            })
    }
}

自定义View ScanInputView代码

class ScanInputView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
    private val binding: ViewScaninputBinding = ViewScaninputBinding.inflate(LayoutInflater.from(context), this)

    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScanInputView)
        val hint = typedArray.getString(R.styleable.ScanInputView_hint)
        val imeNext = typedArray.getBoolean(R.styleable.ScanInputView_imeNext, false)
        typedArray.recycle()

        binding.inputId.showSoftInputOnFocus = false
        binding.inputId.addTextChangedListener(AppUtils.onTextChanged {
            binding.inputLayoutId.error = null
        })
        setHint(hint)

        if (imeNext) 
            binding.inputId.imeOptions = EditorInfo.IME_ACTION_NEXT

        binding.btnKeyboard.setOnClickListener {
            val keyboard = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            if (!binding.inputId.hasFocus()) {
                binding.inputId.requestFocus()
                moveCursorToEnd()
            }
            keyboard.showSoftInput(binding.inputId, 0)
        }
    }

    fun setOnEditorActionListener(editorActionListener: TextView.OnEditorActionListener) {
        binding.inputId.setOnEditorActionListener(editorActionListener)
    }

    // 省略其他方法...
}

ScanInputView对应的布局XML

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:layout_height="wrap_content"
    tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"
    android:id="@+id/viewScanInput">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/input_layout_id"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintEnd_toStartOf="@id/btn_keyboard"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/img_topbanner">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/input_id"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:saveEnabled="false"
            android:imeOptions="actionDone"
            android:inputType="text"
            android:maxLines="1"
            android:singleLine="true" />
    </com.google.android.material.textfield.TextInputLayout>

    <ImageButton
        android:id="@+id/btn_keyboard"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_marginTop="14sp"
        android:background="?attr/selectableItemBackgroundBorderless"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/input_layout_id"
        app:layout_constraintTop_toTopOf="@id/input_layout_id"
        app:srcCompat="@drawable/ic_icon_keyboard"
        app:tint="@color/colorPrimary" />
</merge>

问题排查与解决方案

我仔细梳理了你的代码,发现几个可能导致监听器不触发的关键点,咱们逐个解决:

1. 监听器返回值逻辑错误(最可能的原因)

你当前的监听器写法有逻辑漏洞:if{... true} false 这种结构会导致不管条件是否满足,最终都会返回false,因为if块里的true并没有作为整个lambda的返回值。正确的写法需要明确返回结果:

binding.scaninputView.setOnEditorActionListener { v, actionId, event ->
    // 只处理按键抬起事件,避免重复触发
    val isEnterUp = event != null && event.action == KeyEvent.ACTION_UP && event.keyCode == KeyEvent.KEYCODE_ENTER
    val isDoneAction = actionId == EditorInfo.IME_ACTION_DONE && v.text.isNotBlank()
    
    if (isEnterUp || isDoneAction) {
        setEmpfaenger(v.text.toString().trim())
        return@OnEditorActionListener true // 明确标记事件已被消费
    }
    false
}

2. ImeOptions可能被覆盖

在ScanInputView的初始化代码中,如果imeNext属性为true,会将输入框的imeOptions设为IME_ACTION_NEXT,但你在Fragment里判断的是IME_ACTION_DONE,这会导致条件不匹配。

如果你的场景需要使用IME_ACTION_DONE,请确保:

  • 在布局中给ScanInputView设置app:imeNext="false"
  • 或者在ScanInputView的init代码中补全默认逻辑:
if (imeNext) {
    binding.inputId.imeOptions = EditorInfo.IME_ACTION_NEXT
} else {
    binding.inputId.imeOptions = EditorInfo.IME_ACTION_DONE // 明确默认值
}

3. 确保事件能传递到输入框

因为ScanInputView是继承自ConstraintLayout,有可能父布局拦截了按键事件。可以在ScanInputView中重写dispatchKeyEvent,确保事件优先传递给内部输入框:

override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
    // 先让内部输入框处理事件,处理成功就直接返回
    return binding.inputId.dispatchKeyEvent(event) || super.dispatchKeyEvent(event)
}

4. 焦点与软键盘设置验证

你设置了showSoftInputOnFocus = false,这会阻止自动弹出软键盘,但要确保输入框能正常获取焦点——点击键盘按钮时已经做了requestFocus(),手动点击输入框时也应该能触发焦点获取。


按这个顺序调整代码后,再测试按回车键或软键盘完成按钮,应该就能正常触发setEmpfaenger方法了。如果还有问题,可以补充一下测试时的焦点状态、软键盘类型等细节~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 14:58:00