Falls es jemanden interessiert, ich habe (eine) mögliche Lösung entwickelt, die endlich einmal FUNKTIONIERT!
AndroidKeyBoard.java:
Code:
package vl.base;
import android.text.Editable;
import android.text.InputType;
import android.text.method.KeyListener;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
public class AndroidKeyBoard implements KeyListener {
protected boolean enabled;
protected EditText box;
private InputMethodManager mngr;
private KeyBoardListener listener;
//could be inlined, but yeah..its tschawa!
public AndroidKeyBoard(InputMethodManager mngr, EditText box, KeyBoardListener keyboali)
{
this.box = box;
this.listener = keyboali;
box.setKeyListener(this);
this.mngr = mngr;
}
//has to be called, before the program exits, otherwhise the keyboard
//won't close!
public void close()
{
hide();
}
protected void hide()
{
mngr.hideSoftInputFromWindow(box.getWindowToken(), 0);
}
protected void show()
{
box.requestFocus(); //necessary?? yeah, lets take the secure way...
mngr.showSoftInput(box, InputMethodManager.SHOW_FORCED);
}
public void show(boolean shx)
{
if (enabled != shx)
{
if (shx)
show();
else
hide();
enabled = shx;
}
}
public void clearMetaKeyState(View view, Editable content, int states) {
}
public int getInputType() {
//more or less similar look and feel as the good old iphone keyboard
return InputType.TYPE_NULL;
}
//just eat everything, yeah this thing is very greedy!
public boolean onKeyDown(View view, Editable text, int keyCode, KeyEvent event) {
if (enabled)
listener.keyboardChange(event.getUnicodeChar(), keyCode);
return true;
}
public boolean onKeyOther(View view, Editable text, KeyEvent event) {
return true;
}
public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event) {
return true;
}
public void onHardWareKeyBoardShown(boolean b) {
if (enabled)
if (b)
hide();
else
show();
}
}
AndroidKeyBoardActivity.java:
Code:
package vl.base;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
public abstract class AndroidKeyBoardActivity extends Activity implements KeyBoardListener {
//x is a kewl letter...so use it :P
protected AndroidKeyBoard kbx;
@Override
protected void onDestroy()
{
super.onDestroy();
kbx.close();
}
public abstract int getMainViewID();
public abstract View getMainView();
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
EditText editText;
LinearLayout l = new LinearLayout(getApplicationContext());
l.addView(getMainView() != null ? getMainView() : ((LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).
inflate(getMainViewID(), null), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
l.addView(editText = new EditText(this.getApplicationContext()),
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
);
setContentView(l);
kbx = new AndroidKeyBoard((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE),
editText, this);
}
//important preconditions:
/*
* activity tag of the xml manifest must include something like this
* android:configChanges="keyboardHidden"
*/
@Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO)
kbx.onHardWareKeyBoardShown(true);
else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES)
kbx.onHardWareKeyBoardShown(false);
}
}
KeyBoardListener.java:
Code:
package vl.base;
public interface KeyBoardListener {
public void keyboardChange(int sign, int code);
}
Man braucht lediglich anstelle von der Activity von AndroidKeyBoardActivity erben (extends AndroidKeyBoardActivity).
Wichtig sind dabei, dass folgende Methoden implementiert werden (sind sowieso abstract:
Code:
/*return xml-document id. 0, if view with the given instance should be taken*/
public int getMainViewID() {
return 0;
}
/*return instance to the content view, null otherwhise if xml-document should be parsed*/
@Override
public View getMainView() { return null; }
/*key with unicode sign "sign" and keycode "code" was pressed*/
public void keyboardChange(final int sign, final int code) { }
Sofern getMainView null zurück liefert, wird die XML-Datei mit der ID getMainViewID geladen und diese View als Contentview gesetzt.
D.h. in der Activity, die von der AndroidKeyBoardActivity erbt, soll KEINE Contentview gesetzt werden. Dies wird bereits in der AndroidKeyBoardView getan. Grund dafür ist, dass Edittext nicht invisible gesetzt werden darf, weil sonst das Keyboardöffnen nicht funktioniert. Auch hier gibt es wieder einen kleinen Trick...die zurückgelieferte View bei getMainView bzw. getMainViewID wird einfach in einen "LinearLayout"-Container gebaut. Als Optionen werden intern FILL_PARENT angegeben. Der EditText wird auch angehängt, jedoch von der vorigen View VERDECKT.
Diese Lösung funktioniert eigentlich auch mit HW-Keyboards, d.h. es sollte erkannt werden, wann ein keyboard offen oder geschlossen wird.
Das Keyboard generell wird mit
eingeblendet und
ausgeblendet.
Damit das Erkennen, des Öffnens der Tastatur funktioniert, muss im activity-Tag des Manifests folgendes Vorkommen (oder durch logisches Oder verknüpft werden!)
Code:
android:configChanges="keyboardHidden"
.
Hoffe, ich habe nichts vergessen.
Diese Methode eignet sich prima, um ganz einfach (Haha!) NUR ein Keyboard anzuzeigen und zwar nur dann, wenn die HW-Tastatur nicht gerade offen ist.
Zusätzlich wird, wie bereits erwähnt, dynamisch auf das Ereignis des Öffnens der Tastatur reagiert. Zu beachten ist, dass die Callback-Funktion "keyboardChange" natürlich nur aufgerufen wird, wenn "kbx.show(true);" aufgerufen wurde...andernfalls kann man auch auf der HW-Tastatur so viel drücken, wie man will.
Sollte das Öffnen des keyboards von einem anderen Thread gewünscht sein, müsste man in der Activity (die von AndroidKeyBoardActivity erbt) einen Handler definieren:
Code:
private Handler h = new Handler() {
@Override
public void handleMessage(Message msg)
{
kbx.show(msg.what == 1);
}
};
Mit dem Aufruf
von einem anderen Thread, wird trotzdem sichergestellt, dass keine Exception geworfen wird, die normalerweise auftritt, wenn Views von Threads manipuliert werden, die diese nicht erzeugt haben.
Sollte alles sein, viel Spaß
