Как получить размеры экрана в пикселях в Android

1845

Я создал несколько пользовательских элементов и хочу программно разместить их в верхнем правом углу ( nпиксели от верхнего края и mпиксели от правого края). Поэтому мне нужно получить ширину экрана и высоту экрана, а затем установить положение:

int px = screenWidth - m;
int py = screenHeight - n;

Как мне попасть screenWidthи screenHeightв основное занятие ?

Нико Гамулин
источник
Используйте dp вместо px. потому что это будет искажать ваш макет с другими устройствами ..
Джавад Зеб
Не забудьте умножить на getResources (). GetDisplayMetrics (). Плотность для учета масштабирования экрана
jmaculate
Это доказывает, что ответ с наибольшим количеством голосов не всегда является лучшим (и многие люди повторяют ответы для повторения). Вместо getSize и устаревшей комбинации getWidth / getHeight (игнорируя ошибки), попробуйте Balaji.K getMetrics. Комментарий Ника в его ответе даже объясняет, getDisplayMetricsкак учитывать размер системы / строки состояния. Также вы можете использовать плотность, как объяснили jmaculate и LoungeKatt, чтобы иметь значение EXACT : DisplayMetrics dm = getResources().getDisplayMetrics(); float fwidth = dm.density * dm.widthPixels;протестировано в Android v2.2 (API 8) и v4.0 с хорошими результатами и без ошибок / предупреждений .
Armfoot
DisplayMetrics displaymetrics = new DisplayMetrics (); . getWindowManager () getDefaultDisplay () getMetrics (displaymetrics). int height = displaymetrics.heightPixels; int width = displaymetrics.widthPixels;
Азар
другой способ получить DisplayMetrics: Resources.getSystem().getDisplayMetrics(). Вам не понадобится, Contextчтобы получить их.
Тэг

Ответы:

3479

Если вы хотите размеры экрана в пикселях, вы можете использовать getSize:

Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;

Если вы не в, Activityвы можете получить значение Displayпо умолчанию через WINDOW_SERVICE:

WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();

Если вы находитесь во фрагменте и хотите выполнить это, просто используйте Activity.WindowManager (в Xamarin.Android) или getActivity (). GetWindowManager () (в java).

Перед тем как getSizeбыл введен (в уровне API 13), вы можете использовать getWidthи getHeightметоды, которые в настоящее время устарели:

Display display = getWindowManager().getDefaultDisplay(); 
int width = display.getWidth();  // deprecated
int height = display.getHeight();  // deprecated

Однако для описываемого вами варианта использования поле / отступ в макете кажется более подходящим.

Другой способ: DisplayMetrics

Структура, описывающая общую информацию об отображении, такую ​​как его размер, плотность и масштабирование шрифта. Чтобы получить доступ к членам DisplayMetrics, инициализируйте объект следующим образом:

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

Мы можем использовать widthPixelsдля получения информации для:

«Абсолютная ширина дисплея в пикселях».

Пример:

Log.d("ApplicationTagName", "Display width in px is " + metrics.widthPixels);
Йозеф Пфлегер
источник
13
getWidth () или getSize ()? Что бы я использовал, если бы мне нужно, чтобы мое приложение работало как по API <13, так и по API> 13?
Кэрол
52
try {display.getSize (size); ширина = размер.х; высота = размер. у; } catch (NoSuchMethodError e) {width = display.getWidth (); height = display.getHeight (); }
Арно
248
Я не понимаю, почему вы хотите использовать try/catchдля такой проверки? Почему бы просто не использовать if (android.os.Build.VERSION.SDK_INT >= 13)без каких-либо исключений вообще? В try/catchнормальном потоке приложений я считаю плохую практику.
Патрик
2
@ A-Live, тогда приложение тоже сломается (но не рухнет). Тем не менее, мы, разработчики, должны предварительно проверить новую версию ОС, и это может скрыть проблему. Также с этим аргументом можно / нужно окружать каждые несколько строк кода try / catch, что, на мой взгляд, является плохой практикой, как уже упоминалось.
Патрик
11
Что делать, если вы хотите получить размер экрана, исключая панель навигации и / или панель уведомлений
Android-разработчик
375

Одним из способов является:

Display display = getWindowManager().getDefaultDisplay(); 
int width = display.getWidth();
int height = display.getHeight();

Это устарело, и вместо этого вы должны попробовать следующий код. Первые две строки кода дают вам DisplayMetricsцели. Эти объекты содержат поля , как heightPixels, widthPixels.

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);

