Высота статусбара?
Есть ли способ получить высоту статусбара + заголовок заголовка? Проверка на форуме разработчиков показывает тот же вопрос, но не дает решения (которое я смог найти).
Я знаю, что мы можем получить его после начального этапа компоновки, но я хочу включить его в onCreate() моей деятельности.
Спасибо
14 ответов
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;
Log.i("*** Jorgesys :: ", "StatusBar Height= " + StatusBarHeight + " , TitleBar Height = " + TitleBarHeight);
Получить высоту строки состояния на onCreate()
метод вашей деятельности, используйте этот метод:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Для тех, кто, как и я, хочет использовать его в своих макетах XML:
<...
android:layout_marginTop="@*android:dimen/status_bar_height"
... />
Не смущайтесь тем, что Android Studio (2.2 Preview 3 - на момент написания статьи) не поддерживает это понятие. Время выполнения делает. Я взял это из исходного кода Google.
Хотя это старый вопрос, я обнаружил, что ответ не работает в onCreate()
:
Я нашел этот код отсюда, который работает в onCreate()
метод
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Я надеюсь, что это помогает всем, кто сталкивается с этой проблемой.
Поддерживаемый способ получения высоты строки состояния - использовать WindowInsets
класс, начиная с API 21+:
customView.setOnApplyWindowInsetsListener((view, insets) -> {
// Handle insets
return insets.consumeSystemWindowInsets();
});
или же WindowInsetsCompat
для поддержки библиотек:
ViewCompat.setOnApplyWindowInsetsListener(customView, (view, insets) -> {
// Handle insets
return insets.consumeSystemWindowInsets();
});
Вы также можете переопределить onApplyWindowInsets
метод внутри представления:
public class CustomView extends View {
@Override
public WindowInsets onApplyWindowInsets(final WindowInsets insets) {
final int statusBarHeight = insets.getStableInsetTop();
return insets.consumeStableInsets();
}
}
Для получения более подробной информации, я бы порекомендовал проверить выступление Криса Бэйнса - стать мастером по сборке окон (слайды доступны здесь).
Вы также можете взять размер строки состояния, найденный в файле измерения.xml на Android, используя способ, описанный в этом сообщении в блоге.
Это может получить высоту строки состояния без необходимости ждать рисования.
Цитирую код из поста в блоге:
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
Вам нужно поместить этот метод в класс ContextWrapper.
Я бы предложил следующий код:
Rect rect = new Rect();
Window window = activity.getWindow();
if (window != null) {
window.getDecorView().getWindowVisibleDisplayFrame(rect);
android.view.View v = window.findViewById(Window.ID_ANDROID_CONTENT);
android.view.Display display = ((android.view.WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
//return result title bar height
return display.getHeight() - v.getBottom() + rect.top;
}
Два примера:
1) Марка устройства 1: Samsung, устройство: maguro, плата: тунец, процессор_abi: armeabi-v7a, дисплей: ICL53F.M420KREL08, производитель: Samsung, модель: Galaxy Nexus, версия для печати: 4.0.2, версия.sdk: 14;
Разрешение экрана: 1280 x 720. На этом устройстве нет аппаратных кнопок.
Результаты:
rect: left=0 right=720 top=72 bottom=1208;
v: left=0 right=720 top=72 bottom=1208;
display: height=1208 width=720;
correct result=72;
Устройство 1 имеет строку заголовка в верхней части экрана и строку состояния с программными кнопками в нижней части экрана.
2) Устройство 2, устройство: bravo, плата: bravo, cpu_abi: armeabi-v7a, дисплей: FRG83G, производитель: HTC, модель: HTC Desire, ver.release: 2.2.2, ver.sdk: 8,
Разрешение экрана: 800 х 400. Это устройство имеет аппаратные кнопки.
Результаты:
rect: left=0 right=480 top=38 bottom=800;
v: left=0 right=480 top=0 bottom=800;
display: height=800 width=480;
correct result: phone_bar_height=38;
Устройство 2 имеет строку заголовка в верхней части экрана и вообще не имеет строки состояния.
Два решения были предложены выше:
A) v.getTop() - rect.top
(это неверно для устройства 1 - оно дает 0 вместо 72)
B) display.getHeight() - v.getHeight()
(это неверно для устройства 2 - оно дает 0 вместо 38)
Вариант:
display.getHeight() - v.getBottom() + rect.top
дает правильные результаты в обоих случаях.
Обновить
3) Еще один пример (третье устройство): марка: LGE, устройство: v909, cpu_abi: armeabi-v7a, дисплей: HMJ37, модель: LG-V909, версия для печати: 3.1, версия.sdk: 12
rect: left=0 right=1280 top=0 bottom=720
v: left=0 right=1280 top=0 bottom=720
Display: height=768 width=1280
phone_bar_height=48
Устройство 3 имеет горизонтальную ориентацию, не имеет строки заголовка в верхней части экрана и строки состояния в нижней части экрана.
Так вот:
int size_of_title_bar = rect.top;
int size_of_status_bar = display.getHeight() - v.getBottom();
Это верно для устройств 2 и 3. Я не уверен насчет устройства 1. Пользователь прислал мне скриншот устройства 1. Там есть строка состояния с программной кнопкой. Но выражение "display.getHeight() - v.getBottom()" дает 0.
Прикрепите runnable к одному из ваших представлений в вашем методе onCreate и поместите туда приведенный выше код. Это заставит приложение вычислять строку состояния + высоту титровального экрана, когда они прикреплены к экрану.
Посмотрите на код ниже:
myView.post(new Runnable() {
@Override
public void run() {
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;
}
});
Если это по-прежнему не помогает, попробуйте вызвать метод postDelayed представления вместо post и добавить значение миллисекунды в качестве второго аргумента.
Это может показаться не связанным, но в большинстве случаев причина, по которой люди ищут высоту строки состояния, заключается в смещении их собственных представлений, чтобы они не помещались под нее.
Установив fitsSystemWindows
в представлении, которое вы хотите "нажать", чтобы освободить место в строке состояния, это будет сделано автоматически и в соответствии с размером строки состояния на каждом устройстве. Заполнение будет добавлено в представление, для которого установлено это свойство true
,
Имейте в виду, что заполнение будет добавлено только к первому представлению в иерархии с fitSystemWindows
установлен в true
Это относится к случаям, когда строка состояния является полупрозрачной, например. Убедитесь, что вы установили тему для деятельности, которая не имеет fitSystemWindows
установить, в противном случае дополнение будет добавлено к действию (потому что оно первое в иерархии).
Эта статья хорошо читается на эту тему
Текущий фактический способ:
Котлин:
ViewCompat.setOnApplyWindowInsetsListener(toolbar) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.statusBars())
view.updateLayoutParams<MarginLayoutParams> {
topMargin = insets.top
}
WindowInsetsCompat.CONSUMED
}
Джава:
ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
mlp.topMargin = insets.top;
v.setLayoutParams(mlp);
return WindowInsetsCompat.CONSUMED;
}
Google рекомендует использовать его таким образом, если вы хотите поддерживать в своем приложении сквозную обработку .
В API 23 есть лучшее решение для получения высоты строки состояния. API 23 добавляет WindowInsets
функция, так что вы можете использовать этот код, чтобы получить размер системных вставок, в данном случае вверху.
public int getStatusBarHeight() {
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
return binding.mainContent.getRootWindowInsets().getStableInsetTop();
}
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if(resourceId != 0) {
return getResources().getDimensionPixelSize(resourceId);
}
return 0;
}
Обратите внимание, что getRootWindowInsets()
будет возвращать ноль до тех пор, пока представление не будет присоединено к окну, поэтому его нельзя использовать непосредственно в onCreate()
но вы можете добавить прослушиватель для окна присоединения и сделать это там - здесь я добавляю вставку строки состояния к размеру моей панели инструментов, которую я скрываю и показываю, вместе со строкой состояния. Когда он отображается, я хочу, чтобы строка состояния поверх него, поэтому я добавляю высоту строки состояния к верхнему отступу панели инструментов.
binding.mainContent.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View view) {
binding.toolbar.setPadding(binding.toolbar.getPaddingLeft(),
binding.toolbar.getPaddingTop() + getStatusBarHeight(),
binding.toolbar.getPaddingRight(), binding.toolbar.getPaddingBottom());
binding.mainContent.removeOnAttachStateChangeListener(this);
}
@Override
public void onViewDetachedFromWindow(View view) {
}
});
Я думаю, что лучший способ рассчитать это, чтобы получить высоту полноэкранного режима минус наш основной макет
phoneBarsHeight = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight()
- mainView.getHeight();
И вы можете положить его в onGlobalLayout()
, Это работает на планшетах тоже, я пробовал на Theme.NoTitleBar, но он всегда должен работать.
Может быть, вы можете даже улучшить его и использовать его onCreate()
путем изменения mainView.getHeight()
в mainView.getMeasuredHeight()
,
В порядке. Окончательный ответ!!! Тот, у которого нет побочных эффектов, основан на задокументированном поведении, поддерживает Q, вырезы, устройства с разным размером строки состояния в зависимости от ориентации и т. Д.
protected void onCreate(Bundle savedInstanceState) {
...
setContentView(R.layout.activity_main);
....
// Use The topmost view of the activity, which
// is guaranteed to be asked about window insets/
View rootView = findViewById(R.id.root_view_of_your_activity);
ViewCompat.setOnApplyWindowInsetsListener(rootView, new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets)
{
//THIS is the value you want.
statusBarHeight = insets.getSystemWindowInsetTop();
// Let the view handle insets as it likes.
return ViewCompat.onApplyWindowInsets(v,insets);
}
});
Обратный вызов происходит после onStart(), перед первым макетом и иногда после него.
Решение, опубликованное Jorgesys, очень хорошее, но оно не работает внутри метода onCreate(). Я думаю, это потому, что статусная строка и заголовок создаются после onCreate().
Решение простое - вы должны поместить код в runnable и выполнить его после onCreate (), используя root.post((Runnable action) );
Итак, все решение:
root = (ViewGroup)findViewById(R.id.root);
root.post(new Runnable() {
public void run(){
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int StatusBarHeight= rectgle.top;
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int TitleBarHeight= contentViewTop - StatusBarHeight;
Log.i("*** jakkubu :: ", "StatusBar Height= " + StatusBarHeight +
" , TitleBar Height = " + TitleBarHeight);
}
});
Я нахожу это здесь
Ориентируясь на API 30, я использовал успешно обновленный ответ Nicklas (ссылка: /questions/32142575/vyisota-stroki-sostoyaniya-v-android/32142598#32142598)
В моем примере я настраиваю динамически настраиваемую высоту панели инструментов в полноэкранном режиме.
WindowCompat.setDecorFitsSystemWindows(window, false)
Деятельность
Проверено на GooglePixel 5
class MyActivity : ViewBindingActivity<LayoutBinding>() {
...
override fun created(binding: LayoutBinding, savedInstanceState: Bundle?) {
binding.root.setOnApplyWindowInsetsListener { _, insets ->
val statusBarHeight = insets.getInsets(WindowInsets.Type.statusBars()).top // <- HERE YOU ARE
val toolbarHeight = getDimenPx(R.dimen.toolbar_height)
binding.toolbar.layoutParams.height = statusBarHeight + toolbarHeight
insets
}
}
}