ฉันจะตรวจสอบว่าแป้นพิมพ์ซอฟต์แวร์ปรากฏบนอุปกรณ์ Android ได้อย่างไร


249

Android มีวิธีการในการตรวจสอบว่าซอฟต์แวร์ (หรือที่เรียกว่า "soft") ปรากฏบนหน้าจอหรือไม่?



1
สิ่งที่สามารถแก้ปัญหานี้ในบางกรณี (ถ้าแป้นพิมพ์ของบุคคลที่ 3 มีการติดตั้ง) คือการตรวจสอบการแจ้งเตือนทั่วโลกเมื่อแป้นพิมพ์จะเปิดให้มีการแจ้งเตือนระบบที่กล่าวว่า "การเปลี่ยนแปลงแป้นพิมพ์" - สามารถทำได้ด้วยNotificationListenerService
ศาสตราจารย์

2
เกือบ 8 ปีและยังไม่มีวิธีแก้ปัญหาที่แน่นหนาโอ้ถ้าพวกเขาแนะนำตัวหนึ่งมันจะเป็นของ API> 30 อย่างไรก็ตามไม่เป็นไร ...
M.kazem Akhgary

สำเนาซ้ำที่เป็นไปได้ของAndroid: ตรวจหา
แผงปุ่มกด

คำตอบ:


71

ไม่มีวิธีการโดยตรง - ดูhttp://groups.google.com/group/android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898aโดยที่ Dianne Hackborn จากทีม Android ได้ตอบกลับ อย่างไรก็ตามคุณสามารถตรวจจับได้โดยอ้อมโดยตรวจสอบว่าขนาดหน้าต่างเปลี่ยนแปลงใน #onMeasure หรือไม่ ดูวิธีตรวจสอบการมองเห็นคีย์บอร์ดของซอฟต์แวร์ใน Android .


276

มันใช้งานได้สำหรับฉัน บางทีนี้อยู่เสมอวิธีที่ดีที่สุดสำหรับทุกรุ่น

มันจะมีประสิทธิภาพในการทำให้คุณสมบัติของการมองเห็นแป้นพิมพ์และสังเกตการเปลี่ยนแปลงนี้ล่าช้าเนื่องจากวิธี onGlobalLayout เรียกหลายครั้ง นอกจากนี้ก็เป็นสิ่งที่ดีที่จะตรวจสอบการหมุนอุปกรณ์และไม่ได้เป็นwindowSoftInputModeadjustNothing

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)
            }
        }
    }
});

3
นี่คือส่วนสำคัญในการทำงาน: gist.github.com/faruktoptas/e9778e1f718214938b00c2dcd2bed109
Faruk Toptas

1
ใส่สิ่งนี้ลงในคลาส utils และผ่านกิจกรรม - ตอนนี้มีประโยชน์ทั่วทั้งแอป
Justin

2
และจะมีการcontentViewประกาศที่ไหน?
Code-Apprentice

1
@ Code-Apprentice ในกิจกรรม / ส่วนที่คุณต้องการตอบสนองต่อการเปลี่ยนแปลงแป้นพิมพ์อ่อน ContentView เป็นมุมมองรูทของโครงร่างของกิจกรรม / แฟรกเมนต์นี้
arowrow

1
ทำงานให้ฉันใน Android 6 และ 7
V.March

71

ลองนี้:

InputMethodManager imm = (InputMethodManager) getActivity()
            .getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        writeToLog("Software Keyboard was shown");
    } else {
        writeToLog("Software Keyboard was not shown");
    }

9
สิ่งนี้ไม่ได้ผลสำหรับฉัน แป้นพิมพ์ที่แสดงทริกเกอร์สาขาแม้ในกรณีที่แป้นพิมพ์ไม่เคยปรากฏหรือถูกแสดงแล้วปิด
Peter Ajtai

30
มันจะกลับมาจริงเสมอ
shivang Trivedi

1
ใช่มันจะกลับมาจริงเสมอ
Léon Pelletier

ไม่ถูกต้อง. สิ่งนี้จะส่งกลับจริงเสมอ
Gaurav Arora

178
เป็นที่น่าสงสารว่ากรอบ Android ขาดและแย่ลงไม่สอดคล้องกันในเรื่องนี้ มันควรจะง่ายสุด ๆ
Vicky Chijwani