int height = metrics.heightPixels;
int width = metrics.widthPixels;
Balaji.K
источник
14
Обратите внимание, что метрики (ширина, высота) меняются в зависимости от поворота устройства.
Тони Чан
8
Метрики будут возвращать размер дисплея, но HoneyComb и выше, ваша деятельность будет иметь меньше места, чем возвращается из-за системной панели.
Парень
3
@ Да, это зависит от вашей реализации. Вы можете скрыть строку состояния: requestWindowFeature (Window.FEATURE_NO_TITLE); getWindow (). setFlags (WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
Hagai L
79
Также существует этот способ: getContext (). GetResources (). GetDisplayMetrics (). WidthPixels
Ник
окончательный float scale = getResources (). getDisplayMetrics (). плотность; int width = (int) (metrics.widthPixels * scale + 0.5f); - При этом вы должны учитывать плотность устройства.
Заброшенная корзина
120

Возможно, он не отвечает на ваш вопрос, но было бы полезно знать (я сам искал его, когда пришел к этому вопросу), что если вам нужно измерение View, но ваш код выполняется, когда его макет еще не выложен (например, в onCreate()), вы можете настроить ViewTreeObserver.OnGlobalLayoutListenerс View.getViewTreeObserver().addOnGlobalLayoutListener()и поместить соответствующий код, который нуждается в измерении представления там. Обратный вызов слушателя будет вызван, когда макет будет размечен.

Франческо Фельтринелли
источник
или просто напишите view.post
Лукас Ханачек,
view.post не гарантированно работает, хотя. Это просто обходной путь.
marsbear
@marsbear, где говорится, View.post()что работа не гарантируется? Мне любопытно, потому что я также полагаюсь на этот метод для получения размера представления после макета и не знал, что это ненадежно.
Тони Чан
@ Turbo Я говорю, что: p Мы использовали этот обходной путь раньше, и он оказался ненадежным. Этот обходной путь основан на предположении, что первоначальное размещение выполняется в том же UIThread витке, что и инициализация. Следовательно, вы можете запланировать выполнение своего кода до следующего поворота пользовательского интерфейса с помощью post () и все будет в порядке. Оказалось, что верстка может занять еще больше времени при определенных обстоятельствах, и представление все еще не было выложено, когда запускался опубликованный код. Теперь я добавляю ViewTreeObserver в onCreate и удаляю его после первого onLayout. Инициируйте свои вещи во время этого первого onLayout.
marsbear
@ marsbear имеет ли значение, от чего Viewвы получаете ViewTreeObserver? Или они все делят один и тот же?
Тони Чан
109

(Ответ 2012 г., возможно, устарел). Если вы хотите поддерживать предварительно Honeycomb, вам нужно будет установить обратную совместимость до API 13. Что-то вроде:

int measuredWidth = 0;
int measuredHeight = 0;
WindowManager w = getWindowManager();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
    Point size = new Point();
    w.getDefaultDisplay().getSize(size);
    measuredWidth = size.x;
    measuredHeight = size.y;
} else {
    Display d = w.getDefaultDisplay();
    measuredWidth = d.getWidth();
    measuredHeight = d.getHeight();
}

Конечно, устаревшие методы в конечном итоге будут удалены из самых последних SDK, но, хотя мы по-прежнему полагаемся на большинство наших пользователей, имеющих Android 2.1, 2.2 и 2.3, это то, что нам осталось.

digiphd
источник
Да, это было в 2012 году.
digiphd
извините, позвольте мне уточнить, что я имел в виду. Крайне маловероятно, что кто-либо будет поддерживать API <14 с 22.06.2015
sudocoder
69

Я безуспешно перепробовал все возможные «решения» и заметил, что приложение «Dalvik Explorer» Эллиотта Хьюза всегда показывает правильный размер на любом устройстве Android / версии ОС. В итоге я посмотрел на его проект с открытым исходным кодом, который можно найти здесь: https://code.google.com/p/enh/

Вот весь соответствующий код:

WindowManager w = activity.getWindowManager();
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
// since SDK_INT = 1;
widthPixels = metrics.widthPixels;
heightPixels = metrics.heightPixels;
try {
    // used when 17 > SDK_INT >= 14; includes window decorations (statusbar bar/menu bar)
    widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
    heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
} catch (Exception ignored) {
}
try {
    // used when SDK_INT >= 17; includes window decorations (statusbar bar/menu bar)
    Point realSize = new Point();
    Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
    widthPixels = realSize.x;
    heightPixels = realSize.y;
} catch (Exception ignored) {
}

