GameTextInput   Android 游戏开发工具包 的一部分。

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

GameTextInput 提供了一个简单的 API 来显示或隐藏软键盘,设置或获取当前编辑的文本,并在文本更改时接收通知。这并非旨在用于全功能的文本编辑器应用程序,但仍为游戏中典型的用例提供了选择和撰写区域支持。此外,此库还支持高级 输入法编辑器 (IME) 功能,例如拼写检查、自动完成和多键字符。

在内部,GameTextInput 将输入文本(以及相关状态)累积到内部缓冲区 GameTextInput::currentState_ 并通知应用程序其任何更改。然后,应用程序在其注册的回调函数中执行文本处理。

可用性

GameTextInput 可以通过以下方式使用

  • 与 GameActivity 结合使用:GameActivity 集成了 GameTextInput。使用 GameActivity 的应用程序只能使用集成的 GameTextInput。使用说明在 GameActivity 页面 上进行了全面记录。有关 GameActivity 和 GameTextInput 集成的示例,请参阅 games-samples 存储库。此使用模型不在本指南的范围内。

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

请注意,以上两种方法是互斥的。

正式的 GameTextInput 版本在以下渠道提供

本指南涵盖了第一个使用案例。要使用 zip 文件版本,请参阅包内附带的说明。

设置构建

GameTextInput 作为 Android 归档 (AAR) 分发。此 AAR 包含 Java 类和 C 源代码,它们实现了 GameTextInput 的原生功能。您需要通过 Prefab 将这些源文件包含在您的构建过程中,Prefab 将原生库和源代码公开给您的 CMake 项目NDK 构建

  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. 导入 game-text-input 包并将其添加到项目 CMakeLists.txt 文件中的目标中

    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 配置文件。

集成构建

  1. 从已附加到 JVM 的 C 线程或应用程序主线程调用 GameTextInput_init,并使用 JNIEnv 指针。

    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 添加到 UI 布局中。例如,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 活动中。当您使用 视图绑定 时,这非常简单

    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 上创建错误