プログラムでAndroidナビゲーションバーの高さと幅を取得するにはどうすればよいですか?


122

画面下部の黒いナビゲーションバーは、Androidでは簡単に削除できません。ハードウェアボタンの代わりとして、3.0以降、Androidの一部となっています。ここに写真があります:

システムバー

このUI要素の幅と高さのサイズをピクセル単位で取得するにはどうすればよいですか?


この問題の最善の解決策をここに追加します。表示メトリックと実際のメトリックを比較することで、デバイスにナビゲーションバーが存在するかどうかを識別できます。私の答えを見て、私はAndroidデバイス全体の実際のナビゲーションバーサイズを見つけるために完全なコードを追加しました。
Sino Raj 2016

回答:


178

以下のコードを試してください:

Resources resources = context.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
    return resources.getDimensionPixelSize(resourceId);
}
return 0;

7
ありがとう。+1。このアプローチがどれほど安定しているか知っていますか?リソース識別子はプラットフォームのバージョン間で変更される可能性がありますか?
ベンピアソン

59
このコードは、ナビゲーションバーのないデバイスでは0を返さないことに注意してください。Samsung S2およびS3でテスト済み。私は72と96だ
イージス

4
@Egidijus私の答えを見てください、それは物理的なナビゲーションを持つデバイスに対して0を返しますstackoverflow.com/a/29938139/1683141
Mdlc

1
下部にナビゲーションバーはありませんが、galaxy s6 edgeも0を返しません。192を返します
agamov 2015

5
このコードは、ナビゲーションバーのデフォルトサイズを示します(navigation_bar_height_landscape横長モードでのナビゲーションバーの高さ、およびnavigation_bar_width垂直ナビゲーションバーの幅も試してください)。物理的なメニューボタンの存在をテストするなどして、ナビゲーションバーが実際に表示されているかどうか、どこに表示されているかを個別に調べる必要があります。たぶん、android.googlesource.com
platform / frameworks / base / + /…の

103

アプリで使用できる画面サイズと実際の画面サイズを比較して、ナビゲーションバーのサイズを取得します。アプリで使用できる画面サイズが実際の画面サイズよりも小さい場合、ナビゲーションバーが表示されると思います。次に、ナビゲーションバーのサイズを計算します。このメソッドはAPI 14以降で動作します。

public static Point getNavigationBarSize(Context context) {
    Point appUsableSize = getAppUsableScreenSize(context);
    Point realScreenSize = getRealScreenSize(context);

    // navigation bar on the side
    if (appUsableSize.x < realScreenSize.x) {
        return new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y);
    }

    // navigation bar at the bottom
    if (appUsableSize.y < realScreenSize.y) {
        return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y);
    }

    // navigation bar is not present
    return new Point();
}

public static Point getAppUsableScreenSize(Context context) {
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    return size;
}

public static Point getRealScreenSize(Context context) {
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();
    Point size = new Point();

    if (Build.VERSION.SDK_INT >= 17) {
        display.getRealSize(size);
    } else if (Build.VERSION.SDK_INT >= 14) {
        try {
            size.x = (Integer) Display.class.getMethod("getRawWidth").invoke(display);
            size.y = (Integer) Display.class.getMethod("getRawHeight").invoke(display);
        } catch (IllegalAccessException e) {} catch (InvocationTargetException e) {} catch (NoSuchMethodException e) {}
    }

    return size;
}

更新

ディスプレイカットアウトを考慮するソリューションについては、ジョンの回答を確認してください。


2
これは、私がテストしているデバイスのすべての相違全体で機能する唯一のソリューションです。私の必要条件は、navBarが方向を考慮して画面の下部にあるかどうかを判断することです。画面の下部にあるナビゲーションバーのサイズを返すように、回答のコードを少し調整しました。0は、存在しないことを示します。私のテストでは、Nexus5 = portrait:144、Landscape:0 | Nexus7 =縦:96、横:96 | Samsung Note II =ポートレート:0、ランドスケープ:0 | Samsung S10 = portrait:0、Landscape:0
se22as

2
Danyloのソリューションが一部のモデルでのみ機能することも確認できます。Egidijusによるこのソリューションは、より効果的なソリューションであり、これまでにテストされたすべてのモデルで機能しています。これありがとう。
Bisclavret 2015

