bagaimana cara mendapatkan ukuran layar android secara terprogram, sekali dan untuk semua?

132

Bagaimana saya bisa mengetahui ukuran layar saya secara terprogram, dalam unit yang digunakan oleh acara sentuh dan Lihat pengukuran / tata letak? Dengan kata lain, saya ingin koordinat sudut kanan bawah layar, dalam sistem koordinat yang digunakan oleh event sentuh getRawX()/getRawY()dan View.getLocationOnScreen().

Saya ragu untuk memanggil unit acara / tampilan yang diinginkan "piksel" karena ternyata ada beberapa gagasan "piksel" pada ponsel saya dalam berbagai mode, dan mereka tidak menambahkan cerita yang konsisten.

Saya melihat ini telah ditanyakan dan banyak dijawab di stackoverflow dan di tempat lain, tetapi tidak ada jawaban yang benar-benar berfungsi pada ponsel saya (droid 4, android 4.1.2) di semua mode:

(Wow!)

Ini untuk kode pustaka yang perlu bekerja terlepas dari apakah aplikasi dalam "mode kompatibilitas layar" (mis. TargetSdkVersion <= 10 dalam manifes) atau tidak, dan saya juga tidak ingin membuat asumsi tentang posisi, ukuran , atau keberadaan bilah status atau dekorasi layar serupa lainnya.


Berikut ini faktanya:

  1. telepon saya (droid 4 yang menjalankan Android 4.1.2) memiliki 540x960 piksel fisik, yaitu titik-titik bercahaya kecil berwarna.

  2. ukuran layar di unit yang diinginkan, dari melihat acara sentuh dan Lihat pengukuran, adalah 360x640 ketika aplikasi dalam mode compat layar, 540x960 ketika aplikasi tidak dalam mode compat layar. Ini adalah angka yang harus saya temukan secara terprogram, tanpa mucking dengan acara sentuh atau Tampilan untuk menemukannya, tapi saya mengalami kesulitan yang sangat besar untuk menemukan API yang akan mengembalikan angka-angka ini.

  3. Obyek Display dan DisplayMetrics diperoleh dengan berbagai cara, semuanya mengklaim ukuran layar adalah 540x960 "piksel" (baik dalam mode compat layar atau tidak). Untuk lebih spesifik, semua yang berikut mengatakan 540x960 setiap saat: DisplayMetrics. {Width, height} Pixels, Display.getSize (), Display.getRealSize (), Display.get {Lebar, Tinggi} (),

  4. Objek konfigurasi yang diperoleh dengan berbagai cara semuanya mengatakan layar {Width, Height} Dp = 360x614 (baik dalam mode compat layar atau tidak). Saya tidak percaya itu mewakili seluruh layar, karena rasio aspeknya salah. (Saya pikir ini adalah seluruh layar dikurangi status bar; Saya perlu seluruh layar.) Saya pikir aman untuk mengatakan bahwa seluruh layar adalah 360x640 dp, meskipun saya tidak tahu ada API yang mengembalikan itu 640.

  5. DisplayMetrics diperoleh dengan berbagai cara mengatakan "densitas" adalah 1.0f ketika dalam mode compat layar, 1.5f ketika tidak dalam mode compat layar.

  6. Kegiatan getWindow().getAttributes().{width,height} ini tidak membantu karena biasanya berisi MATCH_PARENT daripada ukuran sebenarnya. Tapi saya rupanya bisa mendapatkan jawaban yang diinginkan dari suatu aktivitas getWindow().getDecorView().getMeasured{Width,Height}() (yang sebenarnya mengejutkan karena dekorasi tampilan jendela aktivitas itu tidak terlihat seperti mengambil seluruh layar; sepertinya mengambil layar dikurangi bar status). Tapi saya tidak ingin bergantung pada ini karena jika jendela pernah diubah ukurannya (keyboard lunak muncul? Seseorang memanggil window.setAttributes ()? Atau mungkin saya tidak dalam suatu Kegiatan sama sekali), ini jelas akan menjadi semua salah.

