Обнаружение ориентации навигационной панели Android

Есть ли способ узнать, где эта панель навигации будет отображаться для пейзажа:

  • на Nexus7 находится внизу
  • на узле 5 находится справа.

Спасибо

enter image description here

Ответы

Ответ 1

Используя свойства вид декора в сочетании с текущим DisplayMetrics, вы можете найти с какой стороны расположена панель навигации.

// retrieve the position of the DecorView
Rect visibleFrame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleFrame);

DisplayMetrics dm = getResources().getDisplayMetrics();
// check if the DecorView takes the whole screen vertically or horizontally
boolean isRightOfContent = dm.heightPixels == visibleFrame.bottom;
boolean isBelowContent   = dm.widthPixels  == visibleFrame.right;

Ответ 2

Мое решение

public static boolean hasNavBar (Resources resources)
{
    int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
    if (id > 0)
        return resources.getBoolean(id);
    else
        return false;
}

public static int getNavigationBarHeight (Resources resources)
{
    if (!Utils.hasNavBar(resources))
        return 0;

    int orientation = resources.getConfiguration().orientation;

    //Only phone between 0-599 has navigationbar can move
    boolean isSmartphone = resources.getConfiguration().smallestScreenWidthDp < 600;
    if (isSmartphone && Configuration.ORIENTATION_LANDSCAPE == orientation)
        return 0;

    int id = resources
        .getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT ? "navigation_bar_height" : "navigation_bar_height_landscape", "dimen", "android");
    if (id > 0)
        return resources.getDimensionPixelSize(id);

    return 0;
}

public static int getNavigationBarWidth (Resources resources)
{
    if (!Utils.hasNavBar(resources))
        return 0;

    int orientation = resources.getConfiguration().orientation;

    //Only phone between 0-599 has navigationbar can move
    boolean isSmartphone = resources.getConfiguration().smallestScreenWidthDp < 600;

    if (orientation == Configuration.ORIENTATION_LANDSCAPE && isSmartphone)
    {
        int id = resources.getIdentifier("navigation_bar_width", "dimen", "android");
        if (id > 0)
            return resources.getDimensionPixelSize(id);
    }

    return 0;
}

Решение, основанное на https://android.googlesource.com/platform/frameworks/base/+/9f65c4c34abb07bdda54649ed510af26f16e9c1b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

Ответ 3

Основанный частично на ответе Павла (в свою очередь, на основе реализации PhoneWindowManager), вот что я сейчас использую:

  public static boolean isSystemBarOnBottom(Context ctxt) {
    Resources res=ctxt.getResources();
    Configuration cfg=res.getConfiguration();
    DisplayMetrics dm=res.getDisplayMetrics();
    boolean canMove=(dm.widthPixels != dm.heightPixels &&
        cfg.smallestScreenWidthDp < 600);

    return(!canMove || dm.widthPixels < dm.heightPixels);
  }

Это работает на Nexus 7 2012 и Nexus 4, каждый из которых работает под управлением Android 5.1.

На устройствах с постоянной клавишей MENU нет системной панели. В зависимости от вашего варианта использования вам может потребоваться проверить этот случай:

ViewConfiguration.get(ctxt).hasPermanentMenuKey()

(где ctxt - некоторая Context)

Лично я использую это, чтобы попытаться иметь скользящую панель на противоположной оси от системной панели, так как прорезь на боковой стороне с системной панелью немного сложно запускать. Я бы не использовал это или какой-либо другой алгоритм (например, те, которые зависят от getDecorView()), для чего-то критического.

Ответ 4

Рабочее решение для меня:

public static boolean hasNavBar(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Point realPoint = new Point();
        Display display = wm.getDefaultDisplay();
        display.getRealSize(realPoint);
        DisplayMetrics metrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);
        return metrics.heightPixels + metrics.widthPixels != realPoint.y + realPoint.x;
    }

    public static boolean isSystemBarOnBottom(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Point realPoint = new Point();
        Display display = wm.getDefaultDisplay();
        display.getRealSize(realPoint);
        DisplayMetrics metrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);
        Configuration cfg = context.getResources().getConfiguration();
        boolean canMove = (metrics.widthPixels != metrics.heightPixels &&
                cfg.smallestScreenWidthDp < 600);

        return (!canMove || metrics.widthPixels < metrics.heightPixels);
    }

Ответ 5

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

boolean navBarOnTheBottom(){
        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        int viewHeight = displaymetrics.heightPixels;
        if (bkg.getHeight() == viewHeight)
        {
            Log.d(TAG, "nav bar on the side");
            return false;
        }
        else{
            Log.d(TAG, "nav bar on the bottom");
            return true;
        }
    }

bkg это основной linearLayout, который содержит все мои приложения. Убедитесь, что bkg.getHeight() не дает вам 0, с некоторыми макетами, которые он мне дал 0

EDIT: Получите высоту макета, как это, если приведенное выше дает вам 0

@Override
    public void onWindowFocusChanged (boolean hasFocus) {
        // the height will be set at this point
        bkgHeight = bkg.getHeight();
    }