2
ステータスバーはアプリの使用可能な画面の一部です。
Egis

1
これは機能しますが、既存のバーが非表示になっているかどうかは考慮されません。これを確認する方法はありますか?
X-HuMan 2017年

1
ナビゲーションバーの代わりにナビゲーションジェスチャーがオンになっていると、Android Pでは機能しません。この状況を解決する方法を教えてください
Nik

36

NavigationBarの高さはデバイスによって異なりますが、向きによっても異なります。まず、デバイスにナビゲーションバーがあるかどうかを確認してから、デバイスがタブレットかタブレット(電話)かを確認し、最後に正しい高さを得るためにデバイスの向きを確認する必要があります。

public int getNavBarHeight(Context c) {
         int result = 0;
         boolean hasMenuKey = ViewConfiguration.get(c).hasPermanentMenuKey();
         boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);

         if(!hasMenuKey && !hasBackKey) {
             //The device has a navigation bar
             Resources resources = c.getResources();

             int orientation = resources.getConfiguration().orientation;
             int resourceId;
             if (isTablet(c)){
                 resourceId = resources.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT ? "navigation_bar_height" : "navigation_bar_height_landscape", "dimen", "android");
             }  else {
                 resourceId = resources.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT ? "navigation_bar_height" : "navigation_bar_width", "dimen", "android");     
             }

             if (resourceId > 0) {
                 return resources.getDimensionPixelSize(resourceId);
             }
         }
         return result;
} 


private boolean isTablet(Context c) {
    return (c.getResources().getConfiguration().screenLayout
            & Configuration.SCREENLAYOUT_SIZE_MASK)
            >= Configuration.SCREENLAYOUT_SIZE_LARGE;
}

これは私には機能しません。Nexus5はhasMenuKeyとhasBackKeyに対してtrueを返すため、navBarはないと見なされます。(Nexus7は、hasMenuKeyおよびhasBackKeyに対して正しくfalseを返します)
se22as

5
このコードをNexus 5でテストしましたが、どちらもfalseを返します。エミュレータやROMを使用していませんか?
Mdlc 2015年

はい、私は申し訳ありません私は以前、私の声明で明らかにしている必要があり、エミュレータを使用していた
se22as

これは!hasMenuKeyにするべきではありません|| !hasMenuKey &&!hasBackKeyの代わりに!hasBackKey?確認してください
yongsunCN 2016年

2
残念ながら、Sony Xperia Z3では動作しません hasBackKey = false!が、本当のはずです。以下は、代わりに働いていた: boolean navBarExists = getResources().getBoolean(getResources().getIdentifier("config_showNavigationBar", "bool", "android"));
Hamzeh Soboh

27

実際、タブレット(少なくともNexus 7)のナビゲーションバーは縦と横でサイズが異なるため、この関数は次のようになります。

private int getNavigationBarHeight(Context context, int orientation) {
    Resources resources = context.getResources();

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

6
コンテキストから方向を取得するには、次を使用しますcontext.getResources().getConfiguration().orientation
Hugo Gresse 2015

この問題の最善の解決策をここに追加します。表示メトリックと実際のメトリックを比較することで、デバイスにナビゲーションバーが存在するかどうかを識別できます。私の答えを見て、私はAndroidデバイス全体の実際のナビゲーションバーサイズを見つけるために完全なコードを追加しました。
Sino Raj

17

カットアウトの高さも取得できるので、こちらの方がいいと思います。

ルートビューを取得し、setOnApplyWindowInsetsListenerを追加(または、onApplyWindowInsetsをオーバーライドできます)し、そこからinsets.getSystemWindowInsetsを取得します。

カメラアクティビティで、systemWindowInsetBottomに等しいパディングを下部レイアウトに追加します。そして最後に、それはカットアウトの問題を修正します。

カメラアクティビティインセット

appcompatでそれはこのようです

ViewCompat.setOnApplyWindowInsetsListener(mCameraSourcePreview, (v, insets) -> {
    takePictureLayout.setPadding(0,0,0,insets.getSystemWindowInsetBottom());
    return insets.consumeSystemWindowInsets();
});

appcompatなしでは、これ:

mCameraSourcePreview.setOnApplyWindowInsetsListener((v, insets) -> { ... })

setOnApplyWindowInsetsListener代わりに使用できますか?もしそうなら、どうですか?そして、なぜあなたはLOLLIPOPと残りを区別したのですか?
Android開発者

はい、可能です。答えを直します。差別化も必要ありません
ジョン

1
これが最良の答えです。文字通りあなたを愛しています。
Himanshu Rawat

1
これが本当の答えです。
nyconing

1
onCreate()から呼び出すと、リスナーは実行されません。何か不足していますか?
howettl

12

これがお役に立てば幸いです

public int getStatusBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

public int getNavigationBarHeight()
{
    boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
    int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0 && !hasMenuKey)
    {
        return getResources().getDimensionPixelSize(resourceId);
    }
    return 0;
}

