Làm cách nào để phát hiện xem bàn phím phần mềm có hiển thị trên Thiết bị Android hay không?


249

Có cách nào trong Android để phát hiện nếu bàn phím phần mềm (còn gọi là "mềm") hiển thị trên màn hình không?



1
những gì có thể là một giải pháp cho vấn đề này trong một số trường hợp nhất định (nếu bàn phím của bên thứ 3 được cài đặt) là kiểm tra các thông báo toàn cầu vì khi bàn phím mở, có một thông báo hệ thống có nội dung "thay đổi bàn phím" - có thể được thực hiện với NotificationListenerService
Giáo sư

2
gần 8 năm và vẫn chưa có giải pháp vững chắc, ồ nếu họ giới thiệu một cái, dù sao nó cũng sẽ dành cho API> 30 nên đừng
bận

Câu trả lời:


71

Không có cách nào trực tiếp - hãy xem http://groups.google.com/group/android-pl platform / browse_thread / thread / 1728f26f2334c060/5e4910f0d9eb898a nơi Dianne Hackborn từ nhóm Android đã trả lời. Tuy nhiên, bạn có thể phát hiện nó một cách gián tiếp bằng cách kiểm tra xem kích thước cửa sổ có thay đổi trong #onMeasure không. Xem Cách kiểm tra mức độ hiển thị của bàn phím phần mềm trong Android? .


276

Điều này làm việc cho tôi. Có lẽ đây luôn là cách tốt nhất cho tất cả các phiên bản .

Sẽ rất hiệu quả khi tạo một thuộc tính hiển thị bàn phím và quan sát các thay đổi này bị trì hoãn vì phương thức onGlobalLayout gọi nhiều lần. Ngoài ra nó là tốt để kiểm tra vòng quay thiết bị và windowSoftInputModekhông 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)
            }
        }
    }
});


1
Đặt cái này trong một lớp utils và chuyển vào hoạt động - bây giờ hữu ích trên toàn bộ ứng dụng.
Justin

2
contentViewtuyên bố ở đâu?
Code-Apprentice

1
@ Code-Apprentice Trong hoạt động / đoạn bạn đang tìm cách đáp ứng với những thay đổi của bàn phím mềm. ContentView là chế độ xem gốc của bố cục của hoạt động / đoạn này.
airowe

1
Làm việc cho tôi trên Android 6 và 7.
V.March

71

thử cái này:

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
Điều này không làm việc cho tôi. Bàn phím hiển thị kích hoạt nhánh ngay cả khi bàn phím không bao giờ được hiển thị hoặc được hiển thị và sau đó đóng lại.
Peter Ajtai

30
nó luôn luôn trở về đúng
shivang Trivingi

1
Vâng, nó luôn luôn trở lại đúng sự thật.
Léon Pelletier

Sai lầm. Điều này luôn trở lại đúng
Gaurav Arora

178
Thật là thảm hại khi khung Android bị thiếu, và tệ hơn, không nhất quán trong vấn đề này. Điều này nên là siêu đơn giản.
Vicky Chijwani

57

Tôi đã tạo một lớp đơn giản có thể được sử dụng cho việc này: https://github.com/ravindu1024/android-keyboardlistener . Chỉ cần sao chép nó vào dự án của bạn và sử dụng như sau:

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

Trường hợp trong mã exaclty tôi phải đặt cái này ở đâu? Tôi đưa điều này vào một hoạt động, tuy nhiên, nó không phát hiện bất kỳ sự xuất hiện hoặc biến mất bàn phím nào.
toom

Vâng, bạn có thể đặt nó bất cứ nơi nào trong hoạt động của bạn. Chỉ cần đặt nó trong phương thức onCreate () sau lệnh gọi setContentView () và bạn sẽ nhận được các cuộc gọi lại. Btw, bạn đang dùng thử thiết bị gì?
ravindu1024

@MaulikDodia Tôi đã kiểm tra và nó hoạt động tốt trong các mảnh. Thiết lập nó như thế này: KeyboardUtils.addPalToggleListener (getActivity (), this); và nó nên hoạt động. Bạn đang dùng thử thiết bị nào?
ravindu1024

Tôi đang thử trên thiết bị Moto-G3. @ Ravindu1024
Maulik Dodia

Cảm ơn về đoạn trích này, tôi có một câu hỏi là mã này có cần thiết để loại bỏ người nghe không?
Pratik Butani

28

Rất dễ

1. Đặt id trên chế độ xem gốc của bạn

rootViewchỉ là một khung nhìn trỏ đến khung nhìn gốc của tôi trong trường hợp này 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. Khởi tạo chế độ xem gốc trong Hoạt động của bạn:

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

