Я хотів би змінити макет залежно від того, відображається віртуальна клавіатура чи ні. Я шукав API та різні блоги, але не можу знайти нічого корисного.
Це можливо?
Дякую!
Я хотів би змінити макет залежно від того, відображається віртуальна клавіатура чи ні. Я шукав API та різні блоги, але не можу знайти нічого корисного.
Це можливо?
Дякую!
Відповіді:
Це рішення не працюватиме для м'яких клавіатур і
onConfigurationChanged
не буде вимагатися для м'яких (віртуальних) клавіатур.
Ви повинні самостійно впоратися із змінами конфігурації.
http://developer.android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange
Зразок:
// 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();
}
}
Потім просто змініть видимість деяких представлень, оновіть поле та змініть файл макета.
newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
~ Chris
Це може бути не найефективнішим рішенням. Але це працювало для мене кожен раз ... Я називаю цю функцію там, де мені потрібно слухати 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;
}
}
});
}
Примітка. Цей підхід спричинить проблеми, якщо користувач використовує плаваючу клавіатуру.
android:windowSoftInputMode="adjustPan"
або adjustResize
на повноекранному екрані, оскільки макет ніколи не змінюється.
Якщо ви хочете обробляти показ / приховування вікна IMM (віртуальної) клавіатури зі своєї діяльності, вам потрібно буде підкласифікувати ваш макет та замінити метод onMesure (щоб ви могли визначити вимірювану ширину та виміряну висоту вашого макета). Після цього встановіть підкласичний макет як основний вигляд вашої діяльності by setContentView (). Тепер ви зможете обробляти покази / приховування вікон IMM. Якщо це звучить складно, це не так насправді. Ось код:
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>
Тепер усередині вашої активності оголосіть підклас для вашого макета (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);
}
}
З коду ви бачите, що ми завищуємо макет нашої діяльності в конструкторі підкласу
inflater.inflate(R.layout.main, this);
А тепер просто встановіть перегляд вмісту підкласового макета для нашої діяльності.
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"
або adjustResize
на повноекранному екрані, оскільки макет ніколи не змінюється.
Я зробив так:
Додати OnKeyboardVisibilityListener
інтерфейс.
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();
}
}
Сподіваюся, це допоможе вам.
На основі кодексу Небойши Томчича я розробив наступний підклас відносного макета:
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();
}
}
}
Це працює чудово ... Позначте, що це рішення працюватиме лише тоді, коли для режиму м'якого введення вашої активності встановлено значення "WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE"
android:windowSoftInputMode="adjustPan"
або adjustResize
на повноекранному екрані, оскільки макет ніколи не змінюється.
Як і у відповідь @ amalBit, зареєструйте слухача глобального макета та обчисліть різницю видимого дна dectorView та запропонованого дна, якщо різниця більша за якесь значення (здогадалися висоту IME), ми вважаємо, що IME збільшився:
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;
}
Поріг висоти 100 - здогадана мінімальна висота IME.
Це працює як для prilagodPan, так і для prilagodResize.
Рішення Небойси майже для мене спрацювало. Коли я натиснув всередині рядкового EditText, він знав, що відображається клавіатура, але коли я почав вводити всередину EditText, фактична висота та запропонована висота все ще були однаковими, тому він не знав, що клавіатура все ще відображається. Я зробив невелику модифікацію, щоб зберігати максимальну висоту, і вона працює чудово. Ось переглянений підклас:
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);
}
}
Не впевнений, чи хтось допише це. Знайшов це рішення простим у використанні! . Клас SoftKeyboard знаходиться на gist.github.com . Але в той час, коли спливаюче або приховане виклик клавіатури подій, нам потрібен обробник, щоб правильно виконувати дії в інтерфейсі:
/*
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
...
}
});
}
});
Я вирішую це шляхом переосмислення onKeyPreIme (int keyCode, подія KeyEvent) у моєму користувальницькому редакторі EditText.
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
//keyboard will be hidden
}
}
У мене є такий собі злом, щоб це зробити. Хоча, здається, не існує способу виявити, коли м'яка клавіатура показала або приховала, ви насправді можете визначити, коли вона збираєтьсяOnFocusChangeListener
відобразити або приховати, встановивши на те, EditText
що ви слухаєте.
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
}
});
ПРИМІТКА. Одне з цих хак необхідно пам’ятати про те, що цей зворотний виклик запускається негайно, коли ви EditText
отримуєте або втрачаєте фокус. Це насправді буде спрацьовувати безпосередньо перед тим, як м'яка клавіатура відображається або ховається. Найкращий спосіб, коли я виявив щось робити після того, як клавіатура показує або приховує, - це використовувати Handler
та затримати щось ~ 400 мс, як-от так:
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
говорить лише, чи EditText
має фокус після зміни стану. Але, IME
можливо, приховано, коли EditText
є фокус, як виявити цей випадок?
Сандер, я вважаю, ви намагаєтесь показати вид, заблокований м'якою клавіатурою. Спробуйте це http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html .
Я вирішив проблему з однорядковим кодуванням зворотного перегляду тексту.
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);
}
}
Ви також можете перевірити наявність першої нижньої підкладки DecorView для дітей. Коли буде показано клавіатуру, вона буде встановлена на нульове значення.
@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);
}
Приховати | Показати події для клавіатури можна просто за допомогою простого хаку в 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
}
}
});
Тут ActivityRootView - це кореневий вигляд вашої діяльності.
за допомогою viewTreeObserver легко отримати подію клавіатури.
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 - це ваш поглядedit_text.parent
Відповідь Небойші Томчича мені не була корисною. Я маю RelativeLayout
з TextView
і AutoCompleteTextView
всередині нього. Мені потрібно прокрутити TextView
донизу, коли клавіатура відображається і коли вона прихована. Для цього я відміняю onLayout
метод, і він прекрасно працює для мене.
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);
}
}
}