57

ฉันสร้างชั้นง่ายๆที่สามารถนำมาใช้สำหรับการนี้: https://github.com/ravindu1024/android-keyboardlistener เพียงแค่คัดลอกไปยังโครงการของคุณและใช้ดังต่อไปนี้:

KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
{
    @Override
    public void onToggleSoftKeyboard(boolean isVisible)
    {
        Log.d("keyboard", "keyboard visible: "+isVisible);
    }
});

ฉันต้องใส่รหัสนี้ไว้ที่ไหนใน exaclty ฉันนำสิ่งนี้ไปทำกิจกรรม แต่ไม่พบลักษณะแป้นพิมพ์หรือการหายตัวไป
toom

คุณสามารถนำไปไว้ที่ใดก็ได้ในกิจกรรมของคุณ เพียงวางไว้ในเมธอด onCreate () หลังจากการเรียก setContentView () และคุณควรได้รับการเรียกกลับ แต่คุณลองใช้อุปกรณ์อะไร
ravindu1024

@MaulikDodia ฉันตรวจสอบและทำงานได้ดีในเศษเล็กเศษน้อย ตั้งค่าดังนี้: KeyboardUtils.addKeyboardToggleListener (getActivity (), this); และมันควรจะทำงาน คุณลองใช้อุปกรณ์อะไร
ravindu1024

ฉันลองใช้อุปกรณ์ Moto-G3 @ ravindu1024
Maulik Dodia

ขอบคุณสำหรับตัวอย่างนี้ฉันมีคำถามหนึ่งข้อที่ต้องใช้รหัสนี้เพื่อลบผู้ฟัง?
Pratik Butani

28

ง่ายมาก

1. ใส่ id ในมุมมองรูตของคุณ

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">

2. เริ่มต้นมุมมองรูทของคุณในกิจกรรมของคุณ:

RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view);

3. ตรวจสอบว่าแป้นพิมพ์เปิดหรือปิดโดยใช้ 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");
                }
            }
        });

15
เฮ้เพื่อนช่วยบอกฉันทีว่าเวทมนตร์ 100 มาจากไหน? ทำไมไม่ 101 หรือ 99 ขอบคุณ
Karoly

@Karoly 1ฉันคิดว่านี่อาจจะเป็นและ ไม่เป็นไร เพียงแค่นี้จะต้องน้อยกว่าความยาวจริงของแป้นพิมพ์
Vlad

@Karoly โดยทั่วไปเขาเปรียบเทียบขนาดหน้าต่างกับขนาดมุมมองรูทของกิจกรรมของคุณ ลักษณะที่ปรากฏของแป้นพิมพ์อ่อนจะไม่ส่งผลกระทบต่อขนาดของหน้าต่างหลัก ดังนั้นคุณยังสามารถลดค่าได้ 100
mr5

หมายเลขเวทย์มนตร์นั้นขึ้นอยู่กับเลย์เอาต์ของแถบด้านบนของคุณ ดังนั้นมันจึงสัมพันธ์กับแอปของคุณ ฉันใช้ 400 ในหนึ่งของฉัน
Morten Holmgaard

โปรดจำไว้ว่า onGlobalLayout นั้นถูกเรียกว่าทุกเฟรมดังนั้นคุณต้องไม่ทำอะไรหนัก ๆ ในนั้น
Akshay

8

ฉันใช้สิ่งนี้เป็นพื้นฐาน: 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);

ไม่ได้เป็นทางออกที่ดี แต่ก็ทำให้งานเสร็จสมบูรณ์


2
วิธีนี้ใช้ได้ผล หากคุณใช้งานเป็น singelton คุณสามารถนำไปใช้กับ edittexts ทั้งหมดเกี่ยวกับการเปลี่ยนโฟกัสและมีผู้ฟังแป้นพิมพ์ทั่วโลกหนึ่งคน
Rarw

@depperm getActivity () ใช้เฉพาะแฟรกเมนต์ลอง YourActivityName.this แทน ดูเพิ่มเติมที่: stackoverflow.com/questions/14480129/…
Christopher Hackl


6

คุณสามารถอ้างถึงคำตอบนี้ - https://stackoverflow.com/a/24105062/3629912

มันทำงานให้ฉันทุกครั้ง

