お久しぶりです。y_a_s_です。
今日は珍しく開発メモを。
プラットフォームはAndroid。 
突然ですが、ソフトウェアキーボードってあるじゃないですか。

スマートフォンとかで、文字を打つときに下からニュっと出てくるアレ。
Androidアプリを作ってた時に思ったのですが、こいつ意外と気まぐれですよね。
出てきて欲しい時に出てこないのに、別に今必要じゃないという時に出てきてしまう。

そんな気まぐれさに嫌気がさしてしまいました。
どうにかこれを、バックボタンを押したり、テキストエディットなどをタップしたりせず、自由に扱えないかと調べてみました。


調査時の画面は以下の通りです。
res/layout/main.xml
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.    xmlns:tools="http://schemas.android.com/tools"
  3.    android:layout_width="match_parent"
  4.    android:layout_height="match_parent"
  5.    android:orientation="vertical" >
  6.  
  7.     <Button
  8.        android:id="@+id/button"
  9.        android:layout_width="wrap_content"
  10.        android:layout_height="wrap_content"
  11.        android:text="Button" />
  12.  
  13.     <EditText
  14.        android:id="@+id/edit"
  15.        android:layout_width="match_parent"
  16.        android:layout_height="wrap_content"/>
  17. </LinearLayout>


まずは表示状態のソフトウェアキーボードを、ボタンを押して非表示にする方法。
非表示にするには、 InputMethodManager を利用します。
  1. InputMethodManager inputMethodMgr = (InputMethodManager)
  2.     getSystemService(Context.INPUT_METHOD_SERVICE);
  3. inputMethodMgr.hideSoftInputFromWindow(view.getWindowToken(),0);

これだけです。まあ簡単。
コードはこちら。
  1. public class SoftweraKeyboardTestActivity extends Activity
  2. {
  3.     @Override
  4.     public void onCreate(Bundle savedInstanceState)
  5.     {
  6.         super.onCreate(savedInstanceState);
  7.         setContentView(R.layout.main);
  8.  
  9.         // ボタンを押したとき
  10.         findViewById(R.id.button).setOnClickListener(new View.OnClickListener()
  11.         {
  12.             @Override
  13.             public void onClick(View v)
  14.             {
  15.                 // ソフトウェアキーボードを非表示
  16.                 InputMethodManager inputMethodMgr = (InputMethodManager)
  17.                     getSystemService(Context.INPUT_METHOD_SERVICE);
  18.                 inputMethodMgr.hideSoftInputFromWindow(v.getWindowToken(),0);
  19.             }
  20.         });
  21.     }
  22. }

ソフトウェアキーボードを表示させるには、画面上のテキストエディットをタップしてました。
コンセプト全否定ですが、ここでは非表示にすることが目的なので御容赦を。

実際の利用には、テキストエディットのフォーカスをクリアして、フォーカスが変更された時に呼び出される onFocusChange()  内で設定した方いいと思います。


次に、Activity起動時に表示されてしまうソフトウェアキーボードを表示させない方法。
これも簡単で、setContentView の前に、下の一文を追加するだけです。 
  1. getWindow().setSoftInputMode(
  2.         WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);


問題は、非表示状態のソフトウェアキーボードをボタンを押した時に表示させる方法。
表示させる場合にも InputMethodManager を利用します。 
  1. InputMethodManager inputMethodMgr = (InputMethodManager)
  2.     getSystemService(Context.INPUT_METHOD_SERVICE);
  3. inputMethodMgr.showSoftInput(view, InputMethodManager.SHOW_FORCED);

これだけ見ると非表示と大して変わらないようにも見えますが、これが罠でした。

結論から言うと、これだけではソフトウェアキーボードは表示できません。
表示させるためには、 showSoftInput の第1引数に渡す、編集可能な View にフォーカスが乗っていなければならないとのこと。
  1. view.setFocusable(true);    // フォーカス可能に設定
  2. view.requestFocus() ;    // フォーカスを当てる

しかもこのフォーカス、動的に乗せようとしても、すぐには乗ってると認識してくれないようです。 



駄目だ、やはり自由に扱おうだなんて無理だったのか……。



そう諦めかけたとき、天啓が。
 