3. Phát hiện nếu bàn phím được mở hoặc đóng bằng cách sử dụng 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
Này anh bạn, bạn có thể vui lòng cho tôi biết phép thuật 100 này đến từ đâu không? Tại sao không phải 101 hay 99? Cảm ơn
Karoly

@Karoly tôi nghĩ điều này có thể và 1. Không vấn đề. Chỉ điều này phải nhỏ hơn chiều dài thực của bàn phím
Vlad

@Karoly về cơ bản, anh ấy đang so sánh kích thước cửa sổ với kích thước chế độ xem gốc của hoạt động của bạn. Sự xuất hiện của bàn phím mềm không ảnh hưởng đến kích thước của cửa sổ chính. vì vậy bạn vẫn có thể hạ thấp giá trị 100.
mr5

Số ma thuật phụ thuộc vào cách bố trí topbar của bạn trong số những thứ khác. Vì vậy, nó là tương đối với ứng dụng của bạn. Tôi đã sử dụng 400 trong một của tôi.
Morten Holmgaard

hãy nhớ rằng onGlobalLayout được gọi là mọi khung hình, vì vậy hãy đảm bảo bạn không làm những việc nặng nề trong đó.
Akshay Gaonkar

8

Tôi đã sử dụng điều này như là một cơ sở: 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;
}
}

Sau đó viết phương pháp này:

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;

}

Sau đó, bạn có thể sử dụng điều này để kiểm tra tất cả các trường (EditText, AutoCompleteTextView, v.v.) có thể đã mở một phím chức năng:

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

Addmittely không phải là một giải pháp lý tưởng, nhưng nó hoàn thành công việc.


2
Những công việc này. Nếu bạn triển khai dưới dạng singelton, bạn có thể áp dụng cho tất cả các edittexts khi thay đổi tiêu điểm và có một trình nghe bàn phím toàn cầu
Rarw

@depperm getActivity () dành riêng cho Fragment, thay vào đó hãy thử YourActivityName.this. Xem thêm: stackoverflow.com/questions/14480129/ Kẻ
Christopher Hackl


6

Bạn có thể tham khảo câu trả lời này - https://stackoverflow.com/a/24105062/3629912

Nó làm việc cho tôi mọi lúc.

adb shell dumpsys window InputMethod | grep "mHasSurface"

Nó sẽ trả về true, nếu bàn phím phần mềm hiển thị.


10
Điều này chỉ hữu ích trong quá trình phát triển - không phải là giải pháp để sử dụng trong ứng dụng. (Người dùng sẽ không chạy adb.)
ToolmakerSteve

5

Vì vậy, sau một thời gian dài chơi xung quanh với AccessService, chèn cửa sổ, phát hiện chiều cao màn hình, v.v., tôi nghĩ rằng tôi đã tìm ra cách để làm điều này.

Tuyên bố từ chối trách nhiệm: nó sử dụng một phương thức ẩn trong Android, có nghĩa là nó có thể không nhất quán. Tuy nhiên, trong thử nghiệm của tôi, nó dường như hoạt động.

Phương thức này là InputMethodManager # getInputMethodWindowVisibleHeight () và nó đã tồn tại từ Lollipop (5.0).

Gọi mà trả về chiều cao, tính bằng pixel, của bàn phím hiện tại. Về lý thuyết, bàn phím không nên cao 0 pixel, vì vậy tôi đã thực hiện kiểm tra chiều cao đơn giản (trong Kotlin):

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
    //keyboard is shown
else {
    //keyboard is hidden
}

Tôi sử dụng API ẩn của Android để tránh phản xạ khi tôi gọi các phương thức ẩn (tôi làm điều đó rất nhiều cho các ứng dụng tôi phát triển, chủ yếu là các ứng dụng hacky / tuner), nhưng điều này cũng có thể xảy ra với sự phản chiếu:

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

Công dụng tuyệt vời của phản xạ
kaustubhpatange

4

Điều này ít phức tạp hơn cho các yêu cầu tôi cần. Hy vọng điều này có thể giúp:

Trên MainActivity:

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

Giá trị boolean nguyên thủy mặc định cho mPalStatus sẽ được khởi tạo thành false .

Sau đó kiểm tra giá trị như sau và thực hiện một hành động nếu cần:

 mSearchBox.requestFocus();
    if(!isKeyboardActive()){
        showKeyboard();
    }else{
        dismissKeyboard();
    }

4

Điều này sẽ hoạt động nếu bạn cần kiểm tra trạng thái bàn phím:

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

Trong đó UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP= 100 và dip () là một func anko chuyển đổi dpToPx:

