Android 扫码枪输入时屏蔽软键盘和顶部状态栏

这是个扫码枪回车输入扫码内容的界面,常用于收银收款等场景
前期踩了很多坑,网上的资料也因为 Android 历史版本不同有各种兼容问题,最后总结了下
在无霸屏设置的 android 设备上使用如下方案可有效避免界面弹出软键盘和显示顶部状态栏问题,环境为 Android 7.1.2
屏蔽软键盘:自动聚焦 的 inputType 设置为 none
隐藏顶部状态:方案一 hideStatusBar 必须在 setContentView 之前,方案二在 styles 中设置 NoActionBar 具体可自行搜索

  • AndroidManifest.xml
<activity
    android:name=".MyActivity"
    android:windowSoftInputMode="stateHidden"
    android:exported="false" />
  • activity_my.xml
<EditText
    android:id="@+id/scanInput"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:focusedByDefault="true"
    android:importantForAutofill="no"
    android:inputType="none" />
  • MyActivity.kt
class MyActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMyBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMyBinding.inflate(layoutInflater)
        hideStatusBar()
        setContentView(binding.root)
        hideSoftKeyboard()
        initListener()
    }

    override fun onResume() {
        super.onResume()
        hideSoftKeyboard()
        hideActionBar()
    }

    private fun hideSoftKeyboard() {
        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
        this.currentFocus?.let { view ->
            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
            imm?.hideSoftInputFromWindow(view.windowToken, InputMethodManager.RESULT_HIDDEN)
        }
    }

    private fun hideStatusBar() {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        window.setFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN
        )
    }

    private fun hideActionBar() {
        window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
        actionBar?.hide()
    }

    private fun initListener() {
        binding.scanInput.requestFocus()
        binding.scanInput.setOnKeyListener { _, keyCode, keyEvent ->
            if (keyCode == KeyEvent.KEYCODE_ENTER && keyEvent.action == KeyEvent.ACTION_UP) {
                val code = binding.scanInput.text.toString()
                // to do with code
                binding.scanInput.text = null
                return@setOnKeyListener true
            }
            false
        }
    }

}

如果是 Jetpack Compose 布局或者不想用 EditText 获取输入,那么可以在 Activity 内用 dispatchKeyEvent 事件获取,
需要注意的是 KeyEvent 并不能直接转为我们想要的字符,所以需要用 KeyListener 和 Editable 组合输入,并最终获取类似输入框中的字符串

class MyActivity : ComponentActivity() {
    private val tag = "MainActivity"
    private var isFocus = false
    private val tkl: KeyListener = TextKeyListener(Capitalize.NONE, false)
    private val et: Editable = Editable.Factory.getInstance().newEditable("")

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        isFocus = hasFocus
        Log.i(tag, "hasFocus: $hasFocus")
    }

    private fun onKey(event: KeyEvent): Boolean {
        return when (event.action) {
            KeyEvent.ACTION_DOWN -> {
                tkl.onKeyDown(null, et, event.keyCode, event)
            }
            KeyEvent.ACTION_UP -> {
                tkl.onKeyUp(null, et, event.keyCode, event)
            }
            else -> {
                tkl.onKeyOther(null, et, event)
            }
        }
    }

    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        if (isFocus) {
            if (event.action == KeyEvent.ACTION_UP && event.keyCode == KeyEvent.KEYCODE_ENTER) {
                Log.i(tag, "[dispatchKeyEvent] enter: ${et}")
                et.clear()
                return true
            } else if (onKey(event)) {
                return true
            }
        }
        return super.dispatchKeyEvent(event)
    }
}

如有问题或建议,欢迎大家评论区讨论指正!

posted @ 2024-10-11 11:17  huelse  阅读(340)  评论(1编辑  收藏  举报