5

これは、ナビゲーションバーをかわすためにビューにpaddingRightおよびpaddingBottomを追加するための私のコードです。ここでいくつかの回答を組み合わせて、isInMultiWindowModeとともに横向きの特別な句を作成しました。重要なのは、navigation_bar_heightを読み取ることですが、config_showNavigationBarも確認してくださいをして、実際に高さを使用する必要があることを確認してください。

以前の解決策はどれも私にとってうまくいきませんでした。Android 7.0以降では、マルチウィンドウモードを考慮する必要があります。この休憩比較実装display.realSizeをしてdisplay.size以来realSizeはあなたに画面全体の寸法(両方の分割ウィンドウ)を与えると、サイズが唯一のあなたのアプリケーションウィンドウの大きさを与えます。この差にパディングを設定すると、ビュー全体がパディングされたままになります。

/** Adds padding to a view to dodge the navigation bar.

    Unfortunately something like this needs to be done since there
    are no attr or dimens value available to get the navigation bar
    height (as of December 2016). */
public static void addNavigationBarPadding(Activity context, View v) {
    Resources resources = context.getResources();
    if (hasNavigationBar(resources)) {
        int orientation = resources.getConfiguration().orientation;
        int size = getNavigationBarSize(resources);
        switch (orientation) {
        case Configuration.ORIENTATION_LANDSCAPE:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
                context.isInMultiWindowMode()) { break; }
            v.setPadding(v.getPaddingLeft(), v.getPaddingTop(),
                         v.getPaddingRight() + size, v.getPaddingBottom());
            break;
        case Configuration.ORIENTATION_PORTRAIT:
            v.setPadding(v.getPaddingLeft(), v.getPaddingTop(),
                         v.getPaddingRight(), v.getPaddingBottom() + size);
            break;
        }
    }
}

private static int getNavigationBarSize(Resources resources) {
    int resourceId = resources.getIdentifier("navigation_bar_height",
                                             "dimen", "android");
    return resourceId > 0 ? resources.getDimensionPixelSize(resourceId) : 0;
}

private static boolean hasNavigationBar(Resources resources) {
    int hasNavBarId = resources.getIdentifier("config_showNavigationBar",
                                              "bool", "android");
    return hasNavBarId > 0 && resources.getBoolean(hasNavBarId);
}

1

下部のナビゲーションバーの高さは48 dp(縦モードと横モードの両方)で、バーを垂直に配置すると42 dpになります。


4
高さは通常48 dpです。しかし、一部の製造元はそれを変更でき、一部のカスタムROMはそれを変更できます。正確なサイズを得るには、Danyloの回答(stackoverflow.com/a/26118045/1377145)を使用することをお
勧めし

それはさらに良いです。ありがとう。
Aritra Roy、2015

縦置き?ランドスケープモードのときのように?
sudocoder、2015年

1

Egidijusによって提案され、Build.VERSION.SDK_INT> = 17で完全に機能するソリューション

しかし、デバイスでBuild.VERSION.SDK_INT <17を使用して次のステートメントを実行すると、「NoSuchMethodException」が発生しました。

Display.class.getMethod("getRawHeight").invoke(display);

このような場合のために、メソッドgetRealScreenSize()を変更しました。

else if(Build.VERSION.SDK_INT >= 14) 
{
    View decorView = getActivity().getWindow().getDecorView();
    size.x = decorView.getWidth();
    size.y = decorView.getHeight();
}

1

