GameTextInput   Android Game Development Kit 的一部分。

对于编写使用软键盘进行文本输入的全屏 Android 应用,使用 GameTextInput 库是的一种更加简单的替代方案。

GameTextInput 提供了简单的 API,用于显示或隐藏软键盘、设置或获取当前修改过的文本,以及在文本发生更改时收到通知。此库并不适用于功能齐全的文本编辑器应用,但仍可以为游戏中的典型用例提供选择和撰写区域方面的支持。此外,此库还支持高级输入法 (IME) 功能,例如拼写检查、补全和多键输入字符。

在系统内部,GameTextInput 会在内部缓冲区 GameTextInput::currentState_ 累积输入文本(以及相关状态),并在出现更改时通知应用。然后,应用会在其注册的回调函数中执行文本处理。

可用的使用方式

您可以通过以下方式使用 GameTextInput

  • 与 GameActivity 搭配使用:GameActivity 会与 GameTextInput 集成。使用 GameActivity 的应用只能使用经过集成的 GameTextInput。您可以访问 GameActivity 页面,查看使用说明全文。如需 GameActivity 与 GameTextInput 的集成示例,请访问 games-samples 库。不过,这种使用模式并不在本指南的说明范围内。

  • 作为独立库:本指南的其余部分将会介绍具体的使用步骤。

请注意,上述两种方式相互排斥。

您可以通过以下渠道获取正式的 GameTextInput 版本:

本指南介绍的是第一种用例。如需使用 ZIP 文件版本,请参阅相关软件包随附的操作说明。

设置 build

GameTextInputAndroid Archive (AAR) 的形式进行分发。此 AAR 文件包含 Java 类和可实现 GameTextInput 的原生功能的 C 源代码。您需要通过 Prefab 在构建流程中添加这些源文件,该工具会向您的 CMake 项目NDK build 公开原生库或源代码。

  1. 按照 Jetpack Android 游戏页面中的说明操作,将 GameTextInput 库依赖项添加到游戏的 build.gradle 文件中。请注意,如果您的应用使用的是 GameActivity,则无法使用独立的 GameTextInput 库。

  2. 确保 gradle.properties 包含以下几行代码:

    # Tell Android Studio we are using AndroidX.
    android
    .useAndroidX=true
    # Use Prefab 1.1.2 or higher, which contains a fix for "header only" libs.
    android
    .prefabVersion=1.1.2
    # Required only if you're using Android Studio 4.0 (4.1 is recommended).
    # android.enablePrefab=true
  3. 在项目的 CMakeLists.txt 文件中,导入 game-text-input 软件包并将其添加到目标中:

    find_package(game-text-input REQUIRED CONFIG)
    ...
    target_link_libraries
    (... game-text-input::game-text-input)
  4. 在游戏中的某个 .cpp 文件中,添加以下代码行,以包含 GameTextInput 实现:

    #include <game-text-input/gametextinput.cpp>
  5. 在使用 GameTextInput C API 的源文件中添加头文件:

    #include <game-text-input/gametextinput.h>
  6. 编译并运行应用。如果您遇到 CMake 错误,请验证 AAR 和 build.gradle 文件是否设置正确。如果未找到 #include 文件,请验证您的 CMakeLists.txt 配置文件。