adb shell dumpsys window InputMethod | grep "mHasSurface"

มันจะกลับมาจริงถ้าแป้นพิมพ์ซอฟต์แวร์สามารถมองเห็นได้


10
สิ่งนี้มีประโยชน์ในระหว่างการพัฒนาเท่านั้นไม่ใช่วิธีแก้ปัญหาสำหรับใช้ในแอป (ผู้ใช้จะไม่ทำงาน adb)
ToolmakerSteve

5

ดังนั้นหลังจากเล่นเป็นเวลานานด้วย 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

การใช้การสะท้อนที่น่าอัศจรรย์
kaustubhpatange

4

นี่ซับซ้อนน้อยกว่าข้อกำหนดที่ฉันต้องการ หวังว่านี่จะช่วยได้:

เกี่ยวกับกิจกรรมหลัก:

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();
    }

4

สิ่งนี้จะใช้ได้ถ้าคุณต้องการตรวจสอบสถานะของแป้นพิมพ์:

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()
}

3

ฉันทำสิ่งนี้โดยการตั้งค่า 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
                }
            }
        });

สิ่งนี้จะถูกเรียกว่าบ่อยมาก
Denis Kniazhev

สิ่งนี้จะแตกต่างจาก @BrownsooHan อย่างไร ฉันกำลังมองหาวิธีที่แอพพลิเคชั่นดึงแอพอื่น ๆ ออกมาให้พ้นจากการแสดงคีย์บอร์ด
Evan Langlois

คำตอบของเขาคือพื้นฐานเดียวกับของฉันมีเพียงฉันเท่านั้นที่ฉันขุดมาหลายเดือนก่อนหน้าเขาและเขามี upvotes มากกว่า
PearsonArtPhoto

3

ลองใช้รหัสนี้ใช้งานได้จริงหาก 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;
}

isKeyboardShown ยังคงเรียกตัวเองเมื่อมันไม่แสดง
Mandeep Singh

2

ในกรณีของฉันฉันมีเพียงหนึ่ง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 อาจมีจำนวนมากในอุปกรณ์บางอย่าง ผู้จำหน่ายที่ต่างกันก็มีคีย์บอร์ดที่แตกต่างกัน


1

ใน 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();
        }
    }
}

1
คุณสามารถปรับปรุงคำตอบนี้ด้วยตัวอย่างที่เป็นรูปธรรมมากขึ้นด้วยการนำเข้าทั้งหมดและตัวอย่างการทำงานได้หรือไม่?
User3

1
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();
            }
        }
});

1

คำตอบของ @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
}

ทำงานได้ดี


1

ในที่สุดก็มีวิธีการเริ่มต้นโดยตรงจาก 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 }

0

ฉันมีปัญหาที่คล้ายกัน ฉันจำเป็นต้องตอบสนองต่อปุ่ม Enter บนหน้าจอ (ซึ่งซ่อนแป้นพิมพ์) ในกรณีนี้คุณสามารถสมัครสมาชิก OnEditorAction ของมุมมองข้อความที่แป้นพิมพ์ถูกเปิดด้วย - หากคุณมีช่องที่สามารถแก้ไขได้หลายกล่องจากนั้นสมัครสมาชิกทั้งหมด

ในกิจกรรมของคุณคุณสามารถควบคุมแป้นพิมพ์ได้อย่างเต็มที่ดังนั้นคุณจะไม่ประสบปัญหาว่าจะเปิดแป้นพิมพ์หรือไม่หากคุณฟังเหตุการณ์การเปิดและปิดทั้งหมด


ไม่ได้ผลสำหรับฉัน ฉันได้รับเฉพาะคีย์ Enter ใน OnEditorAction
3c71

0

มีวิธีการโดยตรงเพื่อหาสิ่งนี้ และไม่ต้องการการเปลี่ยนแปลงโครงร่าง
ดังนั้นมันจึงทำงานในโหมดเต็มหน้าจอแบบเต็มอิ่มเช่นกัน
แต่น่าเสียดายที่มันไม่สามารถใช้ได้กับทุกอุปกรณ์ ดังนั้นคุณต้องทดสอบด้วยอุปกรณ์ของคุณ