すべてのデバイス(Nexus 5、Samsung Galaxy Nexus 6 edge +、Samsung S10、Samsung Note IIなどを含む)でこの問題を解決しました。これは、デバイスに依存する問題を処理するのに役立つと思います。

ここでは、2種類のコードを追加しています。

Javaコード(ネイティブAndroid用):

import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.ViewConfiguration;
import android.view.WindowManager;

public class DeviceSpec {

    private int resourceID = -1;
    private Display display = null;
    private DisplayMetrics displayMetrics = null;
    private DisplayMetrics realDisplayMetrics = null;
    private Resources resources = null;
    private WindowManager windowManager = null;

    public double GetNavigationBarHeight(Context context) {
        try {
            windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            display = windowManager.getDefaultDisplay();
            displayMetrics = new DisplayMetrics();
            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
                realDisplayMetrics = new DisplayMetrics();
                display.getMetrics(displayMetrics);
                display.getRealMetrics(realDisplayMetrics);
                if(displayMetrics.heightPixels != realDisplayMetrics.heightPixels) {
                    resources = context.getResources();
                    return GetNavigationBarSize(context);
                }
            }
            else {
                resources = context.getResources();
                resourceID = resources.getIdentifier("config_showNavigationBar", "bool", "android");
                if (resourceID > 0 && resources.getBoolean(resourceID))
                    return GetNavigationBarSize(context);
            }
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

    private double GetNavigationBarSize(Context context) {
        resourceID = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceID > 0 && ViewConfiguration.get(context).hasPermanentMenuKey())
           return (resources.getDimensionPixelSize(resourceID) / displayMetrics.density);
        return 0;
    }
}

およびC#コード(Xamarinフォーム/ Android用)

int resourceId = -1;
        IWindowManager windowManager = null;
        Display defaultDisplay = null;
        DisplayMetrics displayMatrics = null;
        DisplayMetrics realMatrics = null;
        Resources resources = null;

        public double NavigationBarHeight
        {
            get
            {
                try
                {
                    windowManager = Forms.Context.GetSystemService(Context.WindowService).JavaCast<IWindowManager>();
                    defaultDisplay = windowManager.DefaultDisplay;
                    displayMatrics = new DisplayMetrics();
                    if (Build.VERSION.SdkInt >= BuildVersionCodes.JellyBeanMr2)
                    {
                        realMatrics = new DisplayMetrics();
                        defaultDisplay.GetMetrics(displayMatrics);
                        defaultDisplay.GetRealMetrics(realMatrics);
                        if (displayMatrics.HeightPixels != realMatrics.HeightPixels)
                        {
                            resources = Forms.Context.Resources;
                            return GetHeightOfNivigationBar();
                        }
                    }
                    else {
                        resources = Forms.Context.Resources;
                        resourceId = resources.GetIdentifier("config_showNavigationBar", "bool", "android");
                        if (resourceId > 0 && resources.GetBoolean(resourceId))
                            return GetHeightOfNivigationBar();
                    }
                }
                catch (Exception e) { }
                return 0;
            }
        }

        private double GetHeightOfNivigationBar()
        {
            resourceId = resources.GetIdentifier("navigation_bar_height", "dimen", "android");
            if (!ViewConfiguration.Get(Forms.Context).HasPermanentMenuKey && resourceId > 0)
            {
                return resources.GetDimensionPixelSize(resourceId) / displayMatrics.Density;
            }
            return 0;
        }

Display.getRealMetrics()APIレベル17が必要
Weizhi

if(Build.VERSION.SdkInt> = BuildVersionCodes.JellyBeanMr2)はすでにチェックされています。
2016年

コードを修正する必要があります。私のLGネクサス5Xが原因に0.0を取得します:[1]はscreenOrientation、デフォルトである、 hasPermanentMenuKeyあるfalseのみ回転していない場合。[2] screenOrientationが横長の場合は、displayMetrics.heightPixels != realDisplayMetrics.heightPixels)他の部分に分類されます。[3]がの場合screenOrientationhasPermanentMenuKeyですfalse
果物

機能しますが、4.xではif(hasPermanentMenuKey)が無駄です。コメントしてください
djdance