РЕДАКТИРОВАТЬ: слегка улучшенная версия (избегать исключений запуска на не поддерживаемой версии ОС):

WindowManager w = activity.getWindowManager();
Display d = w.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
d.getMetrics(metrics);
// since SDK_INT = 1;
widthPixels = metrics.widthPixels;
heightPixels = metrics.heightPixels;
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)
try {
    widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
    heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
} catch (Exception ignored) {
}
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 17)
try {
    Point realSize = new Point();
    Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
    widthPixels = realSize.x;
    heightPixels = realSize.y;
} catch (Exception ignored) {
}
Драган Марьянович
источник
9
Это единственный пост, который учитывает оформление окон (строка состояния / строка меню). отлично работал для меня.
Энди Кокрейн
5
Удивительно, но вы никогда не должны были ожидать исключений из бизнес-логики. Исключительная стрельба (даже когда ее поймали) ужасна для производительности. Кроме того, вы выполняете больше работы, чем необходимо, если SDK_INT> 13. Вместо этого вам просто нужно добавить некоторые if в Build.VERSION.SDK_INT.
Эрик Б
3
@ Эрик Б, я согласен. Я добавил улучшенную версию. Тем не менее, я оставил часть «начиная с SDK 1» на случай, если что-то пойдет не так в try / catch (я видел много плохих вещей в Android, особенно когда вы думаете, что что-то не получается, поэтому я хотел бы сохранить это в безопасности :)) , В любом случае не должно быть слишком много накладных расходов, так как этот расчет должен быть выполнен только один раз (например, значения могут быть сохранены в некоторых статических атрибутах).
Драган Марьянович
8
Обратите внимание, что этот код распространяется по лицензии GPL v3, что имеет значение для использования в производственных приложениях.
TalkLittle
GPL и в зависимости от отражения вызывать методы, которые могут отсутствовать в будущих версиях Android. Mhhh
Мишель
47

Самый простой способ:

 int screenHeight = getResources().getDisplayMetrics().heightPixels;
 int screenWidth = getResources().getDisplayMetrics().widthPixels; 
Zelleriation
источник
46

Для доступа к высоте строки состояния для устройств Android мы предпочитаем программный способ получить ее:

Образец кода

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

Переменная resultдает высоту в пикселе.

Для быстрого доступа

Введите описание изображения здесь

Для получения дополнительной информации о высоте Title bar, Navigation barи Content View, любезно взгляд на Android экран устройства Размеры .

Swapnil Sonar
источник
Как раз то, что мне нужно! getResources().getDisplayMetrics().heightPixels + resultдает фактическую высоту полного экрана. Ответ Драгана Марьяновича также работает, но я предпочитаю это гораздо более короткое и простое решение.
Мишель
Этот подход устарел с Android Marshmallow. Высота строки состояния может меняться от версии устройства или Android. Лучше использовать OnApplyWindowInsetsListener.
Генрих
32

Сначала получите представление (например, by findViewById()), а затем вы можете использовать getWidth () для самого представления.

Марцин Гил
источник
3
Это фактически то, как документация говорит вам сделать это ... но это немного бессмысленно, если вы НЕ используете представление. Вы можете использовать что-то еще, например, mglsurfaceview.
GCB
2
это лучше, поскольку родительский вид может не соответствовать размеру дисплея. Но убедитесь, что это сделано в точке, где представление, размер которого вы запрашиваете, уже выложено, что обычно не будет внутри onCreate (). Вы можете использовать пользовательский обратный вызов из onWindowFocusChanged (boolean hasFocus), который будет вызываться после измерения всех видов и т. Д., Гарантируя, что вы не получите неправильные размеры для интересующего вас вида ...
Дори
27

У меня есть две функции, одна для отправки контекста, а другая для получения высоты и ширины в пикселях:

public static int getWidth(Context mContext){
    int width=0;
    WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    if(Build.VERSION.SDK_INT>12){
        Point size = new Point();
        display.getSize(size);
        width = size.x;
    }
    else{
        width = display.getWidth();  // Deprecated
    }
    return width;
}

а также

