0

私は何日もSOを検索していて、最終的に私が望んでいたことを達成するのに十分な答えをまとめました。まず第一に、それはよくある質問のようですが、実際には答えられていません(少なくとも私が探していた方法ではありません)。調査結果を共有したいと思いましたが、助けを求めたい小さな問題が1つ残っています。ここに行きます:

スコアを表示するTextViewがあります。これは0から始まり、onClickイベントでスコアが増加し、TextViewを更新します(スコアはバイトとして追跡されます--valScore)。

onLongClick:これは課題でした。ユーザーがLongClickを実行して、スコアを修正/変更できるようにしたいと思います。私は最初に、EditText要素と[OK]ボタンと[CANCEL]ボタンだけを含む別のlayout.xmlファイルを利用するソリューションを見つけました。LongClickが含まれるため、スコアを変更するのは非常に面倒でした。ダイアログが開き、EditText要素をクリックしてキーボードを開き、値を入力して[DONE]をクリックし、[OK]をクリックする必要がありました。ダイアログが開いたときにソフトウェアキーボードを自動的に開く方法を理解することで、短縮しました。ただし、[完了]、[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を実行すると、キーボードが開き、ユーザーは新しい値を入力して[完了]をクリックします。TextViewが更新され、うまく機能します。

この問題は、ユーザーが気が変わってデバイスの[戻る]ボタンを押すと発生します。キーボードは閉じますが(GOOD)、DONEボタンが押された場合のようにフォーカスを削除するのではなく、TextViewにフォーカスが残ります。したがって、その後クリックするたびに変更をキャンセルすると、スコアをインクリメントするだけでなく、キーボードが再び開きます。実際にキーボードに値を入力して[完了]をクリックするまで(その後、通常の動作が再び引き継がれます。戻るボタンが押された場合、FocusableInTouchModeをFALSEに設定します。

もう1つの問題は、別の値が入力されている場合に[戻る]ボタンが押されてもsetText()メソッドが実行されることです。valScoreHomeが更新されていなくても、TextViewが変更されます。次の増分で再び正しい番号になりますが、戻るボタンが押された場合、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 に答える