Libgdx文本框中的回车键处理

6
我在我的libgdx应用程序中设置了一个舞台,其中有三个文本字段,在桌面模式和Android模式下获得不同的行为。在Android上,键入回车键会将光标移动到下一个文本字段。在桌面上,键入回车键没有任何作用。
如何使光标在两个平台上始终移动?当用户键入enter时,我希望能够将焦点设置到另一个字段。在Android上,无论我将焦点设置到什么地方,默认的回车键行为都会跳转到该字段之后的字段。
这是我目前使用的代码,用于移动光标并清除下一个字段:
    stage.addListener(new InputListener() {
        @Override
        public boolean keyUp(InputEvent event, int keycode) {
            if (keycode == Input.Keys.ENTER) {
                nextField();
            }
            return false;
        }
    });
    Gdx.input.setInputProcessor(stage);
}

private void nextField() {
    TextField nextField = 
            stage.getKeyboardFocus() == text1
            ? text2
            : stage.getKeyboardFocus() == text2
            ? text3
            : text1;
    nextField.setText("");
    stage.setKeyboardFocus(nextField);
}

我尝试取消事件或从处理程序方法返回true,但焦点仍然在我的代码完成后移动。
我的完整示例代码在GitHub上。
3个回答

5

TextField使用一个私有的内部InputListener,在构造函数中初始化,很难被覆盖。改变焦点的相关代码是在此监听器的keyTyped方法中执行的:

public boolean keyTyped (InputEvent event, char character) {
     [...]
     if ((character == TAB || character == ENTER_ANDROID) && focusTraversal)
         next(Gdx.input.isKeyPressed(Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Keys.SHIFT_RIGHT));
     [...]
}

一种简单的解决方案是完全禁用焦点遍历,并设置一个自动执行遍历的com.badlogic.gdx.scenes.scene2d.ui.TextFieldListener:
TextField textField
textField.setFocusTraversal(false);
textField.setTextFieldListener(new TextFieldListener() {
    @Override
    public void keyTyped(TextField textField, char key) {
        if ((key == '\r' || key == '\n')){
            textField.next(Gdx.input.isKeyPressed(Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Keys.SHIFT_RIGHT));
        }
    }
});

如果您需要使用TextField的setFocusTraversal方法来启用和禁用焦点遍历,那么当TextField添加内部InputListener时,通过在您自己的监听器中包装该内部InputListener也可以实现这一功能(但我不建议这样做)。
class MyTextField extends TextField{

class InputWrapper extends InputListener{
    private final InputListener l;

    public InputWrapper(InputListener l) {
        super();
        this.l = l;
    }

    @Override
    public boolean handle(Event e) {
        return l.handle(e);
    }

    @Override
    public boolean touchDown(InputEvent event, float x, float y,
            int pointer, int button) {
        return l.touchDown(event, x, y, pointer, button);
    }

    @Override
    public void touchUp(InputEvent event, float x, float y,
            int pointer, int button) {
        l.touchUp(event, x, y, pointer, button);
    }

    @Override
    public void touchDragged(InputEvent event, float x, float y,
            int pointer) {
        l.touchDragged(event, x, y, pointer);
    }

    @Override
    public boolean mouseMoved(InputEvent event, float x, float y) {
        return l.mouseMoved(event, x, y);
    }

    @Override
    public void enter(InputEvent event, float x, float y, int pointer,
            Actor fromActor) {
        l.enter(event, x, y, pointer, fromActor);
    }

    @Override
    public void exit(InputEvent event, float x, float y, int pointer,
            Actor toActor) {
        l.exit(event, x, y, pointer, toActor);
    }

    @Override
    public boolean scrolled(InputEvent event, float x, float y,
            int amount) {
        return l.scrolled(event, x, y, amount);
    }

    @Override
    public boolean keyDown(InputEvent event, int keycode) {
        return l.keyDown(event, keycode);
    }

    @Override
    public boolean keyUp(InputEvent event, int keycode) {
        return l.keyUp(event, keycode);
    }
    @Override
    public boolean keyTyped(InputEvent event, char character) {
        if (isDisabled()) {
            return false;
        } else if ((character == '\r' || character == '\n')){
            next(Gdx.input.isKeyPressed(Keys.SHIFT_LEFT) || Gdx.input.isKeyPressed(Keys.SHIFT_RIGHT));
            return true;
        }
        return l.keyTyped(event, character);
    }

}

public MyTextField(String text, Skin skin, String styleName) {
    super(text, skin, styleName);
}

public MyTextField(String text, Skin skin) {
    super(text, skin);
}

public MyTextField(String text, TextFieldStyle style) {
    super(text, style);
}

boolean initialized = false;
@Override
public boolean addListener (EventListener l) {
    if (!initialized) {
        if (!(l instanceof InputListener)) {
            throw new IllegalStateException();
        }
        initialized = true;
        return super.addListener(new InputWrapper((InputListener) l));
    }
    return super.addListener(l);
}
}

编辑: 再想一想,你也可以通过简单地覆盖TextField的setFocusTraversal并在调用此方法期间启用/禁用自己的侦听器来使用第一解决方案完成此操作。


我认为禁用焦点遍历会完全满足我的需求。谢谢。 - Don Kirkby
它起作用了,我已经更新了我的示例代码,并将赏金给你了。 - Don Kirkby

0

我找到了一个解决方法,但我仍然希望有一个更干净的解决方案,可以使两个平台表现一致。

我添加了一个标志来指示焦点是否会默认移动,如果它不会自己移动,我才会改变焦点。然后,我从 Android 的 MainActivity 类或桌面的 Main 类设置该标志。我已经在 GitHub 上发布了完整的示例代码 链接

private void nextField() {
    TextField nextField = 
            stage.getKeyboardFocus() == text1
            ? text2
            : stage.getKeyboardFocus() == text2
            ? text3
            : text1;
    nextField.setText("");
    if ( ! isFocusMovedAutomatically) {
        stage.setKeyboardFocus(nextField);
    }
}

0
在中,我能够做到以下操作:
final TextField newMessageTextField = new TextField("", uiSkin){
    @Override
    protected InputListener createInputListener () {
        return new TextFieldClickListener(){
            @Override
            public boolean keyUp(com.badlogic.gdx.scenes.scene2d.InputEvent event, int keycode) {
                System.out.println("event="+event+" key="+keycode);
                return super.keyUp(event, keycode);
            };
        };
    }
};

在 TextField 上聚焦后按箭头,我得到了以下结果。
event=keyUp key=19
event=keyUp key=20
event=keyUp key=22
event=keyUp key=21

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接