条件はif(Build.VERSION.SDK_INT> = Build.VERSION_CODES.JELLY_BEAN_MR1)でなければなりません。public void getRealMetrics(DisplayMetrics outMetrics)を実行するには、API 17が必要です。docs:developer.android.com/reference/kotlin/android/util/…を
ポートフォリオ

1

@egisと他の回答を組み合わせる-これは、Pixel EMU、Samsung S6、Sony Z3、Nexus 4でテストされたさまざまなデバイスでうまく機能します。このコードは、ディスプレイの寸法を使用してナビゲーションバーの可用性をテストし、実際のシステムナビゲーションバーのサイズ(存在する場合)。

/**
 * Calculates the system navigation bar size.
 */

public final class NavigationBarSize {

	private final int systemNavBarHeight;
	@NonNull
	private final Point navBarSize;

	public NavigationBarSize(@NonNull Context context) {
		Resources resources = context.getResources();
		int displayOrientation = resources.getConfiguration().orientation;
		final String name;
		switch (displayOrientation) {
			case Configuration.ORIENTATION_PORTRAIT:
				name = "navigation_bar_height";
				break;
			default:
				name = "navigation_bar_height_landscape";
		}
		int id = resources.getIdentifier(name, "dimen", "android");
		systemNavBarHeight = id > 0 ? resources.getDimensionPixelSize(id) : 0;
		navBarSize = getNavigationBarSize(context);
	}

	public void adjustBottomPadding(@NonNull View view, @DimenRes int defaultHeight) {
		int height = 0;
		if (navBarSize.y > 0) {
			// the device has a nav bar, get the correct size from the system
			height = systemNavBarHeight;
		}
		if (height == 0) {
			// fallback to default
			height = view.getContext().getResources().getDimensionPixelSize(defaultHeight);
		}
		view.setPadding(0, 0, 0, height);
	}

	@NonNull
	private static Point getNavigationBarSize(@NonNull Context context) {
		Point appUsableSize = new Point();
		Point realScreenSize = new Point();
		WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		if (windowManager != null) {
			Display display = windowManager.getDefaultDisplay();
			display.getSize(appUsableSize);
			display.getRealSize(realScreenSize);
		}
		return new Point(realScreenSize.x - appUsableSize.x, realScreenSize.y - appUsableSize.y);
	}

}


プログラムでTextViewの高さを画面の使用可能な高さの下部に設定する場合、このクラスをどのように使用しますか?
Naveed Abbas

1

ナビゲーションバーとステータスバーの高さを取得する方法。このコードは、一部のHuaweiデバイスとSamsungデバイスで動作します。上記のEgisのソリューションは優れていますが、一部のデバイスでは依然として正しくありません。だから、私はそれを改善しました。

ステータスバーの高さを取得するコードです

private fun getStatusBarHeight(resources: Resources): Int {
        var result = 0
        val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
        if (resourceId > 0) {
            result = resources.getDimensionPixelSize(resourceId)
        }
        return result
    }

このメソッドは、ナビゲーションバーが非表示の場合でも、常にナビゲーションバーの高さを返します。

private fun getNavigationBarHeight(resources: Resources): Int {
    val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
    return if (resourceId > 0) {
        resources.getDimensionPixelSize(resourceId)
    } else 0
}

注:Samsung A70では、このメソッドはステータスバーの高さ+ナビゲーションバーの高さを返します。他のデバイス(Huawei)では、ナビゲーションバーの高さのみを返し、ナビゲーションバーが非表示の場合は0を返します。

private fun getNavigationBarHeight(): Int {
        val display = activity?.windowManager?.defaultDisplay
        return if (display == null) {
            0
        } else {
            val realMetrics = DisplayMetrics()
            display.getRealMetrics(realMetrics)
            val metrics = DisplayMetrics()
            display.getMetrics(metrics)
            realMetrics.heightPixels - metrics.heightPixels
        }
    }

ナビゲーションバーとステータスバーの高さを取得するコードです

