як отримати розмір екрану для Android програмно, раз і назавжди?


132

Як я можу програмно визначити розмір екрана в одиницях, використовуваних сенсорними подіями та Переглядати вимірювання / макет? Іншими словами, я хочу, щоб координати нижнього правого кута екрану в системі координат використовувались сенсорні події ' getRawX()/getRawY()та View.getLocationOnScreen().

Я не вагаюся називати потрібні події / одиниці перегляду "пікселями", оскільки, очевидно, на моєму телефоні існує декілька понять "пікселі" в різних режимах, і вони не додають до послідовної історії.

Я бачу, що про це багато запитували і відповіли в stackoverflow та інших місцях, але жодна з відповідей насправді не працює на моєму телефоні (droid 4, android 4.1.2) у всіх режимах:

(Ого!)

Це для коду бібліотеки, який повинен працювати незалежно від того, перебуває програма в "режимі сумісності екрана" (тобто targetSdkVersion <= 10 в маніфесті) чи ні, і я також не хочу робити жодних припущень щодо позиції, розміру або наявність рядка стану чи будь-яких інших подібних прикрас екрана.


Ось факти:

  1. мій телефон (дроїд 4 під керуванням Android 4.1.2) має 540x960 фізичних пікселів, тобто маленькі кольорові світяться точки.

  2. розмір екрана в потрібних одиницях - від перегляду подій на дотик та перегляду вимірювань - 360x640, коли додаток перебуває в режимі екранного компата, 540x960, коли програма не перебуває в режимі екранного компата. Це номери, які мені потрібно знайти програмно, не зв'язуючись із подіями дотику чи Переглядами, щоб знайти їх, але у мене виникають великі труднощі з пошуком будь-якого API, який поверне ці числа.

  3. Об'єкти Display і DisplayMetrics, отримані різними способами, стверджують, що розмір екрана становить 540x960 "пікселів" (чи в режимі компактного екрану, чи ні). Щоб конкретизувати, весь час говорять про 540x960: DisplayMetrics. {Width, height} Пікселі, Display.getSize (), Display.getRealSize (), Display.get {Width, Height} (),

  4. Об'єкти конфігурації, отримані різними способами, всі говорять про екран {Width, Height} Dp = 360x614 (незалежно від того, чи є він у режимі екрана чи ні). Я не вірю, що це представляє весь екран, оскільки співвідношення сторін неправильне. (Я думаю, що це весь екран мінус статус стану; мені потрібен весь екран.) Я думаю, що можна впевнено сказати, що весь екран 360x640 dp, хоча я не знаю жодного API, який повертає цей 640.

  5. DisplayMetrics, отримані різними способами, кажуть, що "щільність" становить 1,0f, коли в режимі екранного компата, 1,5f, коли не в режимі екранного компат.

  6. Діяльність getWindow().getAttributes().{width,height} не корисна, оскільки зазвичай містить, MATCH_PARENT а не фактичні розміри. Але я можу отримати бажану відповідь від діяльності getWindow().getDecorView().getMeasured{Width,Height}() (що насправді дивно, оскільки декорView вікна діяльності не виглядає так, що він займає весь екран; схоже, що він займає екран за мінусом рядка стану). Але я не хочу на це покладатися, тому що якщо вікно коли-небудь буде змінено (з'являється м'яка клавіатура? Хтось викликає window.setAttributes ()? Або, можливо, я взагалі не перебуваю в активності), це, очевидно, буде все неправильно.

Я розумію, що повинна міститись наступна формула: пікселі = dp * щільність, яка, здається, узгоджується з усіма повідомленими числами ((3), (4), (5) вище), коли не перебуває в режимі сумісності екрана: 540x960 = 360x640 * 1,5 Але в режимі сумісності екрана він не додається: 540x960! = 360x640 * 1 Отже, щось не так.

Найпростіше пояснення, я думаю, полягає в тому, що методи, перелічені в (3) вище, просто дають неправильну відповідь для "пікселів", коли в режимі екранного компат - тобто вони мали на меті повернути 360x640 "пікселів", але вони неправильно повертаючи замість цього 540x960 Але можуть бути й інші способи погляду на це.

