日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

flutter實現掃碼槍獲取數據源禁止系統鍵盤彈窗示例詳解_Android

作者:李小轟_Rex ? 更新時間: 2023-02-26 編程語言

序言

小編在項目中有遇到使用 flutter 實現掃碼槍接入的需求。為方便使用,小編把能力封裝成 package 并發布。好記性不如爛筆頭,下面是該插件的使用方式,以及途中遇到的坑和處理想法。

使用方式:

  • 在pubspec.yaml文件中進行引用:
dependencies:
  scan_gun: ^1.0.0
  • 提供 ScanMonitorWidget 作為父節點,嵌套使用:
  ScanMonitorWidget({
    Key? key,
    required ChildBuilder childBuilder,
    FocusNode? scanNode,
    FocusNode? textFiledNode,
    required void Function(String) onSubmit,
  })

參數說明:

  • childBuilder :

typedef ChildBuilder = Widget Function(BuildContext context),使用者自己UI作為子節點

  • scanNode:

非必傳,如果傳,可通過 scanNode 監聽獲取當前掃碼可用狀態,hasFocus 時為可用也可通過 scanNode requestFocus 方法,強制掃碼獲取焦點,保證掃碼能力

  • textFiledNode:

提供外部存在輸入框鍵盤輸入與掃碼輸入同時存在的場景。內部做了焦點切換能力,保證輸入框焦點取消后,能馬上切換成掃碼槍的焦點

  • onSubmit:

接收掃碼槍返回的結果

兩種場景能力支持

  • 無輸入框交互,獲取掃碼結果:
@override
  Widget build(BuildContext context) {
    return ScanMonitorWidget(
      childBuilder: (context) {
        return body();
      },
      onSubmit: (String result) {
        print(result); //接收到掃碼結果
      },
    );
  }
  • 帶輸入框交互,獲取掃碼結果:
FocusNode textFiledNode = FocusNode();
TextEditingController controller = TextEditingController();
 Widget body() {
  return TextField(
     focusNode: textFiledNode,
     controller: controller,
   );
 }
@override
  Widget build(BuildContext context) {
    return ScanMonitorWidget(
      textFiledNode: textFiledNode,
      childBuilder: (context) {
        return body();
      },
      onSubmit: (String result) {
        print(result); //接收到掃碼結果
      },
    );
  }

github 源碼已上傳 :傳送門

目前該方案為非通用方案,依賴 flutter 版本進行定制,小編使用的是 Flutter 2.8.1 ,后續更新通用方案。

技術點分析

1. 如何獲取掃碼槍輸入內容

使用過 flutter 編寫輸入框的同學都用過 TextField ,通過源碼我們可以看到 TextField 的功能實現者是它的子節點:EditableText

掃碼槍本質上是一個外接的輸入設備。將 EditableText 封裝,控制隱藏。可通過獲取 EditableText 的內容來獲取掃碼槍的輸入內容。

控制隱藏可使用 Offstage 標簽:

    return Stack(
      children: [
        //讓輸入框保持隱藏
        Offstage(child: edtWidget, offstage: true),
        child,
      ],
    );

2. 鍵盤彈出問題

使用 EditableText 的過程中遇到了系統鍵盤彈出的問題。我們通過 Edit 的焦點來獲取掃碼槍的輸入。但 EditableText 一旦獲取了焦點,內部會調用原生層喚起鍵盤。這個問題怎么處理呢?

首先,我們來看看源碼中 EditableText 是如何喚起鍵盤的。 省略非關鍵代碼,直接定位到 EditableTextState

當焦點變化時,調用了 _openOrCloseInputConnectionIfNeeded()

_openInputConnection() 方法中通過 TextInput 喚起系統鍵盤

既然了解到了EditableText喚起鍵盤的邏輯,通過自定義 EditableText,將 TextInput.show 步驟過濾掉,只保留單純的通過焦點獲取輸入源內容的能力。

3. 擴展,如何自定義監聽數據源輸入

TextInput 源碼中,可以發現鍵盤等輸入的數據通過 MessageChannel 的方式進行數據流轉:

由于篇幅原因,這里小編只做拋磚引玉。下面列出核心代碼部分:

  void listenKeyboard() {
    SystemChannels.textInput.setMethodCallHandler((call) => _handleTextInputInvocation(call));
  }
String scanData = '';
void _update(){
    setState(() {});
  }
Future<dynamic> _handleTextInputInvocation(MethodCall methodCall) async {
    final String method = methodCall.method;
    final List<dynamic> args = methodCall.arguments as List<dynamic>;
    switch (method) {
      case 'TextInputClient.updateEditingState': //每次的內容變化會進來這里
        final data = TextEditingValue.fromJSON(args[1] as Map<String, dynamic>);
        final text = data.text;
        scanData += text;
        dev.log('rex: -updateEditingState - $text');
        break;
      case 'TextInputClient.performAction':
        final action = args[1] as String;
        dev.log('rex: -performAction - $action');
        if(action == 'TextInputAction.none'){ //點擊確定
          _update();
        }
        break;
      default:
        throw MissingPluginException();
    }
  }

原文鏈接:https://juejin.cn/post/7163845736411430920

欄目分類
最近更新