public static int getHeight(Context mContext){
    int height=0;
    WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    if(Build.VERSION.SDK_INT>12){
        Point size = new Point();
        display.getSize(size);
        height = size.y;
    }
    else{
        height = display.getHeight();  // Deprecated
    }
    return height;
}
Jorgesys
источник
Вам нужно добавить @SuppressLint("NewApi")чуть выше сигнатуру функции, чтобы иметь возможность компилировать.
Адиль Малик
Я думаю, что лучше получить высоту и ширину за один раз, а не в отдельных вызовах API, потому что в противном случае они могут быть не синхронизированы. Это может произойти, если ориентация экрана меняется во время работы вашего кода.
Сэм
17

Для динамического масштабирования с использованием XML есть атрибут под названием «android: layout_weight»

Приведенный ниже пример, модифицированный по ответу synic в этой теме , показывает кнопку, занимающую 75% экрана (вес = .25), и текстовое представление, занимающее оставшиеся 25% экрана (вес = .75).

<LinearLayout android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight=".25"
        android:text="somebutton">

    <TextView android:layout_width="fill_parent"
        android:layout_height="Wrap_content"
        android:layout_weight=".75">
</LinearLayout>
Crbreingan
источник
17

Вот код, который я использую для задачи:

// `activity` is an instance of Activity class.
Display display = activity.getWindowManager().getDefaultDisplay();
Point screen = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
    display.getSize(screen);
} else {            
    screen.x = display.getWidth();
    screen.y = display.getHeight();
}

Кажется достаточно чистым и все же, заботится об амортизации.

Pijusn
источник
17

Разве это не намного лучшее решение? DisplayMetrics поставляется со всем необходимым и работает с API 1.

public void getScreenInfo(){
    DisplayMetrics metrics = new DisplayMetrics();
    getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);

    heightPixels = metrics.heightPixels;
    widthPixels = metrics.widthPixels;
    density = metrics.density;
    densityDpi = metrics.densityDpi;
}

Вы также можете получить фактическое отображение (включая декоры экрана, такие как строка состояния или панель программного обеспечения), используя getRealMetrics , но это работает только на 17+.

Я что-то пропустил?

Дэвид Корсалини
источник
1
Это не вычитание пространства для элементов управления на экране (например, на планшетах или устройствах Nexus). Кроме того, я получаю другое значение (750 против 800) на своем 10-дюймовом планшете, в зависимости от того, активна ли активность после завершения расчета. Но для моих целей это более чем хорошо. Спасибо!
Стивен Л
15

Просто добавлю к ответу Франческо. Другим более подходящим наблюдателем, если вы хотите узнать местоположение в окне или местоположение на экране, является ViewTreeObserver.OnPreDrawListener ()

Это также может быть использовано для поиска других атрибутов представления, которые в основном неизвестны во время onCreate (), например прокручиваемая позиция, масштабированная позиция.

pellucide
источник
15

Используя следующий код в Activity.

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int wwidth = metrics.widthPixels;
Виноткумар Арпутарадж
источник
15

Найдите ширину и высоту экрана:

width = getWindowManager().getDefaultDisplay().getWidth();
height = getWindowManager().getDefaultDisplay().getHeight();

Используя это, мы можем получить последнюю версию SDK 13 и выше.

// New width and height
int version = android.os.Build.VERSION.SDK_INT;
Log.i("", " name == "+ version);
Display display = getWindowManager().getDefaultDisplay();
int width;
if (version >= 13) {
    Point size = new Point();
    display.getSize(size);
    width = size.x;
    Log.i("width", "if =>" +width);
}
else {
    width = display.getWidth();
    Log.i("width", "else =>" +width);
}
NagarjunaReddy
источник
15
DisplayMetrics dimension = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dimension);
int w = dimension.widthPixels;
int h = dimension.heightPixels;
Кристиана Чавес
источник
12

Я нашел, что сделал свое дело.

Rect dim = new Rect();
getWindowVisibleDisplayFrame(dim);
Джастин
источник
5
Круто, но одна страшная вещь об этом методе в исходном коде: этот комментарий
Норберт
12

Нужно сказать, что если вы не в Activity, а в View(или у вас есть переменная Viewтипа в вашей области видимости), нет необходимости использовать WINDOW_SERVICE. Тогда вы можете использовать как минимум два способа.

Первый:

DisplayMetrics dm = yourView.getContext().getResources().getDisplayMetrics();

Во-вторых:

DisplayMetrics dm = new DisplayMetrics();
yourView.getDisplay().getMetrics(dm);

Все эти методы, которые мы здесь называем, не устарели.

