Ekranın altındaki siyah gezinme çubuğu Android'de kolayca çıkarılamaz. Donanım düğmelerinin yerini almak üzere 3.0'dan beri Android'in bir parçası. Burada bir resim var:
Bu UI öğesinin genişliğini ve yüksekliğini piksel cinsinden nasıl alabilirim?
Ekranın altındaki siyah gezinme çubuğu Android'de kolayca çıkarılamaz. Donanım düğmelerinin yerini almak üzere 3.0'dan beri Android'in bir parçası. Burada bir resim var:
Bu UI öğesinin genişliğini ve yüksekliğini piksel cinsinden nasıl alabilirim?
Yanıtlar:
Aşağıdaki kodu deneyin:
Resources resources = context.getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
return resources.getDimensionPixelSize(resourceId);
}
return 0;
navigation_bar_height_landscape
yatay modda gezinme çubuğu yüksekliği ve navigation_bar_width
dikey gezinme çubuğunun genişliği için de deneyin ). Gezinme çubuğunun gerçekte nerede göründüğünü ayrı ayrı bulmanız gerekir, örneğin fiziksel bir menü düğmesinin varlığını test ederek. Belki android.googlesource.com/platform/frameworks/base/+/…
Uygulamada kullanılabilen ekran boyutunu gerçek ekran boyutuyla karşılaştırarak gezinme çubuğu boyutunu elde ediyorum. Uygulama tarafından kullanılabilen ekran boyutu gerçek ekran boyutundan daha küçük olduğunda gezinme çubuğunun mevcut olduğunu varsayıyorum. Sonra gezinti çubuğu boyutunu hesaplıyorum. Bu yöntem, API 14 ve üzeri ile çalışır.
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;
}
GÜNCELLEME
Ekran kesintilerini hesaba katan bir çözüm için lütfen John'un cevabını kontrol edin .
NavigationBar yüksekliği bazı cihazlar için, ancak bazı yönler için de değişir. Öncelikle cihazın bir navbar olup olmadığını kontrol etmelisiniz, ardından cihaz bir tablet mi yoksa tablet değil mi (telefon) ve son olarak doğru yüksekliği elde etmek için cihazın yönüne bakmalısınız.
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;
}
hasBackKey = false!
doğru olması gerekse de Sony Xperia Z3 üzerinde çalışmıyor . Bunun yerine aşağıdakiler işe yaradı: boolean navBarExists = getResources().getBoolean(getResources().getIdentifier("config_showNavigationBar", "bool", "android"));
Aslında tabletlerdeki gezinme çubuğunun (en azından Nexus 7) dikey ve yatay olarak boyutları farklı olduğundan bu işlev şu şekilde görünmelidir:
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;
}
context.getResources().getConfiguration().orientation
Bence daha iyi cevap burada çünkü kesme yüksekliğini bile almanıza izin veriyor.
Kök görünümünüzü alın ve setOnApplyWindowInsetsListener ekleyin (veya onApplyWindowInsets'i buradan geçersiz kılabilirsiniz) ve ondan insets.getSystemWindowInsets alın.
Kamera etkinliğimde, alt düzenime systemWindowInsetBottom'a eşit dolgu ekliyorum. Ve son olarak, kesme sorununu düzeltir.
appcompat ile bu böyle
ViewCompat.setOnApplyWindowInsetsListener(mCameraSourcePreview, (v, insets) -> {
takePictureLayout.setPadding(0,0,0,insets.getSystemWindowInsetBottom());
return insets.consumeSystemWindowInsets();
});
appcompat olmadan, bu:
mCameraSourcePreview.setOnApplyWindowInsetsListener((v, insets) -> { ... })
setOnApplyWindowInsetsListener
Bunun yerine kullanmak mümkün mü ? Öyleyse nasıl? ve neden LOLLIPOP ile diğerleri arasında ayrım yaptınız?
umarım bu sana yardımcı olur
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;
}
Bu, Gezinme Çubuğunu atlatmak için bir Görünüme paddingRight ve paddingBottom eklemek için kodumdur. Burada bazı cevapları birleştirdim ve isInMultiWindowMode ile birlikte yatay yönlendirme için özel bir madde yaptım. Anahtar, navigation_bar_height'ı okumak , aynı zamanda yüksekliği gerçekten kullanmamız gerektiğinden emin olmak için config_showNavigationBar'ı kontrol etmektir .
Önceki çözümlerin hiçbiri benim için işe yaramadı. Android 7.0'dan itibaren Çoklu Pencere Modunu göz önünde bulundurmanız gerekiyor. Bu, display.realSize ile display.size'yi karşılaştıran uygulamaları bozar , çünkü realSize size tüm ekranın boyutlarını (hem bölünmüş pencereler) hem de size yalnızca Uygulama pencerenizin boyutlarını verir. Bu farklılığa dolgu ayarlamak, tüm görünümünüzün dolgulu kalmasını sağlayacaktır.
/** 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);
}
Alt Gezinme çubuğunun yüksekliği 48dp'dir (hem dikey hem de yatay modda) ve çubuk dikey olarak yerleştirildiğinde 42dp'dir.
Egidijus tarafından önerilen ve Build.VERSION.SDK_INT> = 17 için mükemmel çalışan çözüm
Ancak aygıtımda Build.VERSION.SDK_INT <17 ile aşağıdaki ifadenin yürütülmesi sırasında "NoSuchMethodException" aldım:
Display.class.getMethod("getRawHeight").invoke(display);
Bu tür durumlar için getRealScreenSize () yöntemini değiştirdim:
else if(Build.VERSION.SDK_INT >= 14)
{
View decorView = getActivity().getWindow().getDecorView();
size.x = decorView.getWidth();
size.y = decorView.getHeight();
}
Bu sorunu tüm cihazlar için çözdüm (Nexus 5, Samsung Galaxy Nexus 6 edge +, Samsung S10, Samsung Note II vb. Dahil). Bunun cihaza bağlı sorunları çözmenize yardımcı olacağını düşünüyorum.
Burada iki tür kod ekliyorum,
Java Kodu (Yerel Android için):
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;
}
}
Ve C # kodu (Xamarin Forms / Android için)
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 seviye 17 gerektirir
screenOrientation
Varsayılan olduğunda hasPermanentMenuKey
, false
yalnızca döndürülmüyorsa geçerlidir. [2] screenOrientation
Manzara olduğunda , displayMetrics.heightPixels != realDisplayMetrics.heightPixels)
başka bir yere düşer . [3] screenOrientation
Portre ne zaman , hasPermanentMenuKey
olur false
.
@Egis ve diğerlerinin yanıtı birleştirildiğinde - bu, Pixel EMU, Samsung S6, Sony Z3, Nexus 4 üzerinde test edilen çeşitli cihazlarda iyi çalışır. Bu kod, gezinme çubuğunun kullanılabilirliğini test etmek için ekran boyutlarını kullanır ve ardından gerçek varsa sistem gezinme çubuğu boyutu.
/**
* 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);
}
}
Gezinme çubuğunun ve durum çubuğunun yüksekliği nasıl alınır. Bu kod benim için bazı Huawei cihazlarında ve Samsung cihazlarında çalışıyor . Egis'in yukarıdaki çözümü iyidir, ancak bazı cihazlarda hala yanlıştır. Ben de geliştirdim.
Bu, durum çubuğunun yüksekliğini almak için koddur
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
}
Bu yöntem, gezinme çubuğu gizlendiğinde bile her zaman gezinme çubuğunun yüksekliğini döndürür.
private fun getNavigationBarHeight(resources: Resources): Int {
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId > 0) {
resources.getDimensionPixelSize(resourceId)
} else 0
}
NOT: Samsung A70'te bu yöntem, durum çubuğunun yüksekliğini + gezinme çubuğunun yüksekliğini döndürür. Diğer cihazlarda (Huawei), yalnızca Gezinme çubuğunun yüksekliğini döndürür ve gezinme çubuğu gizlendiğinde 0 değerini döndürür.
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
}
}
Bu, gezinme çubuğunun ve durum çubuğunun yüksekliğini gösteren koddur
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
}
Bunu yaptım, test ettiğim her cihazda ve hatta emülatörlerde çalışıyor:
// 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());
}
İşte bunu nasıl çözdüm. Gezinme çubuğu olup olmadığına (kapasitif, ekran üstü veya sadece ön lolipop) bağlı olarak dolguya ihtiyaç duyan gizlenebilir bir alt çubuk yaptım.
Görünüm
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;
}
Benim durumumda böyle bir şeye sahip olmak istedim:
@Mdlc tarafından önerilen aynı şeyi takip etmek zorunda kaldım, ancak muhtemelen biraz daha basit ( yalnızca > = 21 hedefleme ):
//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)
Manzara üzerinde de çalışır:
Düzenleme Yukarıdaki çözüm, kullanılabilir dikdörtgenin yalnızca gezinme çubuğu nedeniyle değil, aynı zamanda özel pencere boyutu nedeniyle daha küçük olduğu çoklu pencere modunda doğru şekilde çalışmaz. Fark ettiğim bir şey, çoklu pencerede gezinme çubuğunun uygulamanın üzerine gelmemesidir, bu nedenle DecorView dolgusunda herhangi bir değişiklik olmasa bile doğru davranışa sahibiz:
Senaryolarda gezinme çubuğunun uygulamanın alt kısmına nasıl geldiği arasındaki farka dikkat edin. Neyse ki, bunu düzeltmek kolaydır. Uygulamanın çoklu pencere olup olmadığını kontrol edebiliriz. Aşağıdaki kod, araç çubuğunun konumunu hesaplamak ve ayarlamak için bölüm de içerir (tam çözüm: 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 açılır modundaki sonuç:
Gezinme çubuğunun yüksekliğini almak için test edilen kod (piksel cinsinden):
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;
}
Durum çubuğunun yüksekliğini almak için test edilen kod (piksel cinsinden):
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;
}
Pikselleri dp'ye dönüştürme:
public static int pxToDp(int px) {
return (int) (px / Resources.getSystem().getDisplayMetrics().density);
}
Samsung S8 durumunda, yukarıda verilen yöntemlerden hiçbiri gezinme çubuğunun uygun yüksekliğini vermiyordu, bu yüzden KeyboardHeightProvider klavye yükseklik sağlayıcısı androidini kullandım . Ve bana negatif değerlerde yükseklik verdi ve düzen konumlandırmam için bu değeri hesaplamalarda ayarladım.
İşte 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"/>
Kullanım 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()
}
}
Başka yardım için bu gelişmiş kullanım bakmak olabilir burada .
Basit Tek Hatlı Çözüm
Örneğin, yukarıdaki yanıtların çoğunda önerildiği gibi
Sadece gezinme çubuğunun yüksekliğini almak yeterli olmayabilir. 1. gezinme çubuğunun var olup olmadığını, 2. altta mı yoksa sağda mı yoksa solda mı, 3. uygulamanın çoklu pencere modunda açık olup olmadığını değerlendirmemiz gerekir.
Neyse ki android:fitsSystemWindows="true"
, kök düzeninizi ayarlayarak tüm uzun kodlamayı kolayca atlayabilirsiniz . Android sistemi, alt görünümlerin gezinme çubuğuna veya durum çubuğu bölgelerine girmediğinden emin olmak için kök düzenine gerekli dolguyu otomatik olarak ekleyecektir.
Tek satırlık basit bir çözüm var
android:fitsSystemWindows="true"
veya programatik olarak
findViewById(R.id.your_root_view).setFitsSystemWindows(true);
ayrıca kök görünümü elde edebilirsiniz
findViewById(android.R.id.content).getRootView();
or
getWindow().getDecorView().findViewById(android.R.id.content)
Kök görünümü alma hakkında daha fazla ayrıntı için - https://stackoverflow.com/a/4488149/9640177