fun dip(value: Int): Int {
    return (value * Resources.getSystem().displayMetrics.density).toInt()
}

3

Tôi đã làm điều này bằng cách thiết lập GlobalLayoutListener, như sau:

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

Điều này sẽ được gọi là RẤT thường xuyên
Denis Kniazhev

Trong trường hợp nào điều này sẽ khác với câu trả lời @BrownsooHan? Tôi đang tìm kiếm một cách mà một ứng dụng thu hút các ứng dụng khác để thoát khỏi bàn phím đang hiển thị.
Evan Langlois

Câu trả lời của anh ấy về cơ bản giống như của tôi, chỉ có tôi đã làm của tôi nhiều tháng trước anh ấy, và anh ấy có nhiều sự ủng hộ hơn.
PearsonArtPhoto

3

Hãy thử mã này, nó thực sự hoạt động nếu KeyboardShown được hiển thị thì hàm này trả về giá trị thực ....

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

IsPalShown tiếp tục gọi chính nó khi nó không được hiển thị.
Mandeep Singh

2

Trong trường hợp của tôi, tôi chỉ có một EditTextđể quản lý trong bố trí của mình vì vậy tôi đã đưa ra giải pháp này . Nó hoạt động tốt, về cơ bản nó là một tùy chỉnh EditTextnghe lấy nét và gửi một phát sóng cục bộ nếu tiêu điểm thay đổi hoặc nếu nhấn nút quay lại / thực hiện. Để làm việc, bạn cần đặt một hình nộm Viewtrong bố cục của mình android:focusable="true"android:focusableInTouchMode="true"bởi vì khi bạn gọi clearFocus()tiêu điểm sẽ được gán lại cho chế độ xem tập trung đầu tiên. Ví dụ về chế độ xem giả:

<View
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"/>

Thông tin bổ sung

Giải pháp phát hiện sự khác biệt trong thay đổi bố cục không hoạt động tốt vì nó phụ thuộc nhiều vào mật độ màn hình, vì 100px có thể có rất nhiều trong một thiết bị nhất định và không có gì ở một số thiết bị khác mà bạn có thể nhận được thông báo sai. Ngoài ra các nhà cung cấp khác nhau có bàn phím khác nhau.


1

Trong Android, bạn có thể phát hiện thông qua trình bao ADB. Tôi đã viết và sử dụng phương pháp này:

{
        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
Bạn có thể cải thiện câu trả lời này bằng một ví dụ cụ thể hơn, với tất cả hàng nhập khẩu và ví dụ hoạt động không?
dùng3

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

Trả lời của @iWantScala rất tuyệt nhưng không hiệu quả với tôi
rootView.getRootView().getHeight() luôn có cùng giá trị

một cách là xác định hai vars

private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;

thêm người nghe toàn cầu

rootView.getViewTreeObserver()
    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            currentRootViewHeight = rootView.getHeight();
            if (currentRootViewHeight > maxRootViewHeight) {
                maxRootViewHeight = currentRootViewHeight;
            }
        }
    });

sau đó kiểm tra

if (currentRootViewHeight >= maxRootViewHeight) {
    // Keyboard is hidden
} else {
    // Keyboard is shown
}

hoạt động tốt


1

Cuối cùng cũng có một cách trực tiếp bắt đầu từ Android R dựa trên 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

Tôi đã có một vấn đề tương tự. Tôi cần phải phản ứng với nút Enter trên màn hình (ẩn bàn phím). Trong trường hợp này, bạn có thể đăng ký OnEditorAction của chế độ xem văn bản mà bàn phím đã phản đối - nếu bạn có nhiều hộp có thể chỉnh sửa, sau đó đăng ký vào tất cả chúng.

Trong Hoạt động của bạn, bạn có toàn quyền kiểm soát bàn phím, do đó, bạn sẽ không phải đối mặt với vấn đề liệu bàn phím có được mở hay không, nếu bạn lắng nghe tất cả các sự kiện mở và đóng.


Không làm việc cho tôi. Tôi chỉ nhận được phím Enter trong OnEditorAction.
3c71

0

Có một phương pháp trực tiếp để tìm ra điều này. Và, nó không yêu cầu thay đổi bố cục.
Vì vậy, nó hoạt động trong chế độ toàn màn hình nhập vai, quá.
Nhưng, thật không may, nó không hoạt động trên tất cả các thiết bị. Vì vậy, bạn phải kiểm tra nó với (các) thiết bị của bạn.

Mẹo nhỏ là bạn cố gắng ẩn hoặc hiển thị bàn phím mềm và nắm bắt kết quả của lần thử đó.
Nếu nó hoạt động chính xác thì bàn phím không thực sự được hiển thị hoặc ẩn. Chúng tôi chỉ yêu cầu nhà nước.