У будь-якому випадку, отримання бажаних чисел незалежно від режиму, з вищезазначених фрагментів головоломки, безумовно, хитра головоломка. Я знайшов спосіб, який, здається, працює на моєму телефоні в обох режимах, але він надзвичайно ланцюговий, і він спирається на два припущення, які все ще здаються досить хиткими (як описано в коментарях до коду нижче).

Ось мій рецепт:

/** get screen size in "pixels", i.e. touchevent/view units.
* on my droid 4, this is 360x640 or 540x960
* depending on whether the app is in screen compatibility mode
* (i.e. targetSdkVersion<=10 in the manifest) or not. */
public void getScreenSizePixels(int widthHeightInPixels[/*2*/])
{
    Resources resources = getResources();
    Configuration config = resources.getConfiguration();
    DisplayMetrics dm = resources.getDisplayMetrics();
    // Note, screenHeightDp isn't reliable
    // (it seems to be too small by the height of the status bar),
    // but we assume screenWidthDp is reliable.
    // Note also, dm.widthPixels,dm.heightPixels aren't reliably pixels
    // (they get confused when in screen compatibility mode, it seems),
    // but we assume their ratio is correct.
    double screenWidthInPixels = (double)config.screenWidthDp * dm.density;
    double screenHeightInPixels = screenWidthInPixels * dm.heightPixels / dm.widthPixels;
    widthHeightInPixels[0] = (int)(screenWidthInPixels + .5);
    widthHeightInPixels[1] = (int)(screenHeightInPixels + .5);
}

Чи є кращий / чистіший спосіб знайти розмір екрана ??


29
+1 Відмінне запитання та показує багато зусиль для дослідження.
Алекс Гіттемейер

1
@Don У документах пояснюється, що режим сумісності перестане робити "масштабування відповідно" для старих налаштувань. Однак з ваших спостережень не чітко пояснено "як це працює", я думаю, що вони просто відключають масштабування щільності, тобто: 1px стає 1dp. Можливо, ця зміна є лише частиною надання, і DisplayMetricsніколи не оновлюється такими змінами. Є такі питання , як це вже подали.
SD

@ user117 - цікаво. Добре частина DisplayMetrics оновилася принаймні-- щільність змінилася до 1,0. Але, схоже, ширинуПікселі / висотуПікселі не змінили, щоб відповідати. Що стосується цитованого питання, то схоже на те, що поведінка повернута до поведінки 3.1 (тобто я бачу висотуПікселі включають рядок стану ... але, як видається, у неправильних одиницях)
Дон Хетч

@DonHatch Спасибі, любезно - я насправді намагався висловити похвалу за продумане запитання про сорти, як це не дивно вітається на StackExchange. ) якість знань аудиторії з даної теми. Тепер мене можуть травмувати мої власні запитання, що закриваються одне за одним за те, що вони "не реальні", і почуття гумору може мені не підходити, але воно починає виглядати як запитання, на які є справді "приємні" відповіді. про що це все стає тут ... І звичайно, я підтримав ваше :)
mlvljr

btw! ось щось у відповідь на мої підозри: michael.richter.name/blogs/… (ес. див. його (1) пункт, той, що швидко опрацьований відповіді - насправді якраз у цьому питанні!). Зі святом, Нью-Йорк, все одно (мій приходить за 11 хвилин)! :)
mlvljr

Відповіді:


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

Тепер ви можете виміряти розмір екрана в пікселях, що є кращою одиницею вимірювання, ніж сантиметр, тому що всі кнопки, перегляд тексту тощо. Вимірюються в цій одиниці. Що я нормально використовую


3
Відповідно до Op (пункт №3 конкретно), чи не було це неправильно в режимі екранного співзвуччя?
Том

9

Використовуючи DisplayMetrics, ви можете отримати висоту та ширину екрана будь-якого пристрою. Зауважте, що ширина і висота чутливі до обертання. ось код.

DisplayMetrics metrics; 
int width = 0, height = 0;

У вашому методі onCreate

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

 height = Math.min(metrics.widthPixels, metrics.heightPixels); //height
 width = Math.max(metrics.widthPixels, metrics.heightPixels); //width

Спробуйте це.