val metrics = DisplayMetrics()
        activity?.windowManager?.defaultDisplay?.getRealMetrics(metrics)

        //resources is got from activity

        //NOTE: on SamSung A70, this height = height of status bar + height of Navigation bar
        //On other devices (Huawei), this height = height of Navigation bar
        val navigationBarHeightOrNavigationBarPlusStatusBarHeight = getNavigationBarHeight()

        val statusBarHeight = getStatusBarHeight(resources)
        //The method will always return the height of navigation bar even when the navigation bar was hidden.
        val realNavigationBarHeight = getNavigationBarHeight(resources)

        val realHeightOfStatusBarAndNavigationBar =
                if (navigationBarHeightOrNavigationBarPlusStatusBarHeight == 0 || navigationBarHeightOrNavigationBarPlusStatusBarHeight < statusBarHeight) {
                    //Huawei: navigation bar is hidden
                    statusBarHeight
                } else if (navigationBarHeightOrNavigationBarPlusStatusBarHeight == realNavigationBarHeight) {
                    //Huawei: navigation bar is visible
                    statusBarHeight + realNavigationBarHeight
                } else if (navigationBarHeightOrNavigationBarPlusStatusBarHeight < realNavigationBarHeight) {
                    //SamSung A70: navigation bar is still visible but it only displays as a under line
                    //navigationBarHeightOrNavigationBarPlusStatusBarHeight = navigationBarHeight'(under line) + statusBarHeight
                    navigationBarHeightOrNavigationBarPlusStatusBarHeight
                } else {
                    //SamSung A70: navigation bar is visible
                    //navigationBarHeightOrNavigationBarPlusStatusBarHeight == statusBarHeight + realNavigationBarHeight
                    navigationBarHeightOrNavigationBarPlusStatusBarHeight
                }

1

私はこれを行いました、それは私がテストしたすべてのデバイスで、そしてエミュレーターでも動作します:

// Return the NavigationBar height in pixels if it is present, otherwise return 0
public static int getNavigationBarHeight(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());
}

0

これが私がこれを解決した方法です。ナビゲーションバーがあるかどうかに応じてパディングが必要な非表示のボトムバーを作成しました(容量、画面上、またはプレロリポップのみ)。


見る

setPadding(0, 0, 0, Utils.hasNavBar(getContext()) ? 30 : 0);

Utils.java

public static boolean hasNavBar(Context context) {
    // Kitkat and less shows container above nav bar
    if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
        return false;
    }
    // Emulator
    if (Build.FINGERPRINT.startsWith("generic")) {
        return true;
    }
    boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
    boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
    boolean hasNoCapacitiveKeys = !hasMenuKey && !hasBackKey;
    Resources resources = context.getResources();
    int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
    boolean hasOnScreenNavBar = id > 0 && resources.getBoolean(id);
    return hasOnScreenNavBar || hasNoCapacitiveKeys || getNavigationBarHeight(context, true) > 0;
}

public static int getNavigationBarHeight(Context context, boolean skipRequirement) {
    int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0 && (skipRequirement || hasNavBar(context))) {
        return context.getResources().getDimensionPixelSize(resourceId);
    }
    return 0;
}

0

私がこのようなものを持ちたかった私の場合:

スクリーンショット

@Mdlcによって提案されたのと同じことを実行する必要がありましたが、おそらく少し単純です(21以上のターゲットのみ)。

    //kotlin
    val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    val realSize = Point()
    windowManager.defaultDisplay.getRealSize(realSize);
    val usableRect = Rect()
    windowManager.defaultDisplay.getRectSize(usableRect)
    Toast.makeText(this, "Usable Screen: " + usableRect + " real:"+realSize, Toast.LENGTH_LONG).show()

    window.decorView.setPadding(usableRect.left, usableRect.top, realSize.x - usableRect.right, realSize.y - usableRect.bottom)

ランドスケープでも機能します:

風景

編集 上記のソリューションは、ナビゲーションウィンドウだけでなくカスタムウィンドウサイズのためにも使用可能な長方形が小さくならないマルチウィンドウモードでは正しく機能しません。私が気づいたことの1つは、マルチウィンドウではナビゲーションバーがアプリの上に置かれていないため、DecorViewのパディングを変更しなくても正しい動作が得られることです。

デコレーションビューのパディングを変更しないマルチウィンドウ 装飾ビューのパディングを変更しない単一ウィンドウ

