0

我已经搜索了几天,终于编译了足够的答案来完成我想要的。首先,这似乎是一个经常被问到但没有真正回答的问题(至少不是我正在寻找的方式)。我想我会分享我的发现,但我还有一个小问题想寻求帮助。开始:

我有一个显示分数的 TextView。它从 0 开始,在 onClick 事件中分数增加并更新 TextView(分数被跟踪为一个字节 - valScore)。

onLongClick:这就是挑战。我希望用户能够执行 LongClick 来更正/更改分数。我首先找到了一个解决方案,它使用了另一个 layout.xml 文件,其中只有一个 EditText 元素以及 OK 和 CANCEL 按钮。更改乐谱非常麻烦,因为它涉及 LongClick,然后对话框打开,然后您必须单击 EditText 元素以打开键盘,然后输入值,单击 DONE,然后单击 OK。我通过弄清楚如何在对话框打开时自动打开软件键盘来缩短它。但是,您仍然必须单击完成,然后单击确定。我不喜欢这个动作,所以我继续搜索。

几天后,我想出了一些代码,然后又想出了更多代码,并且通过大量的游戏/黑客攻击,我想出了以下解决方案:

    // set the onLongClickListener for tvScoreHome
    tvScoreHome.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            tvScoreHome.setInputType( InputType.TYPE_CLASS_NUMBER );
            tvScoreHome.setFocusable(true);
            tvScoreHome.setFocusableInTouchMode( true );
            tvScoreHome.requestFocus();

            InputMethodManager imm = (InputMethodManager) context.getSystemService(Service.INPUT_METHOD_SERVICE);
            imm.showSoftInput(tvScoreHome, InputMethodManager.SHOW_FORCED);

            tvScoreHome.setText("");

            tvScoreHome.setOnEditorActionListener( new TextView.OnEditorActionListener() {

                @Override
                public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                    if (actionId == EditorInfo.IME_ACTION_DONE) {
                        valScoreHome = Byte.valueOf( tvScoreHome.getText().toString() );

                        // This part will hide the keyboard after input
                        InputMethodManager imm = (InputMethodManager) context.getSystemService(Service.INPUT_METHOD_SERVICE);
                        imm.hideSoftInputFromWindow(v.getWindowToken(), 0);

                        tvScoreHome.setFocusable( false );
                        tvScoreHome.setFocusableInTouchMode( false );
                        tvScoreHome.setText( Byte.toString(valScoreHome) );

                        return true;
                    }

                    return false;
                }

            });

            return true;
        }
    });

这完全符合我的要求。用户执行 LongClick 键盘打开,用户输入新值并单击 DONE。TextView 已更新,效果很好!

如果用户改变主意并点击设备上的“返回”按钮,就会出现问题。键盘关闭(好),但焦点仍保留在 TextView 上,而不是像按下 DONE 按钮时那样移除焦点。因此,如果您在每次单击后取消更改,导致键盘再次打开而不是仅仅增加分数 - 直到您实际在键盘中键入一个值并单击完成(然后常规行为再次接管。我需要如果按下 BACK 按钮,则 setFocusableInTouchMode 为 FALSE。

另一个问题是 setText() 方法会被执行,即使在输入了不同的值时按下了 BACK 按钮。即使 valScoreHome 没有更新,TextView 也会发生变化。在下一次增量时,它会再次变为正确的数字,但如果按下 BACK 按钮,则 setText() 不应执行。

有人可以帮我解决这个问题吗?

4

1 回答 1

2

这两个问题都可以通过子类化来处理TextView

关闭键盘的后退按钮按下由覆盖处理onKeyPreIme

为了避免在用户关闭键盘时更新文本,分数值保存在变量mScore中,但TextView前提是当前不可聚焦。这意味着,TextView“记住”不是由用户输入的分数的当前值。当用户关闭键盘时,文本被设置回保存的值。

public class ScoreTextView extends TextView {
    private CharSequence mScore;

    public ScoreTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        if (!isFocusable()) {
            mScore = text;
        }
        super.setText(text, type);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            setFocusable(false);
            setFocusableInTouchMode(false);
            setText(mScore);
        }
        return super.onKeyPreIme(keyCode, event);
    }
}
于 2012-12-28T19:21:06.690 回答