Сергей Пикалев
источник
12
public class AndroidScreenActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        String str_ScreenSize = "The Android Screen is: "
                                   + dm.widthPixels
                                   + " x "
                                   + dm.heightPixels;

        TextView mScreenSize = (TextView) findViewById(R.id.strScreenSize);
        mScreenSize.setText(str_ScreenSize);
    }
}
Шоаиб Ахмед
источник
12

Для получения размеров экрана используйте отображение метрик

DisplayMetrics displayMetrics = new DisplayMetrics();
if (context != null) 
      WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
      Display defaultDisplay = windowManager.getDefaultDisplay();
      defaultDisplay.getRealMetrics(displayMetrics);
    }

Получите высоту и ширину в пикселях

int width  =displayMetrics.widthPixels;
int height =displayMetrics.heightPixels;
Шарат Кумар
источник
9

Это не ответ для ОП, так как он хотел, чтобы размеры дисплея были в реальных пикселях. Я хотел размеры в «независимых от устройства пикселях», и собирал ответы отсюда https://stackoverflow.com/a/17880012/253938 и вот https://stackoverflow.com/a/6656774/253938 Я подошел с этим:

    DisplayMetrics displayMetrics = Resources.getSystem().getDisplayMetrics();
    int dpHeight = (int)(displayMetrics.heightPixels / displayMetrics.density + 0.5);
    int dpWidth = (int)(displayMetrics.widthPixels / displayMetrics.density + 0.5);
RenniePet
источник
9

Вы можете получить размер высоты, используя:

getResources().getDisplayMetrics().heightPixels;

и размер ширины с помощью

getResources().getDisplayMetrics().widthPixels; 
Jéwôm»
источник
8

Существует не осуждаемый способ сделать это с помощью DisplayMetrics (API 1), который позволяет избежать путаницы в попытках / отлове:

 // initialize the DisplayMetrics object
 DisplayMetrics deviceDisplayMetrics = new DisplayMetrics();

 // populate the DisplayMetrics object with the display characteristics
 getWindowManager().getDefaultDisplay().getMetrics(deviceDisplayMetrics);

 // get the width and height
 screenWidth = deviceDisplayMetrics.widthPixels;
 screenHeight = deviceDisplayMetrics.heightPixels;
paulrehkugler
источник
8

Я бы обернул код getSize следующим образом:

@SuppressLint("NewApi")
public static Point getScreenSize(Activity a) {
    Point size = new Point();
    Display d = a.getWindowManager().getDefaultDisplay();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        d.getSize(size);
    } else {
        size.x = d.getWidth();
        size.y = d.getHeight();
    }
    return size;
}
Саймон
источник
Это происходит сбой на эмуляторе под управлением Android 4.0 (API 14).
jww
6

Для тех, кто ищет полезные размеры экрана без строки состояния и панели действий (также благодаря ответу Swapnil):

DisplayMetrics dm = getResources().getDisplayMetrics();
float screen_w = dm.widthPixels;
float screen_h = dm.heightPixels;

int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resId > 0) {
    screen_h -= getResources().getDimensionPixelSize(resId);
}

TypedValue typedValue = new TypedValue();
if(getTheme().resolveAttribute(android.R.attr.actionBarSize, typedValue, true)){
    screen_h -= getResources().getDimensionPixelSize(typedValue.resourceId);
}
Франческо Вадикамо
источник
6

Сначала загрузите файл XML, а затем напишите этот код:

setContentView(R.layout.main);      
Display display = getWindowManager().getDefaultDisplay();
final int width = (display.getWidth());
final int height = (display.getHeight());

Показать ширину и высоту в соответствии с вашим разрешением экрана.

Дуггу
источник
6

Следуйте методам ниже:

public static int getWidthScreen(Context context) {
    return getDisplayMetrics(context).widthPixels;
}

public static int getHeightScreen(Context context) {
    return getDisplayMetrics(context).heightPixels;
}

private static DisplayMetrics getDisplayMetrics(Context context) {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    wm.getDefaultDisplay().getMetrics(displayMetrics);
    return displayMetrics;
}
sonida
источник
6

Котлин

fun getScreenHeight(activity: Activity): Int {
    val metrics = DisplayMetrics()
    activity.windowManager.defaultDisplay.getMetrics(metrics)
    return metrics.heightPixels
}

fun getScreenWidth(activity: Activity): Int {
    val metrics = DisplayMetrics()
    activity.windowManager.defaultDisplay.getMetrics(metrics)
    return metrics.widthPixels
}
Khemraj
источник
5