集成 build

  1. 在已连接到 JVM 的 C 线程或应用主线程中,使用 JNIEnv 指针调用 GameTextInput_init

    static GameTextInput* gameTextInput = nullptr;

    extern "C"
    JNIEXPORT
    void JNICALL
    Java_com_gametextinput_testbed_MainActivity_onCreated(JNIEnv* env,
      jobject
    this) {
    {
       
    if(!gameTextInput)
          gameTextInput
    = GameTextInput_init(env);
       
    ...
    }
  2. 创建一个能够访问 InputConnectionInputEnabledTextView Java 类。

    public class InputEnabledTextView extends View implements Listener {
     
    public InputConnection mInputConnection;
     
    public InputEnabledTextView(Context context, AttributeSet attrs) {
       
    super(context, attrs);
     
    }

     
    public InputEnabledTextView(Context context) {
       
    super(context);
     
    }
     
    public void createInputConnection(int inputType) {
       
    EditorInfo editorInfo = new EditorInfo();
        editorInfo
    .inputType = inputType;
        editorInfo
    .actionId = IME_ACTION_NONE;
        editorInfo
    .imeOptions = IME_FLAG_NO_FULLSCREEN;
        mInputConnection
    = new InputConnection(this.getContext(), this,
               
    new Settings(editorInfo, true)
       
    ).setListener(this);
     
    }

     
    @Override
     
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
       
    if (outAttrs != null) {
           
    GameTextInput.copyEditorInfo(mInputConnection.getEditorInfo(), outAttrs);
       
    }
       
    return mInputConnection;
     
    }

     
    // Called when the IME input changes.
     
    @Override
     
    public void stateChanged(State newState, boolean dismissed) {
        onTextInputEventNative
    (newState);
     
    }
     
    @Override
     
    public void onImeInsetsChanged(Insets insets) {
       
    // handle Inset changes here
     
    }

     
    private native void onTextInputEventNative(State softKeyboardEvent);
    }
  3. 向界面布局添加创建的 InputEnabledTextView。例如,activity_main.xml 中的以下代码可将其置于屏幕底部:

    <com.android.example.gametextinputjava.InputEnabledTextView
       
    android:id="@+id/input_enabled_text_view"
       
    android:layout_width="wrap_content"
       
    android:layout_height="wrap_content"
       
    app:layout_constraintBottom_toBottomOf="parent"
       
    app:layout_constraintEnd_toEndOf="parent"
       
    app:layout_constraintStart_toStartOf="parent" />
  4. 将这个新的 InputEnabledTextView 类检索到 Java activity 中。如果您使用视图绑定,这会相对简单一些:

    public class MainActivity extends AppCompatActivity {
     
    ...
     
    private ActivityMainBinding binding;
     
    private InputEnabledTextView inputEnabledTextView;

     
    private native void setInputConnectionNative(InputConnection c);

     
    @Override
     
    protected void onCreate(Bundle savedInstanceState) {
       
    ...
        binding
    = ActivityMainBinding.inflate(getLayoutInflater());
        inputEnabledTextView
    = binding.inputEnabledTextView;
        inputEnabledTextView
    .createInputConnection(InputType.TYPE_CLASS_TEXT);
        setInputConnectionNative
    (inputEnabledTextView.mInputConnection);
     
    }
  5. 在 C 库中,将 inputConnection 传递到 GameTextInput_setInputConnection 中。在 GameTextInput_setEventCallback 中传递一个回调,以便以 C 状态结构体 GameTextInputState 的形式收到事件通知。

    extern "C"JNIEXPORT void JNICALL
    Java_com_gametextinput_testbed_MainActivity_setInputConnectionNative(
     
    JNIEnv *env, jobject this, jobject inputConnection) {
     
    GameTextInput_setInputConnection(gameTextInput, inputConnection);
     
    GameTextInput_setEventCallback(gameTextInput,[](void *ctx, const GameTexgtInputState *state) {
       
    if (!env || !state) return;
       
    // process the newly arrived text input from user.
        __android_log_print
    (ANDROID_LOG_INFO, "TheGreateGameTextInput", state->text_UTF8);
     
    }, env);
    }
  6. 在 C 库中调用 GameTextInput_processEvent,该方法会在内部调用您在上一步注册的回调,以便应用在状态发生更改时处理事件。

    extern "C"
    JNIEXPORT
    void JNICALL
    Java_com_gametextinput_testbed_InputEnabledTextView_onTextInputEventNative(
     
    JNIEnv* env, jobject this, jobject soft_keyboard_event) {
     
    GameTextInput_processEvent(gameTextInput, soft_keyboard_event);
    }

实用函数

GameTextInput 库包含实用函数,可让您在 Java 状态对象和 C 状态结构体之间进行转换。通过 GameTextInput_showImeGameTextInput_hideIme 函数使用显示和隐藏 IME 的功能。

参考资料

在使用 GameTextInput 创建应用时,开发者可能发现以下资源很有帮助:

反馈

如果对 GameTextInput 有任何问题和疑问,请在 Google IssueTracker 上创建 bug