TextField в контейнере — клавиатура скрывает текст

У меня есть TextField в контейнере (VBox) внизу. Когда я выбираю TextField для ввода текста, он скрывается за клавиатурой (iPhone). Я поместил VBox в ScrollPane, но все равно.

Могу ли я заставить клавиатуру как-то получить ее высоту? Как разместить текстовые поля, которые не закрыты клавиатурой?

Спасибо за помощь.


person tonimaroni    schedule 25.11.2016    source источник


Ответы (1)


На данный момент в JavaFX или JavaFXPorts нет встроенного метода для получения (собственной) программной клавиатуры iOS.

Чтобы получить клавиатуру и выяснить, будет ли она покрыта каким-либо узлом, например TextField, потребуется Service из доступных в Gluon Charm Down библиотека, но пока такой KeyboardService нет.

На основе собственных решений, таких как это, легко получить уведомление, когда клавиатура отображается или скрывается. Таким образом, мы могли бы использовать эти слушатели и отправить значение высоты обратно на уровень JavaFX.

Итак, давайте создадим KeyboardService с учетом того, как сервисы создаются в библиотеке Charm Down.

Поскольку здесь это немного выходит за рамки, я создал этот суть с необходимым файлы.

Выполните следующие шаги, чтобы заставить его работать:

  1. Создать проект Gluon

Создайте проект Gluon (одно представление) с последней версией подключаемого модуля Gluon для вашей IDE.

  1. Добавьте интерфейс KeyboardService

Добавьте пакет com.gluonhq.charm.down.plugins. Добавьте классы KeyboardService (ссылка) и KeyboardServiceFactory (ссылка).

public interface KeyboardService {
    public ReadOnlyFloatProperty visibleHeightProperty();
}
  1. Реализация iOS

Под пакетом iOS добавьте реализацию сервиса IOSKeyboardService для 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. Собственный код

Создайте папку native в папке /src/ios и добавьте файл Keyboard.h (ссылка). :

#import <UIKit/UIKit.h>
#include "jni.h"

@interface Keyboard : UIViewController {}
@end

void sendKeyboard();

и файл Keyboard.m (ссылка):

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. Создайте собственную библиотеку

На Mac с последней версией XCode вы можете собрать собственную библиотеку libKeyboard.a. Для этого нужно добавить задачу xcodebuild в файл build.gradle проекта (ссылка ). Он основан на ios-build.gradle file из Charm Down.

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

Сохраните проект и запустите ./gradlew clean build xcodebuild из командной строки в корне проекта.

Если все на месте, вы должны найти libKeyboard.a под build/native. Скопируйте файл, создайте папку jniLibs под src/ios и вставьте его туда.

  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 имеет открытый исходный код, поэтому приветствуется любой вклад.

person José Pereda    schedule 26.11.2016
comment
Великолепно! Спасибо!! - person tonimaroni; 28.11.2016
comment
Привет, Хосе. Я только сегодня нашел время, чтобы реализовать вышеуказанный плагин. Отлично описано и все работает. У меня есть кнопка «Отправить» прямо в текстовое поле. В приведенном выше решении мне нужно дважды нажать «Отправить». В первый раз он удаляет клавиатуру ... затем мне нужно снова нажать кнопку, чтобы она выполнила свою работу. У вас есть идея, что мне нужно изменить, чтобы при активной клавиатуре нажатие кнопки срабатывало в первый раз. Спасибо. - person tonimaroni; 03.05.2017
comment
Замените button.setOnAction() на button.setOnMouseClicked(), должно сработать. Каким-то образом событие fire() потребляется, когда клавиатура закрывается, а onAction не запускается. - person José Pereda; 03.05.2017
comment
Это тоже не сработало. Но это дало мне правильный намек в любом случае. setOnTouchPressed запускается правильно. Еще раз спасибо! - person tonimaroni; 04.05.2017
comment
Привет, Хосе. Развертывание на iOS прошло нормально. Теперь я настроил Android, но не могу его там развернуть. Мне нужно раскомментировать все вышеперечисленное и удалить библиотеку из папки src? Сейчас я борюсь с ошибкой INSTALL_FAILED_NO_MATCHING_ABIS, которая, кажется, говорит о том, что у меня неправильная архитектура. Любая идея? - person tonimaroni; 06.06.2017
comment
Вы выполняете развертывание на эмуляторе Android? Это не сработает. В любом случае будет лучше, если вы опубликуете новый вопрос. - person José Pereda; 06.06.2017
comment
Да, я развертывал на эмуляторе Android. Вы правы, я создам новый вопрос. - person tonimaroni; 06.06.2017