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
版本:
- Google Maven 会提供 Jetpack 游戏库版本
- AGDK 下载页面会提供 ZIP 文件版本
本指南介绍的是第一种用例。如需使用 ZIP 文件版本,请参阅相关软件包随附的操作说明。
设置 build
GameTextInput
以 Android Archive (AAR) 的形式进行分发。此 AAR 文件包含 Java 类和可实现 GameTextInput
的原生功能的 C 源代码。您需要通过 Prefab
在构建流程中添加这些源文件,该工具会向您的 CMake 项目或 NDK build 公开原生库或源代码。
按照 Jetpack Android 游戏页面中的说明操作,将
GameTextInput
库依赖项添加到游戏的build.gradle
文件中。请注意,如果您的应用使用的是 GameActivity,则无法使用独立的GameTextInput
库。确保
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
在项目的
CMakeLists.txt
文件中,导入game-text-input
软件包并将其添加到目标中:find_package(game-text-input REQUIRED CONFIG) ... target_link_libraries(... game-text-input::game-text-input)
在游戏中的某个
.cpp
文件中,添加以下代码行,以包含GameTextInput
实现:#include <game-text-input/gametextinput.cpp>
在使用
GameTextInput
C API 的源文件中添加头文件:#include <game-text-input/gametextinput.h>
编译并运行应用。如果您遇到 CMake 错误,请验证 AAR 和
build.gradle
文件是否设置正确。如果未找到#include
文件,请验证您的CMakeLists.txt
配置文件。
集成 build
在已连接到 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); ... }
创建一个能够访问
InputConnection
的InputEnabledTextView
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); }
向界面布局添加创建的
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" />
将这个新的
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); }
在 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); }
在 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_showIme
和 GameTextInput_hideIme
函数使用显示和隐藏 IME 的功能。
参考资料
在使用 GameTextInput
创建应用时,开发者可能发现以下资源很有帮助:
反馈
如果对 GameTextInput
有任何问题和疑问,请在 Google IssueTracker 上创建 bug。