Chciałbym zmienić układ w zależności od tego, czy wirtualna klawiatura jest wyświetlana, czy nie. Przeszukałem API i różne blogi, ale nie mogę znaleźć niczego przydatnego.
Czy to możliwe?
Dzięki!
Chciałbym zmienić układ w zależności od tego, czy wirtualna klawiatura jest wyświetlana, czy nie. Przeszukałem API i różne blogi, ale nie mogę znaleźć niczego przydatnego.
Czy to możliwe?
Dzięki!
Odpowiedzi:
To rozwiązanie nie będzie działać w przypadku klawiatur miękkich i
onConfigurationChanged
nie będzie wywoływane w przypadku klawiatur miękkich (wirtualnych).
Musisz sam poradzić sobie ze zmianami konfiguracji.
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
Próba:
// from the link above
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a hardware keyboard is available
if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
} else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
}
}
Następnie wystarczy zmienić widoczność niektórych widoków, zaktualizować pole i zmienić plik układu.
newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
~ Chris
To może nie być najskuteczniejsze rozwiązanie. Ale działało to dla mnie za każdym razem ... Wywołuję tę funkcję tam, gdzie muszę słuchać SoftKeyboard.
boolean isOpened = false;
public void setListenerToRootView() {
final View activityRootView = getWindow().getDecorView().findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100) { // 99% of the time the height diff will be due to a keyboard.
Toast.makeText(getApplicationContext(), "Gotcha!!! softKeyboardup", 0).show();
if (isOpened == false) {
//Do two things, make the view top visible and the editText smaller
}
isOpened = true;
} else if (isOpened == true) {
Toast.makeText(getApplicationContext(), "softkeyborad Down!!!", 0).show();
isOpened = false;
}
}
});
}
Uwaga: Takie podejście spowoduje problemy, jeśli użytkownik użyje pływającej klawiatury.
android:windowSoftInputMode="adjustPan"
lub adjustResize
z nim, ponieważ układ nigdy nie zmienia rozmiaru.
Jeśli chcesz obsługiwać wyświetlanie / ukrywanie okna klawiatury IMM (wirtualnej) z działania, musisz podklasować swój układ i zastąpić metodę onMesure (abyś mógł określić zmierzoną szerokość i zmierzoną wysokość swojego układu). Następnie ustaw układ podklas jako główny widok działania za pomocą setContentView (). Teraz będziesz mógł obsługiwać pokazy / ukrywanie okien IMM. Jeśli to brzmi skomplikowanie, to nie jest tak naprawdę. Oto kod:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<EditText
android:id="@+id/SearchText"
android:text=""
android:inputType="text"
android:layout_width="fill_parent"
android:layout_height="34dip"
android:singleLine="True"
/>
<Button
android:id="@+id/Search"
android:layout_width="60dip"
android:layout_height="34dip"
android:gravity = "center"
/>
</LinearLayout>
Teraz w swojej działalności zadeklaruj podklasę dla swojego układu (main.xml)
public class MainSearchLayout extends LinearLayout {
public MainSearchLayout(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.main, this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d("Search Layout", "Handling Keyboard Window shown");
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
final int actualHeight = getHeight();
if (actualHeight > proposedheight){
// Keyboard is shown
} else {
// Keyboard is hidden
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Z kodu wynika, że nadmuchujemy układ dla naszej aktywności w konstruktorze podklasy
inflater.inflate(R.layout.main, this);
A teraz po prostu ustaw widok zawartości układu podklas dla naszej działalności.
public class MainActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainSearchLayout searchLayout = new MainSearchLayout(this, null);
setContentView(searchLayout);
}
// rest of the Activity code and subclassed layout...
}
android:windowSoftInputMode="adjustPan"
lub adjustResize
z nim, ponieważ układ nigdy nie zmienia rozmiaru.
Zrobiłem w ten sposób:
Dodaj OnKeyboardVisibilityListener
interfejs.
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
HomeActivity.java :
public class HomeActivity extends Activity implements OnKeyboardVisibilityListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
// Other stuff...
setKeyboardVisibilityListener(this);
}
private void setKeyboardVisibilityListener(final OnKeyboardVisibilityListener onKeyboardVisibilityListener) {
final View parentView = ((ViewGroup) findViewById(android.R.id.content)).getChildAt(0);
parentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private boolean alreadyOpen;
private final int defaultKeyboardHeightDP = 100;
private final int EstimatedKeyboardDP = defaultKeyboardHeightDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);
private final Rect rect = new Rect();
@Override
public void onGlobalLayout() {
int estimatedKeyboardHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, parentView.getResources().getDisplayMetrics());
parentView.getWindowVisibleDisplayFrame(rect);
int heightDiff = parentView.getRootView().getHeight() - (rect.bottom - rect.top);
boolean isShown = heightDiff >= estimatedKeyboardHeight;
if (isShown == alreadyOpen) {
Log.i("Keyboard state", "Ignoring global layout change...");
return;
}
alreadyOpen = isShown;
onKeyboardVisibilityListener.onVisibilityChanged(isShown);
}
});
}
@Override
public void onVisibilityChanged(boolean visible) {
Toast.makeText(HomeActivity.this, visible ? "Keyboard is active" : "Keyboard is Inactive", Toast.LENGTH_SHORT).show();
}
}
Mam nadzieję, że to ci pomoże.
W oparciu o kod z Nebojsa Tomcic opracowałem następującą podklasę RelativeLayout:
import java.util.ArrayList;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
public class KeyboardDetectorRelativeLayout extends RelativeLayout {
public interface IKeyboardChanged {
void onKeyboardShown();
void onKeyboardHidden();
}
private ArrayList<IKeyboardChanged> keyboardListener = new ArrayList<IKeyboardChanged>();
public KeyboardDetectorRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public KeyboardDetectorRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public KeyboardDetectorRelativeLayout(Context context) {
super(context);
}
public void addKeyboardStateChangedListener(IKeyboardChanged listener) {
keyboardListener.add(listener);
}
public void removeKeyboardStateChangedListener(IKeyboardChanged listener) {
keyboardListener.remove(listener);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
final int actualHeight = getHeight();
if (actualHeight > proposedheight) {
notifyKeyboardShown();
} else if (actualHeight < proposedheight) {
notifyKeyboardHidden();
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void notifyKeyboardHidden() {
for (IKeyboardChanged listener : keyboardListener) {
listener.onKeyboardHidden();
}
}
private void notifyKeyboardShown() {
for (IKeyboardChanged listener : keyboardListener) {
listener.onKeyboardShown();
}
}
}
Działa to całkiem dobrze ... Zaznacz, że to rozwiązanie będzie działać, gdy Tryb Miękkiego Wprowadzania Twojej Aktywności jest ustawiony na „WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE”
android:windowSoftInputMode="adjustPan"
lub adjustResize
z nim, ponieważ układ nigdy nie zmienia rozmiaru.
Podobnie jak odpowiedź @ amalBit, zarejestruj nasłuchiwanie w układzie globalnym i oblicz różnicę widocznego dna dectorView i proponowanego dna, jeśli różnica jest większa niż pewna wartość (domyślna wysokość IME), uważamy, że IME jest wyższy:
final EditText edit = (EditText) findViewById(R.id.edittext);
edit.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (keyboardShown(edit.getRootView())) {
Log.d("keyboard", "keyboard UP");
} else {
Log.d("keyboard", "keyboard Down");
}
}
});
private boolean keyboardShown(View rootView) {
final int softKeyboardHeight = 100;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
int heightDiff = rootView.getBottom() - r.bottom;
return heightDiff > softKeyboardHeight * dm.density;
}
próg wysokości 100 to odgadnięta minimalna wysokość edytora IME.
Działa to zarówno dla adjustPan, jak i adjustResize.
Rozwiązanie Nebojsa prawie dla mnie zadziałało. Kiedy kliknąłem wewnątrz wielowierszowego tekstu EditText, wiedziałem, że klawiatura jest wyświetlana, ale kiedy zacząłem pisać wewnątrz EditText, faktyczna wysokość i proponowana wysokość były nadal takie same, więc nie wiedziałam, że klawiatura jest nadal wyświetlana. Wprowadziłem niewielką modyfikację, aby zapisać maksymalną wysokość i działa dobrze. Oto poprawiona podklasa:
public class CheckinLayout extends RelativeLayout {
private int largestHeight;
public CheckinLayout(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.checkin, this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
largestHeight = Math.max(largestHeight, getHeight());
if (largestHeight > proposedheight)
// Keyboard is shown
else
// Keyboard is hidden
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Nie jestem pewien, czy ktoś to opublikuje. Znaleziono rozwiązanie to proste w użyciu! . SoftKeyboard klasa jest na gist.github.com . Ale podczas gdy wywołanie zwrotne / ukrywanie klawiatury na klawiaturze wymaga obsługi, aby poprawnie wykonywać czynności w interfejsie użytkownika:
/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use your root layout
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);
/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{
@Override
public void onSoftKeyboardHide()
{
// Code here
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
...
}
});
}
@Override
public void onSoftKeyboardShow()
{
// Code here
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
...
}
});
}
});
Rozwiązuję ten problem, nadpisując onKeyPreIme (int keyCode, KeyEvent event) w moim niestandardowym EditText.
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
//keyboard will be hidden
}
}
Mam do tego jakiś hack. Chociaż nie wydaje się być sposób, aby wykryć, kiedy klawiatura wykazało lub ukryty, to może faktycznie wykryć, kiedy jest o być pokazane lub ukryte poprzez ustawienie OnFocusChangeListener
na EditText
tym, że słuchasz.
EditText et = (EditText) findViewById(R.id.et);
et.setOnFocusChangeListener(new View.OnFocusChangeListener()
{
@Override
public void onFocusChange(View view, boolean hasFocus)
{
//hasFocus tells us whether soft keyboard is about to show
}
});
UWAGA: Jedną z rzeczy, o których należy pamiętać podczas tego włamania, jest to, że oddzwanianie jest uruchamiane natychmiast po EditText
uzyskaniu lub utracie ostrości. To faktycznie uruchomi się tuż przed wyświetleniem lub ukrywaniem się miękkiej klawiatury. Najlepszym sposobem, w jaki znalazłem coś po pokazaniu lub ukryciu klawiatury, jest użycie a Handler
i opóźnienie czegoś ~ 400 ms, na przykład:
EditText et = (EditText) findViewById(R.id.et);
et.setOnFocusChangeListener(new View.OnFocusChangeListener()
{
@Override
public void onFocusChange(View view, boolean hasFocus)
{
new Handler().postDelayed(new Runnable()
{
@Override
public void run()
{
//do work here
}
}, 400);
}
});
OnFocusChangeListener
mówi tylko, czy EditText
ma fokus po zmianie stanu. Ale IME
może być ukryty, gdy EditText
jest skupiony, jak wykryć tę sprawę?
Sander, myślę, że próbujesz pokazać widok zablokowany przez miękką klawiaturę. Spróbuj tego http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html .
Rozwiązałem problem z kodowaniem wstecznym jednowierszowego tekstu.
package com.helpingdoc;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
public class MainSearchLayout extends LinearLayout {
int hieght = 0;
public MainSearchLayout(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.main, this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d("Search Layout", "Handling Keyboard Window shown");
if(getHeight()>hieght){
hieght = getHeight();
}
final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
final int actualHeight = getHeight();
System.out.println("....hieght = "+ hieght);
System.out.println("....actualhieght = "+ actualHeight);
System.out.println("....proposedheight = "+ proposedheight);
if (actualHeight > proposedheight){
// Keyboard is shown
} else if(actualHeight<proposedheight){
// Keyboard is hidden
}
if(proposedheight == hieght){
// Keyboard is hidden
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Możesz także sprawdzić, czy pierwsze wyściółki dla dzieci DecorView są dolne. Zostanie ustawiona na wartość niezerową, gdy zostanie wyświetlona klawiatura.
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
View view = getRootView();
if (view != null && (view = ((ViewGroup) view).getChildAt(0)) != null) {
setKeyboardVisible(view.getPaddingBottom() > 0);
}
super.onLayout(changed, left, top, right, bottom);
}
Ukryj | Pokaż zdarzenia na klawiaturze można odsłuchiwać poprzez prosty hack w OnGlobalLayoutListener:
final View activityRootView = findViewById(R.id.top_root);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > 100) {
// keyboard is up
} else {
// keyboard is down
}
}
});
Tutaj ActivityRootView to widok główny Twojej aktywności.
za pomocą viewTreeObserver, aby łatwo uzyskać zdarzenie z klawiatury.
layout_parent.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
layout_parent.getWindowVisibleDisplayFrame(r)
if (layout_parent.rootView.height - (r.bottom - r.top) > 100) { // if more than 100 pixels, its probably a keyboard...
Log.e("TAG:", "keyboard open")
} else {
Log.e("TAG:", "keyboard close")
}
}
** layout_parent to twój widokedit_text.parent
Odpowiedź Nebojsa Tomcic nie była dla mnie pomocna. Mam RelativeLayout
z nim TextView
i AutoCompleteTextView
wewnątrz. Muszę przewinąć w TextView
dół, gdy klawiatura jest wyświetlana i gdy jest ukryta. Aby to osiągnąć, przesłoniłem onLayout
metodę i działa ona dla mnie dobrze.
public class ExtendedLayout extends RelativeLayout
{
public ExtendedLayout(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.main, this);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
super.onLayout(changed, l, t, r, b);
if (changed)
{
int scrollEnd = (textView.getLineCount() - textView.getHeight() /
textView.getLineHeight()) * textView.getLineHeight();
textView.scrollTo(0, scrollEnd);
}
}
}