Saya memahami rumus berikut yang seharusnya dipegang: piksel = dp * kerapatan Yang tampaknya sesuai dengan semua angka yang dilaporkan ((3), (4), (5) di atas) ketika tidak dalam mode kompatibilitas layar: 540x960 = 360x640 * 1.5 Tetapi dalam mode kompatibilitas layar itu tidak bertambah: 540x960! = 360x640 * 1 Jadi, ada sesuatu yang salah.

Penjelasan yang paling sederhana, saya pikir, adalah bahwa metode yang tercantum dalam (3) di atas hanya memberikan jawaban yang salah untuk "piksel" ketika dalam mode compat layar - yaitu, mereka dimaksudkan untuk mengembalikan 360x640 "piksel" tetapi mereka salah mengembalikan 540x960 sebagai gantinya. Tapi mungkin ada cara lain untuk melihatnya.

Bagaimanapun, mendapatkan angka yang diinginkan terlepas dari mode, dari potongan puzzle di atas, tentu saja merupakan teka-teki yang rumit. Saya telah menemukan cara yang tampaknya berfungsi pada ponsel saya di kedua mode, tetapi sangat berputar-putar, dan bergantung pada dua asumsi yang masih tampak agak goyah (seperti yang dijelaskan dalam komentar kode di bawah).

Ini resep saya:

