Проверьте панель навигации

Я пытаюсь проверить, присутствует ли панель загрузки Android под нагрузкой, чтобы я мог соответствующим образом настроить макет, у кого-нибудь есть какие-либо предложения?

Это панель навигации, которую я пытаюсь обнаружить:введите описание изображения здесь

PS Все, что я нашел до сих пор, это "плохие" способы попытаться убрать планку, чего я не хочу делать.

12 ответов

Решение

Это заняло у меня некоторое время, но я нашел более надежный способ, чем полагаться на hasPermanentMenuKey(), который не работает для более новых телефонов, таких как HTC One, у которых нет клавиши меню, но есть клавиши home и back, поэтому они не нужны (или покажи) мягкая панель навигации. Чтобы обойти это, попробуйте следующий код, который также проверяет наличие кнопки возврата:

boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);

if(!hasMenuKey && !hasBackKey) {
    // Do whatever you need to do, this device has a navigation bar
}

Нет надежного способа проверить наличие панели навигации. С помощью KeyCharacterMap.deviceHasKey Вы можете проверить наличие определенных физических клавиш на устройстве, но эта информация не очень полезна, так как устройства с физическими клавишами все еще могут иметь панель навигации. Такие устройства, как OnePlus One или любое другое устройство, на котором запущен пользовательский диск, имеют в настройках параметр, который отключает физические клавиши и добавляет панель навигации. Нет возможности проверить, включена ли эта опция, и deviceHasKey все еще возвращает true для ключей, которые отключены этой опцией.

Это самое близкое, что вы можете получить:

boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);

if (hasBackKey && hasHomeKey) {
    // no navigation bar, unless it is enabled in the settings
} else {
    // 99% sure there's a navigation bar
}

Если кнопки "Назад" и "Домой" физически отсутствуют на устройстве, у него должна быть панель навигации, потому что в противном случае пользователь вообще не смог бы перемещаться. Тем не менее, вы никогда не можете быть на 100% уверены в этом, так как производители могут реализовать deviceHasKey неправильно.

Другое решение (часть моего класса UtilsUISystem)

    public static boolean hasNavBar (Resources resources)
    {
        //Emulator
        if (Build.FINGERPRINT.startsWith("generic"))
            return true;

        int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
        return id > 0 && resources.getBoolean(id);
    }

Вот быстрый ответ, который объединяет решения Pauland и Philask. Боюсь, мне не хватает доступных устройств, чтобы проверить, работает ли оно везде, хотя. Мне было бы интересно услышать результаты других.

boolean hasNavBar(Context context) {
    Resources resources = context.getResources();
    int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
    if (id > 0) {
        return resources.getBoolean(id);
    } else {    // Check for keys
        boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
        boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
        return !hasMenuKey && !hasBackKey;
    }
}

Я сделал так, это работает на всех устройствах, которые я тестировал, и даже на эмуляторах:

public static boolean hasNavigationBar(Activity activity) {
    Rect rectangle = new Rect();
    DisplayMetrics displayMetrics = new DisplayMetrics();
    activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle);
    activity.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
    return displayMetrics.heightPixels != (rectangle.top + rectangle.height());
}

Вы можете добавить этот код в метод onCreate() вашей деятельности:

 View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
        (new View.OnSystemUiVisibilityChangeListener() {
            @Override
            public void onSystemUiVisibilityChange(int visibility) {
                if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
                    // TODO: The navigation bar is visible. Make any desired
                    // adjustments to your UI, such as showing the action bar or
                    // other navigational controls.
                } else {
                    // TODO: The navigation bar is NOT visible. Make any desired
                    // adjustments to your UI, such as hiding the action bar or
                    // other navigational controls.
                }
            }
        });

Этот метод работал для меня

    int id = getResources().getIdentifier("config_showNavigationBar","bool","android");
        boolean result = id > 0 && getResources().getBoolean(id);
//
        if(result) {

            // Do whatever you need to do, this device has a soft Navigation Bar
        }

У меня это сработало и проверено на многих устройствах.

Что-то, что, вероятно, должно работать лучше, это измерить экран.

Начиная с API 17 есть getWindowManager().getDefaultDisplay().getRealSize(), который можно сравнить с размером, возвращаемым getWindowManager().getDefaultDisplay().getSize(),

Если вы получаете разные результаты, я думаю, что можно с уверенностью сказать, что есть навигационная панель, а если вы получаете те же результаты, ее нет. Следует обратить внимание на целевой SDK и поддерживаемые экраны, которые могут привести к getSize() масштабироваться, если Android считает, что ваше приложение не будет работать на текущем устройстве без масштабирования.

Ниже API 17 вы можете измерить экран с помощью getWindowManager().getDefaultDisplay().getMetrics() как в альбомном, так и в портретном режиме, и, опять же, разные результаты, вероятно, означают наличие навигационной панели.

Однако, если вы получите те же результаты, вы на самом деле не знаете, так как телефоны могут удерживать навигационную панель на более коротком краю, даже когда в альбомной ориентации. Образованным предположением будет то, что если ширина или высота на 4-8% меньше стандартных размеров, таких как 1280x800, 1280x720, 1024x600, в то время как другое измерение равно, тогда снова, вероятно, есть навигационная панель. Не ставьте на это, хотя. Есть слишком много разрешений, которые слишком мало отличаются друг от друга, чтобы это работало хорошо.

boolean hasNavBar(Context context) {
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        // navigation bar was introduced in Android 4.0 (API level 14)
        Resources resources = context.getResources();
        int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
        if (id > 0) {
            return resources.getBoolean(id);
        } else {    // Check for keys
            boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
            boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
            return !hasMenuKey && !hasBackKey;
        }
    } else {
        return false;
    }
}

В Android 10 (уровень API 29) вы также можете проверить вставку в нижнем окне:

      @RequiresApi(api = Build.VERSION_CODES.Q)
private boolean hasNavigationBar() {
    final WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
    if (windowInsets == null) {
            throw new RuntimeException("Window is not attached");
    }
    return windowInsets.getTappableElementInsets().bottom > 0;
}

Обратите внимание, что окно должно быть прикреплено для getRootWindowInsets() чтобы вернуть ненулевое значение, поэтому вы, вероятно, захотите вызвать это в onAttachedToWindow.

Это решение также используется приложением запуска LineageOS Trebuchet (исходный код ), как я узнал о нем.

Я вижу ответы выше, я хочу указать, что "не существует" можно рассматривать как высоту 0; так может быть так:

public static int getScreenH(Context context) {
    DisplayMetrics dm = new DisplayMetrics();
    dm = context.getResources().getDisplayMetrics();
    int h = dm.heightPixels;
    return h;
}

public static int getDpi(Context context) {

    DisplayMetrics displayMetrics1 = context.getResources().getDisplayMetrics();
    int height1 = displayMetrics1.heightPixels;

    int dpi = 0;
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    DisplayMetrics displayMetrics = new DisplayMetrics();

    @SuppressWarnings("rawtypes")
    Class c;
    try {
        c = Class.forName("android.view.Display");
        @SuppressWarnings("unchecked")
        Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
        method.invoke(display, displayMetrics);
        dpi = displayMetrics.heightPixels;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return dpi;
}

public static int getBottomStatusHeight(Context context) {
    int totalHeight = getDpi(context);

    int contentHeight = getScreenH(context);

    return totalHeight - contentHeight;
}

`` `

Решение: только устройства без постоянных аппаратных клавиш имеют панель навигации, поэтому вы можете проверить версию API и использовать hasPermanentMenuKey() для поиска аппаратных ключей

 boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();