Android มีวิธีการในการตรวจสอบว่าซอฟต์แวร์ (หรือที่เรียกว่า "soft") ปรากฏบนหน้าจอหรือไม่?
Android มีวิธีการในการตรวจสอบว่าซอฟต์แวร์ (หรือที่เรียกว่า "soft") ปรากฏบนหน้าจอหรือไม่?
คำตอบ:
ไม่มีวิธีการโดยตรง - ดูhttp://groups.google.com/group/android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898aโดยที่ Dianne Hackborn จากทีม Android ได้ตอบกลับ อย่างไรก็ตามคุณสามารถตรวจจับได้โดยอ้อมโดยตรวจสอบว่าขนาดหน้าต่างเปลี่ยนแปลงใน #onMeasure หรือไม่ ดูวิธีตรวจสอบการมองเห็นคีย์บอร์ดของซอฟต์แวร์ใน Android .
มันใช้งานได้สำหรับฉัน บางทีนี้อยู่เสมอวิธีที่ดีที่สุดสำหรับทุกรุ่น
มันจะมีประสิทธิภาพในการทำให้คุณสมบัติของการมองเห็นแป้นพิมพ์และสังเกตการเปลี่ยนแปลงนี้ล่าช้าเนื่องจากวิธี onGlobalLayout เรียกหลายครั้ง นอกจากนี้ก็เป็นสิ่งที่ดีที่จะตรวจสอบการหมุนอุปกรณ์และไม่ได้เป็นwindowSoftInputMode
adjustNothing
boolean isKeyboardShowing = false;
void onKeyboardVisibilityChanged(boolean opened) {
print("keyboard " + opened);
}
// ContentView is the root view of the layout of this activity/fragment
contentView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
contentView.getWindowVisibleDisplayFrame(r);
int screenHeight = contentView.getRootView().getHeight();
// r.bottom is the position above soft keypad or device button.
// if keypad is shown, the r.bottom is smaller than that before.
int keypadHeight = screenHeight - r.bottom;
Log.d(TAG, "keypadHeight = " + keypadHeight);
if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
// keyboard is opened
if (!isKeyboardShowing) {
isKeyboardShowing = true
onKeyboardVisibilityChanged(true)
}
}
else {
// keyboard is closed
if (isKeyboardShowing) {
isKeyboardShowing = false
onKeyboardVisibilityChanged(false)
}
}
}
});
contentView
ประกาศที่ไหน?
ลองนี้:
InputMethodManager imm = (InputMethodManager) getActivity()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
writeToLog("Software Keyboard was shown");
} else {
writeToLog("Software Keyboard was not shown");
}
ฉันสร้างชั้นง่ายๆที่สามารถนำมาใช้สำหรับการนี้: https://github.com/ravindu1024/android-keyboardlistener เพียงแค่คัดลอกไปยังโครงการของคุณและใช้ดังต่อไปนี้:
KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
{
@Override
public void onToggleSoftKeyboard(boolean isVisible)
{
Log.d("keyboard", "keyboard visible: "+isVisible);
}
});
rootView
เป็นเพียงมุมมองที่ชี้ไปที่มุมมองรูตของฉันในกรณีนี้คือrelative layout
:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/addresses_confirm_root_view"
android:background="@color/WHITE_CLR">
RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view);
getViewTreeObserver()
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();
if (heightDiff > 100) {
Log.e("MyActivity", "keyboard opened");
} else {
Log.e("MyActivity", "keyboard closed");
}
}
});
1
ฉันคิดว่านี่อาจจะเป็นและ ไม่เป็นไร เพียงแค่นี้จะต้องน้อยกว่าความยาวจริงของแป้นพิมพ์
ฉันใช้สิ่งนี้เป็นพื้นฐาน: http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android
/**
* To capture the result of IMM hide/show soft keyboard
*/
public class IMMResult extends ResultReceiver {
public int result = -1;
public IMMResult() {
super(null);
}
@Override
public void onReceiveResult(int r, Bundle data) {
result = r;
}
// poll result value for up to 500 milliseconds
public int getResult() {
try {
int sleep = 0;
while (result == -1 && sleep < 500) {
Thread.sleep(100);
sleep += 100;
}
} catch (InterruptedException e) {
Log.e("IMMResult", e.getMessage());
}
return result;
}
}
จากนั้นเขียนวิธีนี้:
public boolean isSoftKeyboardShown(InputMethodManager imm, View v) {
IMMResult result = new IMMResult();
int res;
imm.showSoftInput(v, 0, result);
// if keyboard doesn't change, handle the keypress
res = result.getResult();
if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN ||
res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) {
return true;
}
else
return false;
}
จากนั้นคุณสามารถใช้สิ่งนี้เพื่อทดสอบฟิลด์ทั้งหมด (EditText, AutoCompleteTextView และอื่น ๆ ) ที่อาจเปิด softkeyboard:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if(isSoftKeyboardShown(imm, editText1) | isSoftKeyboardShown(imm, autocompletetextview1))
//close the softkeyboard
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
ไม่ได้เป็นทางออกที่ดี แต่ก็ทำให้งานเสร็จสมบูรณ์
คุณสามารถใช้ผลลัพธ์การโทรกลับของ showSoftInput () และ hideSoftInput () เพื่อตรวจสอบสถานะของคีย์บอร์ด รายละเอียดและรหัสตัวอย่างที่
http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android
คุณสามารถอ้างถึงคำตอบนี้ - https://stackoverflow.com/a/24105062/3629912
มันทำงานให้ฉันทุกครั้ง
adb shell dumpsys window InputMethod | grep "mHasSurface"
มันจะกลับมาจริงถ้าแป้นพิมพ์ซอฟต์แวร์สามารถมองเห็นได้
ดังนั้นหลังจากเล่นเป็นเวลานานด้วย AccessibilityServices, insets window, การตรวจจับความสูงของหน้าจอเป็นต้นฉันคิดว่าฉันพบวิธีในการทำเช่นนี้
คำเตือน: มันใช้วิธีการที่ซ่อนอยู่ใน Android ซึ่งหมายความว่ามันอาจไม่สอดคล้องกัน อย่างไรก็ตามในการทดสอบของฉันดูเหมือนว่าจะใช้งานได้
วิธีการคือInputMethodManager # getInputMethodWindowVisibleHeight ()และมีอยู่ตั้งแต่ Lollipop (5.0)
การโทรที่ส่งกลับความสูงเป็นพิกเซลของแป้นพิมพ์ปัจจุบัน ตามทฤษฎีแล้วแป้นพิมพ์ไม่ควรมีความสูง 0 พิกเซลดังนั้นฉันจึงทำการตรวจสอบความสูงอย่างง่าย (ใน Kotlin):
val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
//keyboard is shown
else {
//keyboard is hidden
}
ฉันใช้Android Hidden APIเพื่อหลีกเลี่ยงการสะท้อนเมื่อฉันเรียกวิธีการที่ซ่อนอยู่ (ฉันทำสิ่งนี้มากมายสำหรับแอพที่ฉันพัฒนาซึ่งส่วนใหญ่เป็นแอปแฮ็คเกอร์ / จูนเนอร์) แต่สิ่งนี้ควรเป็นไปได้ด้วย
val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
val windowHeightMethod = InputMethodManager::class.java.getMethod("getInputMethodWindowVisibleHeight")
val height = windowHeightMethod.invoke(imm) as Int
//use the height val in your logic
นี่ซับซ้อนน้อยกว่าข้อกำหนดที่ฉันต้องการ หวังว่านี่จะช่วยได้:
เกี่ยวกับกิจกรรมหลัก:
public void dismissKeyboard(){
InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
mKeyboardStatus = false;
}
public void showKeyboard(){
InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
mKeyboardStatus = true;
}
private boolean isKeyboardActive(){
return mKeyboardStatus;
}
เริ่มต้นค่าบูลีน primative สำหรับ mKeyboardStatus จะเริ่มต้นได้ที่เป็นเท็จ
จากนั้นตรวจสอบค่าดังต่อไปนี้และดำเนินการหากจำเป็น:
mSearchBox.requestFocus();
if(!isKeyboardActive()){
showKeyboard();
}else{
dismissKeyboard();
}
สิ่งนี้จะใช้ได้ถ้าคุณต้องการตรวจสอบสถานะของแป้นพิมพ์:
fun Activity.isKeyboardOpened(): Boolean {
val r = Rect()
val activityRoot = getActivityRoot()
val visibleThreshold = dip(UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP)
activityRoot.getWindowVisibleDisplayFrame(r)
val heightDiff = activityRoot.rootView.height - r.height()
return heightDiff > visibleThreshold;
}
fun Activity.getActivityRoot(): View {
return (findViewById<ViewGroup>(android.R.id.content)).getChildAt(0);
}
โดยที่UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP
= 100 และ dip () เป็น anko func ที่แปลง dpToPx:
fun dip(value: Int): Int {
return (value * Resources.getSystem().displayMetrics.density).toInt()
}
ฉันทำสิ่งนี้โดยการตั้งค่า GlobalLayoutListener ดังนี้:
final View activityRootView = findViewById(R.id.activityRoot);
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
}
}
});
ลองใช้รหัสนี้ใช้งานได้จริงหาก KeyboardShown แสดงแล้วฟังก์ชันนี้จะคืนค่าที่แท้จริง ....
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;
}
ในกรณีของฉันฉันมีเพียงหนึ่งEditText
ในการจัดการในรูปแบบของฉันดังนั้นฉันขึ้นมาเล็กน้อยนี้การแก้ปัญหา มันใช้งานได้ดีโดยทั่วไปมันเป็นแบบกำหนดเองEditText
ที่รับฟังการโฟกัสและส่งการออกอากาศเฉพาะที่หากการเปลี่ยนแปลงโฟกัสหรือกดปุ่มย้อนกลับ / เสร็จสิ้น ในการทำงานคุณต้องวางจำลองView
ในเค้าโครงของคุณด้วยandroid:focusable="true"
และandroid:focusableInTouchMode="true"
เนื่องจากเมื่อคุณเรียกclearFocus()
โฟกัสจะถูกกำหนดใหม่ให้กับมุมมองที่โฟกัสได้แรก ตัวอย่างมุมมองดัมมี่:
<View
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"/>
ข่าวสารเพิ่มเติม
วิธีแก้ปัญหาที่ตรวจพบความแตกต่างในการเปลี่ยนแปลงเค้าโครงทำได้ไม่ดีนักเพราะมันขึ้นอยู่กับความหนาแน่นของหน้าจอเนื่องจาก 100px อาจมีจำนวนมากในอุปกรณ์บางอย่าง ผู้จำหน่ายที่ต่างกันก็มีคีย์บอร์ดที่แตกต่างกัน
ใน Android คุณสามารถตรวจจับผ่าน ADB เชลล์ ฉันเขียนและใช้วิธีนี้:
{
JSch jsch = new JSch();
try {
Session session = jsch.getSession("<userName>", "<IP>", 22);
session.setPassword("<Password>");
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
ChannelExec channel = (ChannelExec)session.openChannel("exec");
BufferedReader in = new BufferedReader(new
InputStreamReader(channel.getInputStream()));
channel.setCommand("C:/Android/android-sdk/platform-tools/adb shell dumpsys window
InputMethod | findstr \"mHasSurface\"");
channel.connect();
String msg = null;
String msg2 = " mHasSurface=true";
while ((msg = in.readLine()) != null) {
Boolean isContain = msg.contains(msg2);
log.info(isContain);
if (isContain){
log.info("Hiding keyboard...");
driver.hideKeyboard();
}
else {
log.info("No need to hide keyboard.");
}
}
channel.disconnect();
session.disconnect();
} catch (JSchException | IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
final View activityRootView = findViewById(R.id.rootlayout);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
activityRootView.getWindowVisibleDisplayFrame(r);
int screenHeight = activityRootView.getRootView().getHeight();
Log.e("screenHeight", String.valueOf(screenHeight));
int heightDiff = screenHeight - (r.bottom - r.top);
Log.e("heightDiff", String.valueOf(heightDiff));
boolean visible = heightDiff > screenHeight / 3;
Log.e("visible", String.valueOf(visible));
if (visible) {
Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show();
}
}
});
คำตอบของ @iWantScala นั้นยอดเยี่ยม แต่ไม่ได้ผลสำหรับฉัน
rootView.getRootView().getHeight()
มีค่าเท่ากันเสมอ
วิธีหนึ่งคือการกำหนดสอง vars
private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;
เพิ่มฟังทั่วโลก
rootView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
currentRootViewHeight = rootView.getHeight();
if (currentRootViewHeight > maxRootViewHeight) {
maxRootViewHeight = currentRootViewHeight;
}
}
});
จากนั้นตรวจสอบ
if (currentRootViewHeight >= maxRootViewHeight) {
// Keyboard is hidden
} else {
// Keyboard is shown
}
ทำงานได้ดี
ในที่สุดก็มีวิธีการเริ่มต้นโดยตรงจาก Android R ตาม Kotlin ตอนนี้
val imeInsets = view.rootWindowInsets.getInsets(Type.ime())
if (imeInsets.isVisible) {
//Ime is visible
//Lets move our view by the height of the IME
view.translationX = imeInsets.bottom }
ฉันมีปัญหาที่คล้ายกัน ฉันจำเป็นต้องตอบสนองต่อปุ่ม Enter บนหน้าจอ (ซึ่งซ่อนแป้นพิมพ์) ในกรณีนี้คุณสามารถสมัครสมาชิก OnEditorAction ของมุมมองข้อความที่แป้นพิมพ์ถูกเปิดด้วย - หากคุณมีช่องที่สามารถแก้ไขได้หลายกล่องจากนั้นสมัครสมาชิกทั้งหมด
ในกิจกรรมของคุณคุณสามารถควบคุมแป้นพิมพ์ได้อย่างเต็มที่ดังนั้นคุณจะไม่ประสบปัญหาว่าจะเปิดแป้นพิมพ์หรือไม่หากคุณฟังเหตุการณ์การเปิดและปิดทั้งหมด
มีวิธีการโดยตรงเพื่อหาสิ่งนี้ และไม่ต้องการการเปลี่ยนแปลงโครงร่าง
ดังนั้นมันจึงทำงานในโหมดเต็มหน้าจอแบบเต็มอิ่มเช่นกัน
แต่น่าเสียดายที่มันไม่สามารถใช้ได้กับทุกอุปกรณ์ ดังนั้นคุณต้องทดสอบด้วยอุปกรณ์ของคุณ
เคล็ดลับคือคุณพยายามซ่อนหรือแสดงคีย์บอร์ดอ่อนและจับผลลัพธ์ของการลอง
หากใช้งานได้ถูกต้องแสดงว่าคีย์บอร์ดไม่แสดงหรือซ่อนอยู่จริงๆ เราแค่ขอให้รัฐ
หากต้องการติดตามข้อมูลล่าสุดคุณเพียงแค่ทำซ้ำการดำเนินการนี้เช่นทุก ๆ 200 มิลลิวินาทีโดยใช้ตัวจัดการ
การใช้งานด้านล่างนี้เป็นการตรวจสอบเพียงครั้งเดียว
หากคุณทำการตรวจสอบหลายครั้งคุณควรเปิดใช้งานการทดสอบทั้งหมด (_keyboardVisible)
public interface OnKeyboardShowHide
{
void onShowKeyboard( Object param );
void onHideKeyboard( Object param );
}
private static Handler _keyboardHandler = new Handler();
private boolean _keyboardVisible = false;
private OnKeyboardShowHide _keyboardCallback;
private Object _keyboardCallbackParam;
public void start( OnKeyboardShowHide callback, Object callbackParam )
{
_keyboardCallback = callback;
_keyboardCallbackParam = callbackParam;
//
View view = getCurrentFocus();
if (view != null)
{
InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
}
else // if (_keyboardVisible)
{
_keyboardVisible = false;
_keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
}
}
private ResultReceiver _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
{
@Override
protected void onReceiveResult( int resultCode, Bundle resultData )
{
switch (resultCode)
{
case InputMethodManager.RESULT_SHOWN :
case InputMethodManager.RESULT_UNCHANGED_SHOWN :
// if (!_keyboardVisible)
{
_keyboardVisible = true;
_keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
}
break;
case InputMethodManager.RESULT_HIDDEN :
case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
// if (_keyboardVisible)
{
_keyboardVisible = false;
_keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
}
break;
}
}
};
นี่เป็นวิธีแก้ปัญหาเพื่อทราบว่ามีซอฟต์คีย์บอร์ดหรือไม่
แป้นพิมพ์ยอดนิยมบางคำมีคำหลักบางคำใน classnames:
จาก ActivityManager.RunningServiceInfo ตรวจสอบรูปแบบข้างต้นใน ClassNames นอกจากนี้ ActivityManager.RunningServiceInfo ของclientPackage = android แสดงว่าคีย์บอร์ดถูกผูกไว้กับระบบ
ข้อมูลดังกล่าวข้างต้นอาจถูกนำมารวมกันเพื่อหาวิธีที่เข้มงวดในการมองเห็นว่าแป้นพิมพ์ที่อ่อนนุ่มสามารถมองเห็นได้
ดังที่คุณทราบแป้นพิมพ์ซอฟต์แวร์ android จะปรากฏเฉพาะเมื่อมีเหตุการณ์ที่เป็นไปได้ในการพิมพ์ กล่าวอีกนัยหนึ่งแป้นพิมพ์จะปรากฏเฉพาะเมื่อ EditText โฟกัส นั่นหมายความว่าคุณจะได้รับอากาศแป้นพิมพ์จะมองเห็นได้หรือไม่โดยใช้OnFocusChangeListener
//Declare this Globally
public boolean isKeyBoardVisible = false;
//In OnCreate *[For Activity]*, OnCreateView *[For Fragment]*
text_send.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if(hasFocus)
isKeyBoardVisible = true;
else
isKeyBoardVisible = false;
}
});
ตอนนี้คุณสามารถใช้isKeyBoardVisibleตัวแปรได้ทุกที่ในชั้นเรียนเพื่อรับสภาพอากาศแป้นพิมพ์เปิดหรือไม่ มันทำงานได้ดีสำหรับฉัน
หมายเหตุ:กระบวนการนี้ไม่ทำงานเมื่อเปิดแป้นพิมพ์โดยใช้โปรแกรมInputMethodManagerเนื่องจากไม่ได้เรียกใช้ OnFocusChangeListener
ฉันแปลงคำตอบเป็น kotlin หวังว่านี่จะช่วยผู้ใช้ kotlin ได้
private fun checkKeyboardVisibility() {
var isKeyboardShowing = false
binding.coordinator.viewTreeObserver.addOnGlobalLayoutListener {
val r = Rect()
binding.coordinator.getWindowVisibleDisplayFrame(r)
val screenHeight = binding.coordinator.rootView.height
// r.bottom is the position above soft keypad or device button.
// if keypad is shown, the r.bottom is smaller than that before.
val keypadHeight = screenHeight - r.bottom
if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
// keyboard is opened
if (!isKeyboardShowing) {
isKeyboardShowing = true
}
} else {
// keyboard is closed
if (isKeyboardShowing) {
isKeyboardShowing = false
}
}
}
}
มันทำงานร่วมกับการปรับสถานะของกิจกรรมและวงจรชีวิตเหตุการณ์ที่ใช้ ยังมี Kotlin:
/**
* This class uses a PopupWindow to calculate the window height when the floating keyboard is opened and closed
*
* @param activity The parent activity
* The root activity that uses this KeyboardManager
*/
class KeyboardManager(private val activity: AppCompatActivity) : PopupWindow(activity), LifecycleObserver {
private var observerList = mutableListOf<((keyboardTop: Int) -> Unit)>()
/** The last value of keyboardTop */
private var keyboardTop: Int = 0
/** The view that is used to calculate the keyboard top */
private val popupView: View?
/** The parent view */
private var parentView: View
var isKeyboardShown = false
private set
/**
* Create transparent view which will be stretched over to the full screen
*/
private fun createFullScreenView(): View {
val view = LinearLayout(activity)
view.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
view.background = ColorDrawable(Color.TRANSPARENT)
return view
}
init {
this.popupView = createFullScreenView()
contentView = popupView
softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE or LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
inputMethodMode = INPUT_METHOD_NEEDED
parentView = activity.findViewById(android.R.id.content)
width = 0
height = LayoutParams.MATCH_PARENT
popupView.viewTreeObserver.addOnGlobalLayoutListener {
val rect = Rect()
popupView.getWindowVisibleDisplayFrame(rect)
val keyboardTop = rect.bottom
if (this.keyboardTop != keyboardTop) {
isKeyboardShown = keyboardTop < this.keyboardTop
this.keyboardTop = keyboardTop
observerList.forEach { it(keyboardTop) }
}
}
activity.lifecycle.addObserver(this)
}
/**
* This must be called after the onResume of the Activity or inside view.post { } .
* PopupWindows are not allowed to be registered before the onResume has finished
* of the Activity
*/
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun start() {
parentView.post {
if (!isShowing && parentView.windowToken != null) {
setBackgroundDrawable(ColorDrawable(0))
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
}
}
}
/**
* This manager will not be used anymore
*/
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun close() {
activity.lifecycle.removeObserver(this)
observerList.clear()
dismiss()
}
/**
* Set the keyboard top observer. The observer will be notified when the keyboard top has changed.
* For example when the keyboard is opened or closed
*
* @param observer The observer to be added to this provider
*/
fun registerKeyboardTopObserver(observer: (keyboardTop: Int) -> Unit) {
observerList.add(observer)
}
}
วิธีที่มีประโยชน์ในการทำให้มุมมองอยู่เหนือแป้นพิมพ์เสมอ
fun KeyboardManager.updateBottomMarginIfKeyboardShown(
view: View,
activity: AppCompatActivity,
// marginBottom of view when keyboard is hide
marginBottomHideKeyboard: Int,
// marginBottom of view when keybouard is shown
marginBottomShowKeyboard: Int
) {
registerKeyboardTopObserver { bottomKeyboard ->
val bottomView = ViewUtils.getFullViewBounds(view).bottom
val maxHeight = ScreenUtils.getFullScreenSize(activity.windowManager).y
// Check that view is within the window size
if (bottomView < maxHeight) {
if (bottomKeyboard < bottomView) {
ViewUtils.updateMargin(view, bottomMargin = bottomView - bottomKeyboard +
view.marginBottom + marginBottomShowKeyboard)
} else ViewUtils.updateMargin(view, bottomMargin = marginBottomHideKeyboard)
}
}
}
ตำแหน่งที่ getFullViewBounds
fun getLocationOnScreen(view: View): Point {
val location = IntArray(2)
view.getLocationOnScreen(location)
return Point(location[0], location[1])
}
fun getFullViewBounds(view: View): Rect {
val location = getLocationOnScreen(view)
return Rect(location.x, location.y, location.x + view.width,
location.y + view.height)
}
ตำแหน่งที่ getFullScreenSize
fun getFullScreenSize(wm: WindowManager? = null) =
getScreenSize(wm) { getRealSize(it) }
private fun getScreenSize(wm: WindowManager? = null, block: Display.(Point) -> Unit): Point {
val windowManager = wm ?: App.INSTANCE.getSystemService(Context.WINDOW_SERVICE)
as WindowManager
val point = Point()
windowManager.defaultDisplay.block(point)
return point
}
ที่ updateMargin
fun updateMargin(
view: View,
leftMargin: Int? = null,
topMargin: Int? = null,
rightMargin: Int? = null,
bottomMargin: Int? = null
) {
val layoutParams = view.layoutParams as ViewGroup.MarginLayoutParams
if (leftMargin != null) layoutParams.leftMargin = leftMargin
if (topMargin != null) layoutParams.topMargin = topMargin
if (rightMargin != null) layoutParams.rightMargin = rightMargin
if (bottomMargin != null) layoutParams.bottomMargin = bottomMargin
view.layoutParams = layoutParams
}
ฉันทำสิ่งนี้ดังต่อไปนี้ แต่มัน relevet เฉพาะในกรณีที่เป้าหมายของคุณคือการปิด / เปิด keyboad
ปิดตัวอย่าง: (ตรวจสอบว่าแป้นพิมพ์ถูกปิดอยู่หรือไม่ถ้าไม่ปิด)
imm.showSoftInput(etSearch, InputMethodManager.HIDE_IMPLICIT_ONLY, new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN)
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
});
อาจจะใช้:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(
getClass().getSimpleName(),
String.format("conf: %s", newConfig));
if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
onHardwareKeyboardChange(newConfig.hardKeyboardHidden);
hardKeyboardHidden = newConfig.hardKeyboardHidden;
}
if (newConfig.keyboardHidden != keyboardHidden) {
onKeyboardChange(newConfig.keyboardHidden);
keyboardHidden = newConfig.hardKeyboardHidden;
}
}
public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;
//todo
private void onKeyboardChange(int keyboardHidden) {
}
//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {
}
พื้นที่เก็บข้อมูลนี้สามารถช่วยในการตรวจสอบสถานะของแป้นพิมพ์โดยไม่มีการสันนิษฐานว่า "แป้นพิมพ์ควรมีมากกว่า X ส่วนหนึ่งของหน้าจอ"
หากคุณสนับสนุน apis สำหรับ AndroidR ในแอปของคุณคุณสามารถใช้วิธีการด้านล่าง
In kotlin :
var imeInsets = view.rootWindowInsets.getInsets(Type.ime())
if (imeInsets.isVisible) {
view.translationX = imeInsets.bottom
}
หมายเหตุ: นี่เป็นเพียงสำหรับ AndroidR และด้านล่างรุ่น Android ต้องปฏิบัติตามคำตอบอื่น ๆ หรือฉันจะอัปเดตสำหรับสิ่งนั้น