これらのシナリオで、ナビゲーションバーがアプリの下部に移動する方法の違いに注意してください。幸い、これは簡単に修正できます。アプリがマルチウィンドウかどうかを確認できます。以下のコードには、ツールバーの位置を計算および調整するための部分も含まれています(完全なソリューション:https : //stackoverflow.com/a/14213035/477790

    // kotlin
    // Let the window flow into where window decorations are
    window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN)
    window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)

    // calculate where the bottom of the page should end up, considering the navigation bar (back buttons, ...)
    val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    val realSize = Point()
    windowManager.defaultDisplay.getRealSize(realSize);
    val usableRect = Rect()
    windowManager.defaultDisplay.getRectSize(usableRect)
    Toast.makeText(this, "Usable Screen: " + usableRect + " real:" + realSize, Toast.LENGTH_LONG).show()

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N || !isInMultiWindowMode) {
        window.decorView.setPadding(usableRect.left, usableRect.top, realSize.x - usableRect.right, realSize.y - usableRect.bottom)
        // move toolbar/appbar further down to where it should be and not to overlap with status bar
        val layoutParams = ConstraintLayout.LayoutParams(appBarLayout.layoutParams as ConstraintLayout.LayoutParams)
        layoutParams.topMargin = getSystemSize(Constants.statusBarHeightKey)
        appBarLayout.layoutParams = layoutParams
    }

Samsungポップアップモードの結果:

ここに画像の説明を入力してください


0

ナビゲーションバーの高さ(ピクセル単位)を取得するためのテスト済みコード:

public static int getNavBarHeight(Context c) {
    int resourceId = c.getResources()
                      .getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        return c.getResources().getDimensionPixelSize(resourceId);
    }
    return 0;
}

ステータスバーの高さ(ピクセル単位)を取得するためのテスト済みコード:

public static int getStatusBarHeight(Context c) {
    int resourceId = c.getResources()
                      .getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        return c.getResources().getDimensionPixelSize(resourceId);
    }
    return 0;
}

ピクセルをdpに変換する:

public static int pxToDp(int px) {
    return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}

0

サムスンS8の場合、上記の提供されたメソッドのいずれもナビゲーションバーの適切な高さを提供していなかったため、KeyboardHeightProvider キーボード高さプロバイダーandroidを使用しました。そして、それは私に負の値で高さを与えました、そして私のレイアウト配置のために私は計算でその値を調整しました。

ここにありKeyboardHeightProvider.javaます:

import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager.LayoutParams;
import android.widget.PopupWindow;


/**
 * The keyboard height provider, this class uses a PopupWindow
 * to calculate the window height when the floating keyboard is opened and closed. 
 */
public class KeyboardHeightProvider extends PopupWindow {

    /** The tag for logging purposes */
    private final static String TAG = "sample_KeyboardHeightProvider";

    /** The keyboard height observer */
    private KeyboardHeightObserver observer;

    /** The cached landscape height of the keyboard */
    private int keyboardLandscapeHeight;

    /** The cached portrait height of the keyboard */
    private int keyboardPortraitHeight;

    /** The view that is used to calculate the keyboard height */
    private View popupView;

    /** The parent view */
    private View parentView;

    /** The root activity that uses this KeyboardHeightProvider */
    private Activity activity;

    /** 
     * Construct a new KeyboardHeightProvider
     * 
     * @param activity The parent activity
     */
    public KeyboardHeightProvider(Activity activity) {
        super(activity);
        this.activity = activity;

        LayoutInflater inflator = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        this.popupView = inflator.inflate(R.layout.popupwindow, null, false);
        setContentView(popupView);

        setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_RESIZE | LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);

        parentView = activity.findViewById(android.R.id.content);

        setWidth(0);
        setHeight(LayoutParams.MATCH_PARENT);

        popupView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