あれ、Activity起動時に表示されるんだったら……?








 
  1. view.setVisibility(View.INVISIBLE);    // ビューを非表示に設定
  2. view.setVisibility(View.VISIBLE);    // ビューを表示に設定
  3. view.setFocusable(true);    // フォーカス可能に設定
  4. view.requestFocus() ;    // フォーカスを当てる

これでフォーカスが認識されました。
正直できると思いませんでした。

以下、ソフトウェアキーボードを表示させるコードです。
  1. public class SoftweraKeyboardTestActivity extends Activity
  2. {
  3.     EditText edit;
  4.  
  5.     @Override
  6.     public void onCreate(Bundle savedInstanceState)
  7.     {
  8.         super.onCreate(savedInstanceState);
  9.         setContentView(R.layout.main);
  10.  
  11.         edit = (EditText)findViewById(R.id.edit);
  12.  
  13.         findViewById(R.id.button).setOnClickListener(new View.OnClickListener()
  14.         {
  15.             @Override
  16.             public void onClick(View v)
  17.             {
  18.                 view.setVisibility(View.INVISIBLE);    // ビューを非表示に設定
  19.                 view.setVisibility(View.VISIBLE);    // ビューを表示に設定
  20.                 view.setFocusable(true);    // フォーカス可能に設定
  21.                 view.requestFocus() ;    // フォーカスを当てる
  22.             }
  23.         });
  24.  
  25.         edit.setOnFocusChangeListener(new View.OnFocusChangeListener()
  26.         {
  27.             public void onFocusChange(View v, boolean hasFocus)
  28.             {
  29.                 // ソフトウェアキーボードを表示する
  30.                 InputMethodManager inputMethodMgr = (InputMethodManager)
  31.                     getSystemService(Context.INPUT_METHOD_SERVICE);
  32.                 inputMethodMgr.showSoftInput(v, InputMethodManager.SHOW_FORCED);
  33.             }
  34.         });
  35.     }
  36. }



最後に、ボタンを押すたびにソフトウェアキーボードの表示と非表示を切り替えるサンプルを。
  1. public class SoftweraKeyboardTestActivity extends Activity
  2. {
  3.     EditText edit;
  4.     boolean isShownKeyboard ;
  5.  
  6.     @Override
  7.     public void onCreate(Bundle savedInstanceState)
  8.     {
  9.         super.onCreate(savedInstanceState);
  10.         getWindow().setSoftInputMode(
  11.                 WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
  12.         setContentView(R.layout.main);
  13.  
  14.         edit = (EditText)findViewById(R.id.edit);
  15.         isShownKeyboard = true;
  16.  
  17.         // ボタンを押したとき
  18.         findViewById(R.id.button).setOnClickListener(new View.OnClickListener()
  19.         {
  20.             @Override
  21.             public void onClick(View v)
  22.             {
  23.                 if(isShownKeyboard)
  24.                 {
  25.                     isShownKeyboard = false ;

  26.                     v.setVisibility(View.INVISIBLE);    // ビューを非表示に設定
  27.                     v.setVisibility(View.VISIBLE);    // ビューを表示に設定
  28.                     v.setFocusable(true);    // フォーカス可能に設定
  29.                     v.requestFocus() ;    // フォーカスを当てる
  30.                 }
  31.                 else
  32.                 {
  33.                     isShownKeyboard = true;
  34.                     edit.clearFocus();    // フォーカスをクリア
  35.                 }
  36.             }
  37.         });
  38.  
  39.         edit.setOnFocusChangeListener(new View.OnFocusChangeListener()
  40.         {
  41.             public void onFocusChange(View v, boolean hasFocus)
  42.             {
  43.                 InputMethodManager inputMethodMgr = (InputMethodManager)
  44.                     getSystemService(Context.INPUT_METHOD_SERVICE);
  45.  
  46.                 if(hasFocus) // フォーカスを受け取ったとき
  47.                 {
  48.                     // ソフトキーボードを表示する
  49.                     inputMethodMgr.showSoftInput(v, InputMethodManager.SHOW_FORCED);
  50.                 }
  51.                 else
  52.                 {
  53.                     // ソフトキーボードを閉じる
  54.                     inputMethodMgr.hideSoftInputFromWindow(v.getWindowToken(),0);
  55.                 }
  56.             }
  57.         });
  58.     }
  59. }































p.s.
ここまで書いて、ようやくクラス名の「ソフトウェア」の綴りが "Software" じゃなくて "Softwera" になってることに気がつきました。orz