Есть моменты, когда вам нужно знать точные размеры доступного пространства для макета в onCreate действия. После некоторых размышлений я разработал этот способ сделать это.

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        startActivityForResult(new Intent(this, Measure.class), 1);
        // Return without setting the layout, that will be done in onActivityResult.
    }

    @Override
    protected void onActivityResult (int requestCode, int resultCode, Intent data) {
        // Probably can never happen, but just in case.
        if (resultCode == RESULT_CANCELED) {
            finish();
            return;
        }
        int width = data.getIntExtra("Width", -1);
        // Width is now set to the precise available width, and a layout can now be created.            ...
    }
}

public final class Measure extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
       // Create a LinearLayout with a MeasureFrameLayout in it.
        // Just putting a subclass of LinearLayout in works fine, but to future proof things, I do it this way.
        LinearLayout linearLayout = new LinearLayout(this);
        LinearLayout.LayoutParams matchParent = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
        MeasureFrameLayout measureFrameLayout = new MeasureFrameLayout(this);
        measureFrameLayout.setLayoutParams(matchParent);
        linearLayout.addView(measureFrameLayout);
        this.addContentView(linearLayout, matchParent);
        // measureFrameLayout will now request this second activity to finish, sending back the width.
    }

    class MeasureFrameLayout extends FrameLayout {
        boolean finished = false;
        public MeasureFrameLayout(Context context) {
            super(context);
        }

        @SuppressLint("DrawAllocation")
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            if (finished) {
                return;
            }
            finished = true;
            // Send the width back as the result.
            Intent data = new Intent().putExtra("Width", MeasureSpec.getSize(widthMeasureSpec));
            Measure.this.setResult(Activity.RESULT_OK, data);
            // Tell this activity to finish, so the result is passed back.
            Measure.this.finish();
        }
    }
}

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

public class MainActivity extends Activity {
    static Activity measuringActivity;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        Bundle extras = getIntent().getExtras();
        if (extras == null) {
            extras = new Bundle();
        }
        int width = extras.getInt("Width", -2);
        if (width == -2) {
            // First time in, just start another copy of this activity.
            extras.putInt("Width", -1);
            startActivityForResult(new Intent(this, MainActivity.class).putExtras(extras), 1);
            // Return without setting the layout, that will be done in onActivityResult.
            return;
        }
        if (width == -1) {
            // Second time in, here is where the measurement takes place.
            // Create a LinearLayout with a MeasureFrameLayout in it.
            // Just putting a subclass of LinearLayout in works fine, but to future proof things, I do it this way.
            LinearLayout linearLayout = new LinearLayout(measuringActivity = this);
            LinearLayout.LayoutParams matchParent = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            MeasureFrameLayout measureFrameLayout = new MeasureFrameLayout(this);
            measureFrameLayout.setLayoutParams(matchParent);
            linearLayout.addView(measureFrameLayout);
            this.addContentView(linearLayout, matchParent);
            // measureFrameLayout will now request this second activity to finish, sending back the width.
        }
    }

    @Override
    protected void onActivityResult (int requestCode, int resultCode, Intent data) {
        // Probably can never happen, but just in case.
        if (resultCode == RESULT_CANCELED) {
            finish();
            return;
        }
        int width = data.getIntExtra("Width", -3);
        // Width is now set to the precise available width, and a layout can now be created. 
        ...
    }

class MeasureFrameLayout extends FrameLayout {
    boolean finished = false;
    public MeasureFrameLayout(Context context) {
        super(context);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (finished) {
            return;
        }
        finished = true;
        // Send the width back as the result.
        Intent data = new Intent().putExtra("Width", MeasureSpec.getSize(widthMeasureSpec));
        MainActivity.measuringActivity.setResult(Activity.RESULT_OK, data);
        // Tell the (second) activity to finish.
        MainActivity.measuringActivity.finish();
    }
}    
Стив Уоринг
источник
Очевидно, вы также можете передать высоту в связке.
Стив Уоринг,
5

Если вам не нужны служебные данные WindowManager, Points или Displays, вы можете получить атрибуты высоты и ширины самого верхнего элемента View в XML-файле, если для его высоты и ширины установлено значение match_parent. (Это верно, если ваш макет занимает весь экран.)

Например, если ваш XML начинается примерно так:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/entireLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

Затем findViewById(R.id.entireLayout).getWidth()вернет ширину экрана и findViewById(R.id.entireLayout).getHeight()вернет высоту экрана.

christinac
источник