เคล็ดลับคือคุณพยายามซ่อนหรือแสดงคีย์บอร์ดอ่อนและจับผลลัพธ์ของการลอง
หากใช้งานได้ถูกต้องแสดงว่าคีย์บอร์ดไม่แสดงหรือซ่อนอยู่จริงๆ เราแค่ขอให้รัฐ

หากต้องการติดตามข้อมูลล่าสุดคุณเพียงแค่ทำซ้ำการดำเนินการนี้เช่นทุก ๆ 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;
        }
    }
};

วิธีการโทรและที่ไหน
Mahdi Astanei

0

นี่เป็นวิธีแก้ปัญหาเพื่อทราบว่ามีซอฟต์คีย์บอร์ดหรือไม่

  1. ตรวจสอบการเรียกใช้บริการบนระบบโดยใช้ ActivityManager.getRunningServices (max_count_of_services);
  2. จากอินสแตนซ์ ActivityManager.RunningServiceInfo ที่ส่งคืนให้ตรวจสอบค่าclientCountสำหรับบริการคีย์บอร์ดแบบนุ่ม
  3. clientCount ดังกล่าวจะเพิ่มขึ้นทุกครั้งที่คีย์บอร์ดนุ่มจะปรากฏขึ้น ตัวอย่างเช่นถ้า clientCount เป็น 1 ในขั้นต้นมันจะเป็น 2 เมื่อมีการแสดงแป้นพิมพ์
  4. เมื่อเลิกใช้คีย์บอร์ด clientCount จะลดลง ในกรณีนี้จะรีเซ็ตเป็น 1

แป้นพิมพ์ยอดนิยมบางคำมีคำหลักบางคำใน classnames:

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = KeyboardService
  4. Fleksy = คีย์บอร์ด
  5. Adaptxt = IME (KPTAdaptxtIME)
  6. Smart = คีย์บอร์ด (SmartKeyboard)

จาก ActivityManager.RunningServiceInfo ตรวจสอบรูปแบบข้างต้นใน ClassNames นอกจากนี้ ActivityManager.RunningServiceInfo ของclientPackage = android แสดงว่าคีย์บอร์ดถูกผูกไว้กับระบบ

ข้อมูลดังกล่าวข้างต้นอาจถูกนำมารวมกันเพื่อหาวิธีที่เข้มงวดในการมองเห็นว่าแป้นพิมพ์ที่อ่อนนุ่มสามารถมองเห็นได้


0

ดังที่คุณทราบแป้นพิมพ์ซอฟต์แวร์ 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


ไม่ใช่แฮ็คจริงๆไม่ได้ทำงานในกรณีส่วนที่ซ้อนกัน ไม่สามารถพูดเกี่ยวกับกิจกรรมต่างๆได้เพราะฉันยังไม่ได้ลองทำ
antroid

0

ฉันแปลงคำตอบเป็น 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

            }
        }
    }
}

0

มันทำงานร่วมกับการปรับสถานะของกิจกรรมและวงจรชีวิตเหตุการณ์ที่ใช้ ยังมี 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
}

-1

ฉันทำสิ่งนี้ดังต่อไปนี้ แต่มัน 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);
                    }
                });

คำถามเกี่ยวข้องกับการค้นหาว่าแป้นพิมพ์กำลังแสดงอยู่หรือไม่
Gopal Singh Sirvi

-1

อาจจะใช้:

@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) {

}

สิ่งนี้จะใช้ได้กับแป้นพิมพ์ฮาร์ดแวร์เท่านั้นไม่ใช่ซอฟต์แวร์หนึ่ง
anthonymonori

-1

ผมเขียนตัวอย่าง

พื้นที่เก็บข้อมูลนี้สามารถช่วยในการตรวจสอบสถานะของแป้นพิมพ์โดยไม่มีการสันนิษฐานว่า "แป้นพิมพ์ควรมีมากกว่า X ส่วนหนึ่งของหน้าจอ"


-1

หากคุณสนับสนุน apis สำหรับ AndroidR ในแอปของคุณคุณสามารถใช้วิธีการด้านล่าง

In kotlin :
    var imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
        view.translationX = imeInsets.bottom 
    }

หมายเหตุ: นี่เป็นเพียงสำหรับ AndroidR และด้านล่างรุ่น Android ต้องปฏิบัติตามคำตอบอื่น ๆ หรือฉันจะอัปเดตสำหรับสิ่งนั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.