2
ні, як я вже говорив у (3), метрики. {width, height} Пікселі не дають правильної відповіді в режимі сумісності екрана.
Дон Хетч

Також я виявив: Здається, що Lite metrics.heightPixels може надати ширину у випадку повернення екрану та навпаки!
JohnyTex

8

У своєму номері 6 ви зазначаєте, що DecorView, здається, забезпечує те, що ви хочете, але ви не вважаєте, що це надійно. Я вважаю, що це так близько, як ви можете підійти. Відповідно до документації для Window.getDecorView:

Отримайте вигляд декору вікна верхнього рівня (містить стандартну рамку вікна / прикраси та вміст клієнта всередині цього), який можна додати як вікно до менеджера вікон.

Рядок стану є частиною згадуваного там декору вікон. Клавіатури програмного забезпечення та інші накладки отримають власне вікно, тому вони не повинні перешкоджати відповідним значенням. Це правильно, що це не точно метричні показники відображення, але якщо ваша програма є повноекранною, це завжди повинен бути повноекранний розмір фільтра через перекладач сумісності. Інші програми не матимуть доступу до вашої програми Window, тому не потрібно турбуватися про те, щоб якісь інші програми змінювали атрибути, поки ви не шукаєте.

Сподіваюся, що це допомагає.


5

Я повинен поставити це як коментар, але у мене немає відповіді на це.
Це може бути не зовсім правильною відповіддю, але я отримав свої розміри, коли я перемикав висоту та ширину методом DisplayMetrics.

    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);   
    width = metrics.heightPixels;
    height = metrics.widthPixels;

як я вже сказав, це може бути невірним, але я не знаю, чому це працювало для мене.


Це тому, що ваш екран обертається, я вважаю.
JohnyTex

Мені це не довірили.
abhyudayasrinet

3

Якщо ви використовуєте api рівня 17 або вище, перевірте getRealMetrics та getRealSize на дисплеї

Для рівня api 14,15 & 16 дивіться тут


3

Я використовував теорему Піфагора, щоб знайти розмір діагоналі екрану телефону / планшета Android, таку саму головну можна застосувати до екрану iPhone або Blackberry.

DisplayMetrics met = new DisplayMetrics();                
this.getWindowManager().getDefaultDisplay().getMetrics(met);// get display metrics object
String strSize = 
new DecimalFormat("##.##").format(Math.sqrt(((met.widthPixels / met.xdpi) *
(met.widthPixels / met.xdpi)) +
((met.heightPixels / met.ydpi) * (met.heightPixels / met.ydpi))));
// using Dots per inches with width and height

Піфагор, мабуть, був генієм, він знав програмування смартфонів стільки років тому: с


1

Я використовую метод нижче, щоб отримати ширину пристрою:

public static int getDeviceWidth(Context context){
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    int width=display.getWidth();
    return width;
}

Цей метод застарілий. Будь ласка, використовуйте метод дисплейметрії.
Симон

0

Я думаю, що ця функція допоможе вам просто отримати ширину та висоту розміру екрана для Android. Функція повертає ширину та висоту у вигляді масиву цілих чисел, як показано нижче

private int[] getScreenSIze(){
        DisplayMetrics displaymetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
        int h = displaymetrics.heightPixels;
        int w = displaymetrics.widthPixels;

        int[] size={w,h};
        return size;

    }

а на методі створення виведіть свою ширину та висоту, як показано нижче

 int[] screenSize= getScreenSIze();
        int width=screenSize[0];
        int height=screenSize[1];
        screenSizes.setText("Phone Screen sizes \n\n  width = "+width+" \n Height = "+height);

Завантажте вихідний код і протестуйте його на андроїд-студії


0

Це працює для мене:

int width = Resources.getSystem (). getDisplayMetrics (). widthPixels;

int height = Resources.getSystem (). getDisplayMetrics (). heightPixels;

Я використовував це для оновлення ширини моїх елементів у горизонтальному перегляді. (Відповідно до моєї вимоги).


-1

Для цього рішення в Котліні спробуйте це:

private fun yourFunction(){
   val metrics = DisplayMetrics()
   windowManager.defaultDisplay.getMetrics(metrics)
   val width = metrics.widthPixels
   val height = metrics.heightPixels
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.