/** 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);
}

Apakah ada cara yang lebih baik / lebih bersih untuk menemukan ukuran layar ??

Don Hatch
sumber
29
+1 Pertanyaan bagus, dan menunjukkan banyak upaya penelitian.
Alex Gittemeier
1
@Don Dalam dokumen , dijelaskan bahwa mode kompatibilitas akan berhenti melakukan operasi "zoom to fit" pada pengaturan yang lebih lama. Namun tidak dijelaskan dengan jelas "cara kerjanya", dari pengamatan Anda, saya pikir mereka hanya mematikan penskalaan kepadatan, yaitu: 1px menjadi 1dp. Mungkin saja perubahan ini hanya di bagian render, dan DisplayMetricstidak pernah diperbarui dari perubahan tersebut. Ada masalah seperti ini sudah diajukan.
SD
@ user117 - menarik. Yah bagian dari DisplayMetrics mendapat pembaruan setidaknya - kepadatan berubah menjadi 1,0. Tapi sepertinya widthPixels / heightPixels tidak cocok. Mengenai masalah yang dikutip, sepertinya perilaku tersebut dikembalikan ke perilaku 3.1 (yaitu saya melihat heightPixels menyertakan bilah status ... tetapi di unit yang salah tampaknya)
Don Hatch
@ DonHatch Terima kasih, baiklah - saya benar-benar mencoba untuk memuji pertanyaan yang masuk akal anehnya tidak begitu diterima di StackExchange - perhatikan bagaimana pertanyaan menjadi lebih dari "nyata" tidak mendapat jawaban, berbicara tentang (rendah) ) kualitas pengetahuan audiens tentang topik tersebut. Sekarang, saya mungkin trauma dengan pertanyaan saya sendiri yang ditutup satu demi satu karena menjadi "tidak nyata", dan selera humor mungkin mengecewakan saya, tetapi itu mulai tampak seperti pertanyaan yang ada jawaban "bagus" yang bisa diterima. tentang apa semua ini terjadi di sini ... Dan tentu saja, saya
membesarkan
btw! inilah sesuatu di sepanjang garis kecurigaan saya: michael.richter.name/blogs/… (esp. lihat poinnya (1), yang pada jawaban yang dibuat dengan cepat - sebenarnya hanya halnya dengan Q ini!). Selamat NY, lagian (punyaku datang dalam 11 menit)! :)
mlvljr

Jawaban:

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

Sekarang Anda dapat mengukur ukuran layar Anda dalam piksel yang merupakan satuan pengukuran yang lebih baik daripada sentimeter karena semua tombol, tampilan teks dll. Diukur dalam unit ini. Itu yang saya gunakan secara normal

Cobra47
sumber
3
Menurut Op (poin # 3 secara khusus), bukankah ini tidak benar dalam mode compat layar?
Tom
9

Dengan menggunakan DisplayMetrics Anda bisa mendapatkan tinggi dan lebar layar perangkat apa pun. Perhatikan bahwa lebar dan tinggi sensitif terhadap rotasi. ini kodenya.

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

Di Metode onCreate Anda

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

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

Coba ini.

Preet_Android
sumber
2
tidak, seperti yang saya katakan di (3), metrik. {width, height} Pixels tidak memberikan jawaban yang benar ketika dalam mode kompatibilitas layar.
Don Hatch
Saya juga menemukan: Tampaknya lite metrics.heightPixels mungkin memberikan lebar seandainya layar diputar dan sebaliknya!
JohnyTex
8

Di # 6 Anda, Anda perhatikan bahwa DecorView tampaknya menyediakan apa yang Anda inginkan, tetapi Anda tidak berpikir itu bisa diterima. Saya percaya itu sedekat yang Anda bisa. Menurut dokumentasi untuk Window.getDecorView:

Ambil tampilan dekorasi jendela tingkat atas (berisi bingkai / dekorasi jendela standar dan konten klien di dalamnya), yang dapat ditambahkan sebagai jendela ke manajer jendela.

Bilah status adalah bagian dari dekorasi jendela yang disebutkan di sana. Keyboard perangkat lunak dan overlay lainnya akan menerima jendela mereka sendiri, sehingga mereka tidak boleh mengganggu nilai-nilai yang relevan. Benar bahwa metrik tampilan tidak tepat, tetapi jika aplikasi Anda layar penuh itu harus selalu ukuran layar penuh yang difilter melalui penerjemah kompatibilitas. Aplikasi lain tidak akan memiliki akses ke aplikasi Anda Window, jadi tidak perlu khawatir tentang beberapa aplikasi lain yang mengubah atribut saat Anda tidak melihat.

Semoga itu bisa membantu.

Dave
sumber
5

Saya harus meletakkan ini sebagai komentar tetapi saya tidak memiliki perwakilan untuk itu.
Ini mungkin bukan jawaban yang sepenuhnya benar tetapi saya mendapatkan dimensi saya ketika saya mengganti tinggi dan lebar dalam metode DisplayMetrics.

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

seperti yang saya katakan ini mungkin tidak benar tetapi saya tidak tahu mengapa tetapi itu berhasil untuk saya.

abhyudayasrinet
sumber
Ini karena layar Anda telah diputar saya percaya.
JohnyTex
Itu tidak percaya padaku.
abhyudayasrinet
3

Jika Anda menggunakan api level 17 atau lebih tinggi, periksa getRealMetrics dan getRealSize di Display

Untuk api level 14,15 & 16 lihat di sini

Keluar
sumber
3

Saya telah menggunakan teorema Pythagoras untuk menemukan ukuran diagonal layar ponsel / tablet Android, prinsip yang sama dapat diterapkan pada layar iPhone atau 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

Pythagoras pasti genios, dia tahu pemrograman ponsel pintar bertahun-tahun yang lalu: hlm

Naeem A. Malik
sumber
1

Saya menggunakan metode di bawah ini untuk mendapatkan lebar perangkat:

public static int getDeviceWidth(Context context){
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    int width=display.getWidth();
    return width;
}
Ghanshyam Patidar
sumber
Metode ini sudah usang. Silakan gunakan metode displaymetrics.
Simon
0

Saya pikir fungsi ini akan membantu Anda untuk hanya mendapatkan lebar dan tinggi ukuran layar android Anda. Fungsi mengembalikan lebar dan tinggi sebagai array bilangan bulat seperti yang ditunjukkan di bawah ini

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;

    }

dan pada metode create Anda, output lebar dan tinggi Anda seperti yang ditunjukkan di bawah ini

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

Unduh kode sumber dan uji di studio android Anda

Daniel Nyamasyo
sumber
0

Ini bekerja untuk saya:

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

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

Saya menggunakan ini untuk memperbarui lebar barang saya dalam tampilan pendaur ulang horizontal. (Sesuai dengan kebutuhan saya) Semoga bermanfaat!

Gagan Deep
sumber
-1

Untuk solusi ini di Kotlin , coba ini:

private fun yourFunction(){
   val metrics = DisplayMetrics()
   windowManager.defaultDisplay.getMetrics(metrics)
   val width = metrics.widthPixels
   val height = metrics.heightPixels
}
Sup.Ia
sumber