ฉันต้องทำสิ่งที่ง่ายมาก - ตรวจสอบว่าแป้นพิมพ์ซอฟต์แวร์ปรากฏขึ้นหรือไม่ เป็นไปได้ใน Android?
ฉันต้องทำสิ่งที่ง่ายมาก - ตรวจสอบว่าแป้นพิมพ์ซอฟต์แวร์ปรากฏขึ้นหรือไม่ เป็นไปได้ใน Android?
คำตอบ:
ใหม่คำตอบ เพิ่ม 25 มกราคม 2012
นับตั้งแต่ที่เขียนคำตอบด้านล่างมีบางคนบอกให้ฉันทราบถึงการมีอยู่ของViewTreeObserverและเพื่อน ๆ API ที่ซ่อนอยู่ใน SDK ตั้งแต่รุ่น 1
แทนที่จะต้องใช้ประเภทเลย์เอาต์ที่กำหนดเองโซลูชันที่ง่ายกว่าคือการให้รูทของกิจกรรมของคุณดู ID ที่รู้จักพูด@+id/activityRoot
ตะขอ GlobalLayoutListener เข้าใน ViewTreeObserver และจากนั้นคำนวณขนาดที่แตกต่างระหว่างรูทมุมมองของกิจกรรมและขนาดหน้าต่าง:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard...
// ... do something here
}
}
});
การใช้ยูทิลิตี้เช่น:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
ง่าย!
หมายเหตุ:
แอปพลิเคชันของคุณต้องตั้งค่าสถานะนี้ใน Android Manifest ไม่android:windowSoftInputMode="adjustResize"
เช่นนั้นโซลูชันด้านบนจะไม่ทำงาน
คำตอบเดิม
ใช่มันเป็นไปได้ แต่มันยากกว่าที่ควรจะเป็น
ถ้าผมจำเป็นต้องดูแลเกี่ยวกับเมื่อปรากฏแป้นพิมพ์และหายไป (ซึ่งเป็นค่อนข้างบ่อย) onMeasure()
แล้วสิ่งที่ฉันทำคือการปรับแต่งรูปแบบของฉันระดับระดับบนสุดซึ่งเป็นหนึ่งในการแทนที่ ตรรกะพื้นฐานคือถ้าเค้าโครงพบว่าตัวเองเติมน้อยกว่าพื้นที่ทั้งหมดของหน้าต่างแสดงว่าคีย์บอร์ดนุ่มนวลอาจแสดง
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.LinearLayout;
/*
* LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when
* the soft keyboard is shown and hidden (something Android can't tell you, weirdly).
*/
public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {
public LinearLayoutThatDetectsSoftKeyboard(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface Listener {
public void onSoftKeyboardShown(boolean isShowing);
}
private Listener listener;
public void setListener(Listener listener) {
this.listener = listener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
Activity activity = (Activity)getContext();
Rect rect = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
int diff = (screenHeight - statusBarHeight) - height;
if (listener != null) {
listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
จากนั้นในชั้นเรียนกิจกรรมของคุณ ...
public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);
mainLayout.setListener(this);
...
}
@Override
public void onSoftKeyboardShown(boolean isShowing) {
// do whatever you need to do here
}
...
}
((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)
android.R.id.content
) คุณจะสามารถพูดได้อย่างมั่นใจมากขึ้นว่าSystem
แทนที่จะใช้แอปพลิเคชันของคุณคือการเปลี่ยนเอนทิตี้ของความสูง จะปลอดภัยกว่ามากสำหรับทีม Android ที่จะให้เวลาพักกับเราและแจ้งให้เราทราบอย่างน้อยสิ่งพื้นฐานเกี่ยวกับอินพุต SoftKeyboard
heightDiff
จะรวมความสูงของแถบการกระทำเสมอ ในคำตอบใหม่ที่ถูกละเว้นโดยการทดสอบว่าความสูงนั้นสูงกว่าค่าคงที่หรือไม่ แต่ 100 พิกเซลไม่เพียงพอสำหรับอุปกรณ์ xxhdpi เช่น Nexus 4 ลองพิจารณาการแปลงค่าเป็น DPs หากคุณต้องการใช้งานแฮ็คนี้ รอบ
หวังว่านี่จะช่วยใครซักคน
คำตอบใหม่ที่รูเบนสแครตตันให้ไว้นั้นยอดเยี่ยมและมีประสิทธิภาพจริงๆ แต่จะใช้ได้เฉพาะเมื่อคุณตั้งค่า windowSoftInputMode เพื่อปรับขนาด หากคุณตั้งค่าเป็น adjustPan คุณจะไม่สามารถตรวจพบว่ามีแป้นพิมพ์ปรากฏอยู่หรือไม่โดยใช้ข้อมูลโค้ดของเขา เพื่อหลีกเลี่ยงปัญหานี้ฉันได้ทำการปรับเปลี่ยนรหัสเล็กน้อยด้านบนนี้
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
... do something here
}
}
});
TwoDScrollerView
คล้ายกับstackoverflow.com/a/5224088/530513แม้ว่าจะมีการซูมด้วย เด็กที่ไม่ได้เป็นที่เรียบง่ายImageView
แต่รูปแบบที่กำหนดเอง (ขยายRelativeLayout
) android:windowSoftInputMode="adjustResize"
แต่ก็ไม่สามารถที่จะตรวจสอบแป้นพิมพ์โดยใช้วิธีการแก้ปัญหาที่แนะนำแม้จะมีการตั้งค่า ขอบคุณ!
ActionBar
ActionBarSherlock
ขอบคุณมาก! โดยวิธีการที่มีวิธีr.height()
:)
heightDiff > root.getRootView().getHeight() / 4
คุ้มค่าที่จะทำงานกับอุปกรณ์ความละเอียดสูง 100px สั้น ใน Nexus 5 ที่มี 1080x1920 res, 1920 - (996-75)>? 100 = 999 1920 - (1776-75)>? 100 = 219 // แป้นพิมพ์ขึ้นใน galaxy s2 ที่มีความละเอียด 480x800, 800 - (800-38)>? 100 = 38 800 - (410-38)>? 100 = 428 // แป้นพิมพ์ขึ้นไปจำนวนมายากล 100px ไม่ดีพอ
มันมีมานานแล้วในแง่ของคอมพิวเตอร์ แต่คำถามนี้ยังมีความเกี่ยวข้องอย่างไม่น่าเชื่อ!
ดังนั้นฉันจึงได้คำตอบข้างต้นและรวมเข้าด้วยกันและทำให้ดีขึ้นเล็กน้อย ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final int DefaultKeyboardDP = 100;
// From @nathanielwolf answer... Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
// Convert the dp to pixels.
int estimatedKeyboardHeight = (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());
// Conclude whether the keyboard is shown or not.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isShown = heightDiff >= estimatedKeyboardHeight;
if (isShown == wasOpened) {
Log.d("Keyboard state", "Ignoring global layout change...");
return;
}
wasOpened = isShown;
listener.onVisibilityChanged(isShown);
}
});
}
ได้ผลสำหรับฉัน :)
หมายเหตุ: หากคุณสังเกตเห็นว่าDefaultKeyboardDPไม่เหมาะกับอุปกรณ์ของคุณเล่นกับค่าและโพสต์ความคิดเห็นสำหรับทุกคนที่จะรู้ว่าสิ่งที่ควรค่า ... ในที่สุดเราจะได้รับค่าที่ถูกต้องเพื่อให้พอดีกับอุปกรณ์ทั้งหมด!
สำหรับรายละเอียดเพิ่มเติมดูการใช้งานในCyborg
ขออภัยสำหรับคำตอบที่ล่าช้า แต่ฉันได้สร้างคลาสผู้ช่วยเล็กน้อยเพื่อจัดการกับเหตุการณ์เปิด / ปิดด้วยการแจ้งให้ผู้ฟังและสิ่งที่มีประโยชน์อื่น ๆ อาจเป็นคนที่เห็นว่าเป็นประโยชน์:
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import java.util.LinkedList;
import java.util.List;
public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {
public interface SoftKeyboardStateListener {
void onSoftKeyboardOpened(int keyboardHeightInPx);
void onSoftKeyboardClosed();
}
private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
private final View activityRootView;
private int lastSoftKeyboardHeightInPx;
private boolean isSoftKeyboardOpened;
public SoftKeyboardStateWatcher(View activityRootView) {
this(activityRootView, false);
}
public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
this.activityRootView = activityRootView;
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
final Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
isSoftKeyboardOpened = true;
notifyOnSoftKeyboardOpened(heightDiff);
} else if (isSoftKeyboardOpened && heightDiff < 100) {
isSoftKeyboardOpened = false;
notifyOnSoftKeyboardClosed();
}
}
public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
}
public boolean isSoftKeyboardOpened() {
return isSoftKeyboardOpened;
}
/**
* Default value is zero {@code 0}.
*
* @return last saved keyboard height in px
*/
public int getLastSoftKeyboardHeightInPx() {
return lastSoftKeyboardHeightInPx;
}
public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.add(listener);
}
public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.remove(listener);
}
private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardOpened(keyboardHeightInPx);
}
}
}
private void notifyOnSoftKeyboardClosed() {
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardClosed();
}
}
}
}
ตัวอย่างการใช้งาน:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
getLastKeyboardHeightInPx()
ไม่รวมความสูงของแถวนั้น คุณรู้วิธีนำมาพิจารณาด้วยหรือไม่
การปรับปรุงบางอย่างเพื่อหลีกเลี่ยงการตรวจจับการมองเห็นของคีย์บอร์ดอ่อนบนอุปกรณ์ที่มีความหนาแน่นสูงอย่างไม่ถูกต้อง:
เกณฑ์ของความแตกต่างความสูงควรได้รับการกำหนดให้เป็น128 DPไม่128 พิกเซล
อ้างถึงเอกสารการออกแบบของ Google เกี่ยวกับ Metrics และ Gridขนาด48 dpนั้นสะดวกสบายสำหรับวัตถุแบบสัมผัสและ32 dpนั้นน้อยที่สุดสำหรับปุ่ม คีย์บอร์ดนุ่มทั่วไปควรมีปุ่มแถว 4 แถวดังนั้นความสูงของแป้นพิมพ์ขั้นต่ำควรเป็น: 32 dp * 4 = 128 dpซึ่งหมายความว่าขนาดเกณฑ์ควรถ่ายโอนเป็นพิกเซลด้วยความหนาแน่นของอุปกรณ์คูณ สำหรับอุปกรณ์ xxxhdpi (ความหนาแน่น 4) ขีดจำกัดความสูงของคีย์บอร์ดอ่อนควรเป็น 128 * 4 = 512 พิกเซล
ความแตกต่างของความสูงระหว่างมุมมองรูทและพื้นที่ที่มองเห็นได้:
ความสูงของมุมมองรูท - ความสูงของแถบสถานะ - ความสูงของเฟรมที่มองเห็น = ด้านล่างของมุมมองรูท - ด้านล่างของเฟรมที่มองเห็นเนื่องจากความสูงของแถบสถานะ
private final String TAG = "TextEditor";
private TextView mTextEditor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
mTextEditor = (TextView) findViewById(R.id.text_editor);
mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
isKeyboardShown(mTextEditor.getRootView());
}
});
}
private boolean isKeyboardShown(View rootView) {
/* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
/* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
int heightDiff = rootView.getBottom() - r.bottom;
/* Threshold size: dp to pixels, multiply with display density */
boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;
Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
+ "root view height:" + rootView.getHeight() + ", rect:" + r);
return isKeyboardShown;
}
ฉันใช้เวลาเล็กน้อยในการคิดสิ่งนี้ ... ฉันใช้งาน CastExceptions บางส่วน แต่คิดว่าคุณสามารถแทนที่ LinearLayout ใน layout.xml ด้วยชื่อคลาสได้
แบบนี้:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">
<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:id="@+id/rlMaster" >
<LinearLayout android:layout_width="fill_parent"
android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>
....
</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>
</LinearLayout>
ด้วยวิธีนี้คุณจะไม่พบปัญหาใด ๆ
... และหากคุณไม่ต้องการทำสิ่งนี้ในทุก ๆ หน้าฉันแนะนำให้คุณใช้ "MasterPage ใน Android" ดูลิงค์ได้ที่นี่: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
การตรวจสอบความสูงขององค์ประกอบไม่น่าเชื่อถือเนื่องจากคีย์บอร์ดบางรุ่นเช่น WifiKeyboard มีความสูงเป็นศูนย์
คุณสามารถใช้ผลลัพธ์การโทรกลับของ showSoftInput () และ hideSoftInput () แทนเพื่อตรวจสอบสถานะของคีย์บอร์ด รายละเอียดและรหัสตัวอย่างที่
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
แนวคิดคือถ้าคุณต้องการซ่อนแป้นพิมพ์และตรวจสอบสถานะอินพุตแบบซอฟต์พร้อมกันให้ใช้วิธีแก้ไขปัญหาต่อไปนี้:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
เมธอดนี้ส่งคืนค่าจริงหากคีย์บอร์ดถูกแสดงก่อนซ่อน
ฉันพบว่าการรวมกันของวิธีการของ @ Reuben_Scratton พร้อมกับวิธีการของ @ Yogesh นั้นทำงานได้ดีที่สุด การรวมวิธีการของพวกเขาจะให้ผลดังนี้:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
// ... do something here
}
}
});
คุณสามารถสังเกตการซ่อนซอฟต์คีย์บอร์ดได้โดยใช้ decorView ของกิจกรรม
public final class SoftKeyboardUtil {
public static final String TAG = "SoftKeyboardUtil";
public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
final View decorView = activity.getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
int displayHight = rect.bottom - rect.top;
int hight = decorView.getHeight();
boolean hide = (double)displayHight / hight > 0.8 ;
if(Log.isLoggable(TAG, Log.DEBUG)){
Log.d(TAG ,"DecorView display hight = "+displayHight);
Log.d(TAG ,"DecorView hight = "+ hight);
Log.d(TAG, "softkeyboard visible = " + !hide);
}
listener.onSoftKeyBoardVisible(!hide);
}
});
}
public interface OnSoftKeyBoardHideListener{
void onSoftKeyBoardVisible(boolean visible);
}
}
แทนที่จะสมมติว่ารหัสต่างกันฉันทำอะไรแบบนี้เพราะฉันมีตัวเลือกเมนูในแอปพลิเคชันของฉัน
final View root= findViewById(R.id.myrootview);
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = root.getRootView().getHeight() - root.getHeight();
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
if(heightDiff <= contentViewTop){
//Soft KeyBoard Hidden
}else{
//Soft KeyBoard Shown
}
}
});
นอกจากนี้ยังมีวิธีแก้ปัญหาด้วยการแทรกของระบบ แต่ใช้งานได้เฉพาะกับAPI >= 21
( Android L
) สมมติว่าคุณมีBottomNavigationView
ซึ่งเป็นลูกของLinearLayout
คุณจำเป็นต้องซ่อนมันเมื่อแป้นพิมพ์ปรากฏขึ้น:
> LinearLayout
> ContentView
> BottomNavigationView
สิ่งที่คุณต้องทำคือการขยายLinearLayout
ในลักษณะเช่นนี้:
public class KeyboardAwareLinearLayout extends LinearLayout {
public KeyboardAwareLinearLayout(Context context) {
super(context);
}
public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public KeyboardAwareLinearLayout(Context context,
@Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
View view = getChildAt(index);
if (view instanceof BottomNavigationView) {
int bottom = insets.getSystemWindowInsetBottom();
if (bottom >= ViewUtils.dpToPx(200)) {
// keyboard is shown
view.setVisibility(GONE);
} else {
// keyboard is hidden
view.setVisibility(VISIBLE);
}
}
}
return insets;
}
}
แนวคิดก็คือเมื่อมีการแสดงแป้นพิมพ์ระบบจะเปลี่ยน.bottom
ค่าที่ค่อนข้างใหญ่
มีวิธีที่ซ่อนอยู่สามารถช่วยInputMethodManager.getInputMethodWindowVisibleHeight
ได้ แต่ฉันไม่รู้ว่าทำไมมันถึงซ่อนอยู่
import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager
class SoftKeyboardStateWatcher(private val ctx: Context) {
companion object {
private const val DELAY = 10L
}
private val handler = Handler()
private var isSoftKeyboardOpened: Boolean = false
private val height: Int
get() {
val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
method.isAccessible = true
return method.invoke(imm) as Int
}
private val task: Runnable by lazy {
Runnable {
start()
if (!isSoftKeyboardOpened && height > 0) {
isSoftKeyboardOpened = true
notifyOnSoftKeyboardOpened(height)
} else if (isSoftKeyboardOpened && height == 0) {
isSoftKeyboardOpened = false
notifyOnSoftKeyboardClosed()
}
}
}
var listener: SoftKeyboardStateListener? = null
interface SoftKeyboardStateListener {
fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
fun onSoftKeyboardClosed()
}
fun start() {
handler.postDelayed(task, DELAY)
}
fun stop() {
handler.postDelayed({
if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
}, DELAY * 10)
}
private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
listener?.onSoftKeyboardOpened(keyboardHeightInPx)
}
private fun notifyOnSoftKeyboardClosed() {
listener?.onSoftKeyboardClosed()
}
}
วิธีแก้ปัญหาเหล่านี้จะไม่สามารถใช้กับ Lollipop ได้ ใน Lollipop activityRootView.getRootView().getHeight()
รวมถึงความสูงของแถบปุ่มในขณะที่การวัดมุมมองไม่ได้ ฉันได้ปรับแก้ปัญหาที่ดีที่สุด / ง่ายที่สุดข้างต้นเพื่อทำงานกับ Lollipop
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
Resources res = getResources();
// The status bar is 25dp, use 50dp for assurance
float maxDiff =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());
//Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float buttonBarHeight =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
maxDiff += buttonBarHeight;
}
if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
...do something here
}
}
});
ฉันเพิ่งพบข้อผิดพลาดขณะใช้โซลูชันส่วนใหญ่ด้านบนที่แนะนำให้เพิ่มหมายเลขคงที่
S4 นั้นมี dpi สูงซึ่งส่งผลให้ความสูงของแถบการนำทางอยู่ที่ 100px ทำให้แอปของฉันคิดว่าแป้นพิมพ์เปิดอยู่ตลอดเวลา
ดังนั้นด้วยโทรศัพท์ความละเอียดสูงใหม่ทั้งหมดที่มีการเปิดตัวฉันเชื่อว่าการใช้ค่าที่เข้ารหัสยากไม่ใช่ความคิดที่ดีในระยะยาว
วิธีที่ดีกว่าที่ฉันพบหลังจากการทดสอบบนหน้าจอและอุปกรณ์ต่าง ๆ คือใช้เปอร์เซ็นต์ รับความแตกต่างระหว่างเนื้อหาแอพ decorView และ ur และหลังจากนั้นตรวจสอบว่าเปอร์เซ็นต์ของความแตกต่างนั้นคืออะไร จากสถิติที่ฉันได้รับแถบนำทาง (โดยไม่คำนึงถึงขนาดความละเอียด ฯลฯ ) ส่วนใหญ่จะใช้ระหว่าง 3% ถึง 5% ของหน้าจอ โดยที่ราวกับว่าคีย์บอร์ดเปิดอยู่มันใช้เวลาระหว่าง 47% ถึง 55% ของหน้าจอ
โดยสรุปแล้วทางออกของฉันคือการตรวจสอบว่าส่วนต่างนั้นมีค่ามากกว่า 10% หรือไม่จากนั้นฉันถือว่าแป้นพิมพ์นั้นเปิดอยู่
ฉันใช้คำตอบของ Reuban เล็กน้อยซึ่งพิสูจน์แล้วว่ามีประโยชน์มากขึ้นในบางสถานการณ์โดยเฉพาะกับอุปกรณ์ความละเอียดสูง
final View activityRootView = findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightView = activityRootView.getHeight();
int widthView = activityRootView.getWidth();
if (1.0 * widthView / heightView > 3) {
//Make changes for Keyboard not visible
} else {
//Make changes for keyboard visible
}
}
});
R.id.activityRoot
คุณสามารถใช้android.R.id.content
สิ่งที่คุณต้องการ
มันมีมานานแล้วในแง่ของคอมพิวเตอร์ แต่คำถามนี้ยังมีความเกี่ยวข้องอย่างไม่น่าเชื่อ! ดังนั้นฉันจึงได้คำตอบข้างต้นและรวมเข้าด้วยกันและทำให้ดีขึ้นเล็กน้อย ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isOpen = heightDiff > 100;
if (isOpen == wasOpened) {
logDebug("Ignoring global layout change...");
return;
}
wasOpened = isOpen;
listener.onVisibilityChanged(isOpen);
}
});
}
มันใช้งานได้สำหรับฉัน
ลองสิ่งนี้:
final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
// ... do something here ... \\
}
}
});
คำตอบของฉันนั้นโดยทั่วไปเหมือนกับคำตอบของ Kachi แต่ฉันห่อไว้ในคลาสผู้ช่วยที่ดีเพื่อทำความสะอาดวิธีการใช้งานตลอดทั้งแอพของฉัน
import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/**
* Detects Keyboard Status changes and fires events only once for each change
*/
public class KeyboardStatusDetector {
KeyboardVisibilityListener visibilityListener;
boolean keyboardVisible = false;
public void registerFragment(Fragment f) {
registerView(f.getView());
}
public void registerActivity(Activity a) {
registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
}
public KeyboardStatusDetector registerView(final View v) {
v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
v.getWindowVisibleDisplayFrame(r);
int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
/** Check this variable to debounce layout events */
if(!keyboardVisible) {
keyboardVisible = true;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
}
} else {
if(keyboardVisible) {
keyboardVisible = false;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
}
}
}
});
return this;
}
public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
visibilityListener = listener;
return this;
}
public static interface KeyboardVisibilityListener {
public void onVisibilityChanged(boolean keyboardVisible);
}
}
คุณสามารถใช้สิ่งนี้เพื่อตรวจจับการเปลี่ยนแปลงของแป้นพิมพ์ได้ทุกที่ในแอปเช่นนี้
new KeyboardStatusDetector()
.registerFragment(fragment) //register to a fragment
.registerActivity(activity) //or register to an activity
.registerView(view) //or register to a view
.setVisibilityListener(new KeyboardVisibilityListener() {
@Override
public void onVisibilityChanged(boolean keyboardVisible) {
if(keyboardVisible) {
//Do stuff for keyboard visible
}else {
//Do stuff for keyboard hidden
}
}
});
หมายเหตุ: ใช้หนึ่งในสาย "ลงทะเบียน" เท่านั้น พวกเขาทั้งหมดทำงานเหมือนกันและมีเพื่อความสะดวกเท่านั้น
คุณสามารถลองสิ่งนี้ทำงานได้ดีสำหรับฉัน:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
ฉันมีปัญหาในการรักษาสถานะแป้นพิมพ์เมื่อเปลี่ยนการวางแนวของชิ้นส่วนภายใน viewpager ฉันไม่แน่ใจว่าทำไม แต่ดูเหมือนจะเฉื่อยชาและทำหน้าที่แตกต่างจากกิจกรรมมาตรฐาน
เพื่อรักษาสถานะแป้นพิมพ์ในกรณีนี้ก่อนอื่นคุณควรเพิ่มandroid:windowSoftInputMode = "stateUnchanged"
ของคุณAndroidManifest.xml
ที่คุณคุณอาจสังเกตเห็นว่าสิ่งนี้ไม่ได้แก้ปัญหาทั้งหมดจริง ๆ - แป้นพิมพ์ไม่เปิดให้ฉันถ้ามันถูกเปิดก่อนหน้านี้ก่อนที่จะเปลี่ยนการวางแนว ในกรณีอื่น ๆ พฤติกรรมดูเหมือนจะถูกต้อง
จากนั้นเราต้องใช้วิธีแก้ไขปัญหาที่กล่าวถึงที่นี่ สิ่งที่สะอาดที่สุดที่ฉันพบคือ George Maisuradze's - ใช้การติดต่อกลับบูลีนจาก hideSoftInputFromWindow:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
ฉันเก็บค่านี้ในonSaveInstanceState
วิธีส่วนของฉันและดึงมันonCreate
มา จากนั้นฉันบังคับให้แสดงแป้นพิมพ์ในonCreateView
กรณีที่มีค่าเป็นtrue
(มันจะกลับมาจริงถ้าแป้นพิมพ์สามารถมองเห็นได้ก่อนที่จะซ่อนตัวจริงก่อนที่จะทำลายชิ้นส่วน)
นี่คือทางออกของฉันและใช้งานได้ แทนที่จะมองหาขนาดพิกเซลเพียงตรวจสอบว่าความสูงของมุมมองเนื้อหาเปลี่ยนไปหรือไม่:
// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private int oldHeight;
@Override
public void onGlobalLayout() {
int newHeight = commentsContent.getMeasuredHeight();
if (newHeight < oldHeight) {
// Check for the keyboard showing in case the height difference
// is a result of orientation change
if (isSoftKeyboardShowing(CommentsActivity.this)) {
// Keyboard is showing so scroll to the latest comment
scrollToLatestComment();
}
}
oldHeight = newHeight;
}
});
public static boolean isSoftKeyboardShowing(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
return inputMethodManager.isActive();
}
อย่าทำรหัสยาก ๆ วิธีที่ดีที่สุดคือคุณต้องปรับขนาดมุมมองของคุณในขณะที่รับโฟกัสบน EditText ด้วย KeyBord Show คุณสามารถเพิ่มคุณสมบัติการปรับขนาดในกิจกรรมลงในไฟล์ Manifest โดยใช้รหัสด้านล่าง
android:windowSoftInputMode="adjustResize"
มีวิธีการโดยตรงเพื่อหาสิ่งนี้ และไม่ต้องการการเปลี่ยนแปลงเค้าโครงใด ๆ
ดังนั้นมันจะทำงานในโหมดเต็มหน้าจอแบบเต็มจอด้วยเช่นกัน
เคล็ดลับคือคุณพยายามซ่อนหรือแสดงคีย์บอร์ดอ่อนและจับผลลัพธ์ของการลอง
ไม่ต้องตกใจนี่ไม่ได้แสดงหรือซ่อนคีย์บอร์ดจริงๆ เราแค่ขอให้รัฐ
หากต้องการติดตามข้อมูลล่าสุดคุณสามารถดำเนินการซ้ำได้อย่างง่ายดายเช่นทุกๆ 200 มิลลิวินาทีโดยใช้ตัวจัดการ
คุณพบการใช้งานที่นี่: https://stackoverflow.com/a/27567074/2525452
ฉันคิดว่าวิธีนี้จะช่วยให้คุณค้นพบว่ามีปุ่มกดปรากฏให้เห็นหรือไม่
public Boolean isSoftKeyBoardVisible(){
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
Log.d(TAG,"Software Keyboard was shown");
return true;
} else {
Log.d(TAG,"Software Keyboard was not shown");
return false;
}
}
คำตอบใหม่ของ Reuben Scratton (คำนวณ HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
) จะไม่ทำงานหากคุณตั้งโหมดแถบสถานะโปร่งแสง
ถ้าคุณใช้แถบสถานะโปร่งแสง activityRootView.getHeight()
จะไม่เปลี่ยนสภาพอากาศเมื่อมองเห็นคีย์บอร์ดนุ่ม มันจะคืนความสูงของกิจกรรมและแถบสถานะเสมอ
ตัวอย่างเช่น Nexus 4, Android 5.0.1 ตั้งค่าandroid:windowTranslucentStatus
เป็นจริงมันจะคืนค่า 1184 ตลอดกาลแม้ ime จะมี opend หากตั้งไว้android:windowTranslucentStatus
เป็นเท็จมันจะคืนค่าความสูงได้อย่างถูกต้องหาก ime มองไม่เห็นมันส่งคืน 1134 (ไม่รวมแถบสถานะ) 。ปิดค่า ime ค่านั้นจะคืน 5xx อาจขึ้นอยู่กับความสูงของ ime
ฉันไม่ทราบว่าสภาพอากาศนี้เป็นจุดบกพร่องฉันลองใช้ 4.4.4 และ 5.0.1 ผลลัพธ์เหมือนกัน
ดังนั้นถึงตอนนี้คำตอบที่ได้รับการยอมรับมากเป็นอันดับสองคำตอบของ Kachi จะเป็นวิธีที่ปลอดภัยที่สุดในการคำนวณความสูงของค่า ime นี่คือสำเนา:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});
วิธีการที่ไม่ต้องการ LayoutListener
ในกรณีของฉันฉันต้องการบันทึกสถานะของแป้นพิมพ์ก่อนที่จะเปลี่ยนชิ้นส่วนของฉัน ฉันเรียกเมธอด hideSoftInputFromWindowจากonSaveInstanceState
ซึ่งจะปิดแป้นพิมพ์และส่งคืนฉันว่าแป้นพิมพ์นั้นสามารถมองเห็นได้หรือไม่
วิธีนี้ตรงไปตรงมา แต่อาจเปลี่ยนสถานะของแป้นพิมพ์ของคุณ
ฉันรู้ว่านี่เป็นโพสต์เก่า แต่ฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดที่ฉันรู้และอุปกรณ์ทดสอบของฉันคือ Nexus 5 ฉันไม่ได้ลองในอุปกรณ์อื่น หวังว่าคนอื่นจะแบ่งปันแนวทางของพวกเขาหากพวกเขาพบว่ารหัสของฉันไม่ดี :)
public static boolean isKeyboardShown(Context context, View view) {
if (context == null || view == null) {
return false;
}
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
imm.hideSoftInputFromWindow ส่งคืนบูลีน
ขอบคุณ
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
ฟังก์ชั่นด้านบนเป็นสิ่งที่ฉันใช้ตรวจสอบว่ามีแป้นพิมพ์ปรากฏอยู่หรือไม่ ถ้าเป็นเช่นนั้นฉันจะปิดมัน
ด้านล่างแสดงวิธีการสองวิธีที่จำเป็น
ก่อนอื่นให้กำหนดความสูงของหน้าต่างที่สามารถทำงานได้ใน onCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// add to onCreate method
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
sheight= rectgle.bottom;
//
}
จากนั้นเพิ่มเมธอดบูลีนที่รับค่าความสูงหน้าต่างในอินสแตนซ์นั้น หากไม่ตรงกับต้นฉบับ (สมมติว่าคุณไม่ได้เปลี่ยนไปตามทาง ... ) แสดงว่าแป้นพิมพ์เปิดอยู่
public boolean keyopen()
{
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int curheight= rectgle.bottom;
if (curheight!=sheight)
{
return true;
}
else
{
return false;
}
}
Frotz!
ฉันรู้ว่าคุณสามารถระบุได้อย่างแม่นยำว่าแป้นพิมพ์ถูกซ่อนอยู่หรือไม่
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public int getNavigationBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public boolean isKeyboardHidden() {
int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
- getSupportActionBar().getHeight();
return delta <= 0;
}
ใช้งานได้กับแท็บเล็ต เมื่อแถบนำทางถูกแสดงในแนวนอน