【问题标题】:TextField in a Container - Keyboard hides Text容器中的文本字段 - 键盘隐藏文本
【发布时间】:2016-11-25 09:39:09
【问题描述】:

我在底部的容器 (VBox) 中有一个 TextField。当我选择 TextField 输入一些文本时,它会隐藏在键盘 (iPhone) 后面。我把 VBox 放在 ScrollPane 中,但还是一样。

我可以让键盘以某种方式获得它的高度吗?如何放置键盘未覆盖的文本字段?

感谢您的帮助。

【问题讨论】:

    标签: javafx gluon-mobile


    【解决方案1】:

    目前,JavaFX 或 JavaFXPorts 中没有内置方法来获取(原生)iOS 软键盘。

    获取键盘并找出是否有任何节点(如 TextField 将被它覆盖)的解决方案需要 Gluon Charm Down library 中可用的 Service,但现在有没有这样的KeyboardService

    基于this 等原生解决方案,在显示或隐藏键盘时很容易收到通知。所以我们可以利用这些监听器并将高度值发送回 JavaFX 层。

    让我们创建KeyboardService,同时考虑到服务是如何在 Charm Down 库中创建的。

    由于这里有点超出范围,我用所需的文件创建了这个gist

    按照以下步骤使其工作:

    1. 创建 Gluon 项目

    使用最新版本的 Gluon 插件为您的 IDE 创建一个 Gluon 项目(单一视图)。

    1. 添加 KeyboardService 接口

    添加包com.gluonhq.charm.down.plugins。添加类 KeyboardService (link) 和 KeyboardServiceFactory (link)。

    public interface KeyboardService {
        public ReadOnlyFloatProperty visibleHeightProperty();
    }
    
    1. iOS 实施

    在 iOS 包下添加服务 IOSKeyboardService (link) 的 iOS 实现。

    public class IOSKeyboardService implements KeyboardService {
    
        static {
            System.loadLibrary("Keyboard");
            initKeyboard();
        }
    
        private static ReadOnlyFloatWrapper height = new ReadOnlyFloatWrapper();
    
        @Override
        public ReadOnlyFloatProperty visibleHeightProperty() {
            return height.getReadOnlyProperty();
        }
    
        // native
        private static native void initKeyboard();
    
        private void notifyKeyboard(float height) {
            Platform.runLater(() -> this.height.setValue(height));
        }
    
    }
    
    1. 本机代码

    /src/ios 下创建native 文件夹并添加Keyboard.h (link) 文件:

    #import <UIKit/UIKit.h>
    #include "jni.h"
    
    @interface Keyboard : UIViewController {}
    @end
    
    void sendKeyboard();
    

    还有Keyboard.m (link) 文件:

    static int KeyboardInited = 0;
    jclass mat_jKeyboardServiceClass;
    jmethodID mat_jKeyboardService_notifyKeyboard = 0;
    Keyboard *_keyboard;
    CGFloat currentKeyboardHeight = 0.0f;
    
    JNIEXPORT void JNICALL Java_com_gluonhq_charm_down_plugins_ios_IOSKeyboardService_initKeyboard
    (JNIEnv *env, jclass jClass)
    {
        if (KeyboardInited)
        {
            return;
        }
        KeyboardInited = 1;
    
        mat_jKeyboardServiceClass = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "com/gluonhq/charm/down/plugins/ios/IOSKeyboardService"));
        mat_jKeyboardService_notifyKeyboard = (*env)->GetMethodID(env, mat_jKeyboardServiceClass, "notifyKeyboard", "(F)V");
        GLASS_CHECK_EXCEPTION(env);
    
        _keyboard = [[Keyboard alloc] init];
    }
    
    void sendKeyboard() {
        GET_MAIN_JENV;
        (*env)->CallVoidMethod(env, mat_jKeyboardServiceClass, mat_jKeyboardService_notifyKeyboard, currentKeyboardHeight);
    }
    
    @implementation Keyboard 
    
    - (void) startObserver 
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    }
    
    - (void) stopObserver 
    {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
    }
    
    - (void)keyboardWillShow:(NSNotification*)notification {
        NSDictionary *info = [notification userInfo];
        CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
        currentKeyboardHeight = kbSize.height;
        sendKeyboard();
    }
    
    - (void)keyboardWillHide:(NSNotification*)notification {
        currentKeyboardHeight = 0.0f;
        sendKeyboard();
    }
    
    @end
    

    1. 构建原生库

    在装有最新版本 XCode 的 Mac 上,您可以构建原生库 libKeyboard.a。为此,您需要将xcodebuild 任务添加到项目的build.gradle 文件(link)中。它基于 Charm Down 中的 ios-build.gradle file

    task xcodebuild {
        doLast {
            xcodebuildIOS("$project.buildDir","$project.projectDir", "Keyboard")
        }
    }
    

    保存您的项目,然后从项目根目录下的命令行运行./gradlew clean build xcodebuild

    如果一切就绪,您应该在build/native 下找到libKeyboard.a。复制文件,在src/ios下创建文件夹jniLibs,然后粘贴到那里。

    1. 实施服务

    TextField 添加到BasicView,并将对齐方式更改为BOTTOM-CENTER

    VBox controls = new VBox(15.0, label, button, new TextField());
    controls.setAlignment(Pos.BOTTOM_CENTER);
    

    实施服务:

    Services.get(KeyboardService.class).ifPresent(keyboard -> {
        keyboard.visibleHeightProperty().addListener((obs, ov, nv) -> 
            setTranslateY(-nv.doubleValue()));
    });
    
    1. 部署和运行

    您应该准备好一切。插入您的 iPhone/iPad,然后运行 ​​./gradlew --info launchIOSDevice

    当 textField 获得焦点时,软键盘出现,并且视图被翻译,所以 textField 完全可见:

    希望这项服务会在某个时候包含在 Charm Down 中。但这也是如何添加自定义服务的一个很好的例子。另请注意,Charm Down 项目是开源的,因此欢迎任何贡献。

    【讨论】:

    • 太棒了!谢谢!!
    • 嘿何塞。我今天才找到时间来实现上面的插件。完美描述,一切正常。我有一个文本字段的“发送”按钮。使用上面的解决方案,我必须按两次“发送”。第一次它删除了键盘.. 然后我必须再次单击该按钮才能让它完成他的工作。你知道我需要改变什么,所以当键盘处于活动状态时,第一次按下按钮会被触发。谢谢。
    • button.setOnAction() 替换为button.setOnMouseClicked(),应该可以。当键盘被关闭且onAction 未被触发时,不知何故会消耗fire() 事件。
    • 那也没用。但无论如何它给了我正确的提示。 setOnTouchPressed 被正确触发。再次感谢您!
    • 你好何塞。部署到 iOs 很好。现在我已经设置了 Android,但未能在那里部署它。我是否需要取消注释以上所有内容并从 src 文件夹中删除 lib?我现在正在为错误 INSTALL_FAILED_NO_MATCHING_ABIS 苦苦挣扎,这似乎表明我有错误的架构。有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 2014-03-18
    • 2011-01-19
    • 1970-01-01
    • 2018-12-22
    • 2021-05-07
    • 2021-05-20
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多