Để luôn cập nhật, bạn chỉ cần lặp lại thao tác này, ví dụ cứ sau 200 mili giây, sử dụng Trình xử lý.

Việc thực hiện dưới đây chỉ là một kiểm tra duy nhất.
Nếu bạn thực hiện nhiều kiểm tra, thì bạn nên kích hoạt tất cả các bài kiểm tra (_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;
        }
    }
};

Làm thế nào để gọi nó và ở đâu?
Mahdi Astanei

0

Đây là một cách giải quyết để biết nếu phím chức năng có thể nhìn thấy.

  1. Kiểm tra các dịch vụ đang chạy trên hệ thống bằng ActivityManager.getRastyService (max_count_of_service);
  2. Từ các phiên bản ActivityManager.RastyServiceInfo được trả về, hãy kiểm tra clientCount giá trị cho dịch vụ bàn phím mềm.
  3. ClientCount đã nói ở trên sẽ được tăng lên mỗi lần, bàn phím mềm được hiển thị. Ví dụ: nếu clientCount ban đầu là 1, nó sẽ là 2 khi bàn phím được hiển thị.
  4. Khi sa thải bàn phím, clientCount bị giảm. Trong trường hợp này, nó đặt lại thành 1.

Một số bàn phím phổ biến có các từ khóa nhất định trong classNames của chúng:

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = Bàn phím dịch vụ
  4. Fleksy = bàn phím
  5. Thích ứng = IME (KPTAdaptxtIME)
  6. Thông minh = Bàn phím (SmartPal)

Từ ActivityManager.RastyServiceInfo, hãy kiểm tra các mẫu trên trong ClassNames. Ngoài ra, ActivityManager.RastyServiceInfo ' clientPackage = android, chỉ ra rằng bàn phím bị ràng buộc với hệ thống.

Các thông tin được đề cập ở trên có thể được kết hợp theo một cách nghiêm ngặt để tìm hiểu xem có thể nhìn thấy bàn phím mềm hay không.


0

Như bạn có thể biết bàn phím Phần mềm Android sẽ chỉ hiển thị khi có thể xảy ra sự cố gõ. Nói cách khác, Bàn phím chỉ hiển thị khi EditText được tập trung. điều đó có nghĩa là bạn có thể nhận được thời tiết Bàn phím có thể nhìn thấy hay không bằng cách sử dụng OnF FocusChangeListener .

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

Bây giờ bạn có thể sử dụng isKeyBoardVisible biến ở bất cứ đâu trong lớp để theo dõi thời tiết bàn phím có mở hay không. Nó làm việc tốt cho tôi.

Lưu ý: Quá trình này không hoạt động khi Bàn phím được mở bằng lập trình bằng InputMethodManager vì điều đó không gọi OnF FocusChangeListener.


không thực sự là một hack, đã không làm việc trong một trường hợp phân mảnh lồng nhau. Không thể nói về các hoạt động vì tôi chưa thử điều này.
antroid

0

Tôi đã chuyển đổi câu trả lời cho kotlin, hy vọng điều này sẽ giúp cho người dùng 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

Nó hoạt động với cờ điều chỉnh Hoạt động và các sự kiện vòng đời được sử dụng. Ngoài ra với 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)
    }
}

Phương pháp hữu ích để giữ chế độ xem luôn ở phía trên bàn phím

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

Trường hợp getFullViewBound

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

Trường hợp 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
}

Nơi cập nhậtMargin

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

Tôi đã làm điều này như sau, nhưng chỉ có liên quan nếu mục tiêu của bạn là đóng / mở keyboad.

đóng ví dụ: (kiểm tra xem bàn phím đã đóng chưa, nếu không - đóng)

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

Câu hỏi có liên quan để tìm ra bàn phím có hiển thị hay không
Gopal Singh Sirvi

-1

a có thể đang sử dụng:

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

}

Điều này sẽ chỉ hoạt động cho bàn phím phần cứng, không phải phần mềm một
anthonymousonori

-1

Tôi đã viết mẫu .

Kho lưu trữ này có thể giúp phát hiện trạng thái bàn phím mà không giả định rằng "bàn phím phải nhiều hơn một phần X của màn hình"


-1

Nếu bạn hỗ trợ apis cho AndroidR trong ứng dụng của mình thì bạn có thể sử dụng phương pháp dưới đây.

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

Lưu ý: Điều này chỉ có sẵn cho AndroidR và bên dưới phiên bản Android cần phải làm theo một số câu trả lời khác hoặc tôi sẽ cập nhật nó cho điều đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.