                @Override
                public void onGlobalLayout() {
                    if (popupView != null) {
                        handleOnGlobalLayout();
                    }
                }
            });
    }

    /**
     * Start the KeyboardHeightProvider, this must be called after the onResume of the Activity.
     * PopupWindows are not allowed to be registered before the onResume has finished
     * of the Activity.
     */
    public void start() {

        if (!isShowing() && parentView.getWindowToken() != null) {
            setBackgroundDrawable(new ColorDrawable(0));
            showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);
        }
    }

    /**
     * Close the keyboard height provider, 
     * this provider will not be used anymore.
     */
    public void close() {
        this.observer = null;
        dismiss();
    }

    /** 
     * Set the keyboard height observer to this provider. The 
     * observer will be notified when the keyboard height has changed. 
     * For example when the keyboard is opened or closed.
     * 
     * @param observer The observer to be added to this provider.
     */
    public void setKeyboardHeightObserver(KeyboardHeightObserver observer) {
        this.observer = observer;
    }

    /**
     * Get the screen orientation
     *
     * @return the screen orientation
     */
    private int getScreenOrientation() {
        return activity.getResources().getConfiguration().orientation;
    }

    /**
     * Popup window itself is as big as the window of the Activity. 
     * The keyboard can then be calculated by extracting the popup view bottom 
     * from the activity window height. 
     */
    private void handleOnGlobalLayout() {

        Point screenSize = new Point();
        activity.getWindowManager().getDefaultDisplay().getSize(screenSize);

        Rect rect = new Rect();
        popupView.getWindowVisibleDisplayFrame(rect);

        // REMIND, you may like to change this using the fullscreen size of the phone
        // and also using the status bar and navigation bar heights of the phone to calculate
        // the keyboard height. But this worked fine on a Nexus.
        int orientation = getScreenOrientation();
        int keyboardHeight = screenSize.y - rect.bottom;

        if (keyboardHeight == 0) {
            notifyKeyboardHeightChanged(0, orientation);
        }
        else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
            this.keyboardPortraitHeight = keyboardHeight; 
            notifyKeyboardHeightChanged(keyboardPortraitHeight, orientation);
        } 
        else {
            this.keyboardLandscapeHeight = keyboardHeight; 
            notifyKeyboardHeightChanged(keyboardLandscapeHeight, orientation);
        }
    }

    /**
     *
     */
    private void notifyKeyboardHeightChanged(int height, int orientation) {
        if (observer != null) {
            observer.onKeyboardHeightChanged(height, orientation);
        }
    }

    public interface KeyboardHeightObserver {
        void onKeyboardHeightChanged(int height, int orientation);
    }
}

popupwindow.xml

<?xml version="1.0" encoding="utf-8"?>
<View
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/popuplayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:orientation="horizontal"/>

での使用 MainActivity

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

/**
 * Created by nileshdeokar on 22/02/2018.
 */
class MainActivity : AppCompatActivity() , KeyboardHeightProvider.KeyboardHeightObserver  {

    private lateinit var keyboardHeightProvider : KeyboardHeightProvider


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        keyboardHeightProvider = KeyboardHeightProvider(this)
        parentActivityView.post { keyboardHeightProvider?.start() }
    }

    override fun onKeyboardHeightChanged(height: Int, orientation: Int) {
        // In case of 18:9 - e.g. Samsung S8
        // here you get the height of the navigation bar as negative value when keyboard is closed.
        // and some positive integer when keyboard is opened.
    }

    public override fun onPause() {
        super.onPause()
        keyboardHeightProvider?.setKeyboardHeightObserver(null)
    }

    public override fun onResume() {
        super.onResume()
        keyboardHeightProvider?.setKeyboardHeightObserver(this)
    }

    public override fun onDestroy() {
        super.onDestroy()
        keyboardHeightProvider?.close()
    }
}

さらにヘルプが必要な場合は、こちらの高度な使用法をご覧ください


0

シンプルな1行ソリューション

上記の回答の多くで示唆されているように、例えば

ナビゲーションバーの高さを取得するだけでは不十分な場合があります。1.ナビゲーションバーが存在するか、2。下部にあるか、右または左にあるか、3。マルチウィンドウモードでアプリが開いているかを考慮する必要があります。

さいわいandroid:fitsSystemWindows="true"、ルートレイアウトを設定するだけで、長いコーディングを簡単にバイパスできます。Androidシステムは、ルートビューに必要なパディングを自動的に追加して、子ビューがナビゲーションバーやステータスバーの領域に入らないようにします。

シンプルな1行のソリューションがあります

android:fitsSystemWindows="true"

またはプログラム的に

findViewById(R.id.your_root_view).setFitsSystemWindows(true);

ルートビューを取得することもできます

findViewById(android.R.id.content).getRootView();
or
getWindow().getDecorView().findViewById(android.R.id.content)

ルートビューの取得の詳細については、https://stackoverflow.com/a/4488149/9640177を参照してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.