วิธีรับขนาดหน้าจอ Android โดยทางโปรแกรมครั้งแล้วครั้งเล่า


132

ฉันจะทราบขนาดหน้าจอโดยใช้โปรแกรมในหน่วยที่ใช้โดยเหตุการณ์การสัมผัสและดูการวัด / เค้าโครงได้อย่างไร ในคำอื่น ๆ ที่ฉันต้องการพิกัดของมุมขวาล่างของหน้าจอในระบบพิกัดที่ใช้โดยกิจกรรมสัมผัส และgetRawX()/getRawY()View.getLocationOnScreen()

ฉันลังเลที่จะเรียกหน่วยเหตุการณ์ / มุมมองที่ต้องการว่า "พิกเซล" เนื่องจากเห็นได้ชัดว่าโทรศัพท์ของฉันมี "พิกเซล" หลายแบบในโหมดต่างๆและไม่ได้รวมเข้ากับเรื่องราวที่สอดคล้องกัน

ฉันเห็นว่ามีการถามและตอบคำถามมากมายใน stackoverflow และที่อื่น ๆ แต่ไม่มีคำตอบใดที่ใช้งานได้จริงบนโทรศัพท์ของฉัน (droid 4, android 4.1.2) ในทุกโหมด:

(ว้าว!)

นี่คือรหัสไลบรารีที่ต้องทำงานไม่ว่าแอปจะอยู่ใน "โหมดความเข้ากันได้ของหน้าจอ" (เช่น targetSdkVersion <= 10 ในไฟล์ Manifest) หรือไม่ก็ตามและฉันก็ไม่ต้องการตั้งสมมติฐานใด ๆ เกี่ยวกับตำแหน่งขนาด หรือการมีอยู่ของแถบสถานะหรือการตกแต่งหน้าจออื่น ๆ ที่คล้ายกัน


นี่คือข้อเท็จจริง:

  1. โทรศัพท์ของฉัน (droid 4 ที่ใช้ Android 4.1.2) มีพิกเซลจริง 540x960 นั่นคือจุดเรืองแสงสีเล็ก ๆ

  2. ขนาดของหน้าจอในหน่วยที่ต้องการจากการดูเหตุการณ์การสัมผัสและดูการวัดคือ 360x640 เมื่อแอปอยู่ในโหมดใช้งานร่วมกับหน้าจอ 540x960 เมื่อแอปไม่ได้อยู่ในโหมดใช้งานร่วมกับหน้าจอ นี่คือตัวเลขที่ฉันต้องหาโดยใช้โปรแกรมโดยไม่ต้องยุ่งกับเหตุการณ์การสัมผัสหรือมุมมองเพื่อค้นหา แต่ฉันมีปัญหาอย่างมากในการค้นหา API ใด ๆ ที่จะส่งคืนตัวเลขเหล่านี้

  3. วัตถุ Display และ DisplayMetrics ที่ได้รับด้วยวิธีต่างๆล้วนอ้างว่าขนาดหน้าจอคือ 540x960 "พิกเซล" (ไม่ว่าจะอยู่ในโหมดการใช้งานร่วมกับหน้าจอหรือไม่ก็ตาม) เพื่อให้เฉพาะเจาะจงสิ่งต่อไปนี้ทั้งหมดกล่าวว่า 540x960 ตลอดเวลา: DisplayMetrics. {width, height} Pixels, Display.getSize (), Display.getRealSize (), Display.get {Width, Height} (),

  4. ออบเจ็กต์การกำหนดค่าที่ได้รับในรูปแบบต่างๆล้วนกล่าวว่าหน้าจอ {ความกว้างความสูง} Dp = 360x614 (ไม่ว่าจะอยู่ในโหมดใช้งานร่วมกับหน้าจอหรือไม่ก็ตาม) ฉันไม่เชื่อว่านั่นแสดงถึงทั้งหน้าจอเนื่องจากอัตราส่วนภาพไม่ถูกต้อง (ฉันคิดว่ามันเป็นทั้งหน้าจอลบแถบสถานะฉันต้องการทั้งหน้าจอ) ฉันคิดว่ามันปลอดภัยที่จะบอกว่าทั้งหน้าจอคือ 360x640 dp แม้ว่าฉันจะไม่รู้จัก API ใด ๆ ที่ส่งคืน 640 นั้น

  5. DisplayMetrics ที่ได้รับในรูปแบบต่างๆกล่าวว่า "ความหนาแน่น" คือ 1.0f เมื่ออยู่ในโหมดใช้งานร่วมกับหน้าจอ 1.5f เมื่อไม่ได้อยู่ในโหมดใช้งานร่วมกับหน้าจอ

  6. กิจกรรม getWindow().getAttributes().{width,height} นี้ไม่มีประโยชน์เนื่องจากโดยทั่วไปจะมีMATCH_PARENT มากกว่าขนาดจริง แต่ผมเห็นได้ชัดว่าสามารถได้คำตอบที่ต้องการจากกิจกรรมของ getWindow().getDecorView().getMeasured{Width,Height}() (ซึ่งจริง ๆ แล้วน่าแปลกใจเพราะหน้าต่างกิจกรรมของ decorView ไม่ได้มีลักษณะเหมือนมันจะขึ้นหน้าจอทั้งหมดมันดูเหมือนว่ามันจะขึ้นหน้าจอลบแถบสถานะ) แต่ฉันไม่ต้องการพึ่งพาสิ่งนี้เพราะถ้าหน้าต่างเคยถูกปรับขนาด (แป้นพิมพ์อ่อนปรากฏขึ้นมีคนเรียก 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 คำถามที่ดีและแสดงให้เห็นถึงความพยายามในการค้นคว้าอย่างมาก
Alex Gittemeier

1
@Don ในเอกสารอธิบายว่าโหมดความเข้ากันได้จะหยุดการดำเนินการ "ซูมให้พอดี" ในการตั้งค่ารุ่นเก่า อย่างไรก็ตามมันไม่ได้อธิบายอย่างชัดเจนว่า "มันทำงานอย่างไร" จากการสังเกตของคุณฉันคิดว่าพวกเขาเพียงแค่ปิดการปรับขนาดความหนาแน่นนั่นคือ: 1px กลายเป็น 1dp อาจเป็นไปได้ว่าการเปลี่ยนแปลงนี้เป็นเพียงส่วนการแสดงผลและDisplayMetricsจะไม่มีการอัปเดตการเปลี่ยนแปลงดังกล่าว มีประเด็นเช่นนี้ยื่นฟ้องแล้ว
SD

@ user117 - น่าสนใจ ดีเป็นส่วนหนึ่งของ DisplayMetrics ได้ปรับปรุงความหนาแน่น least-- เปลี่ยนไปเป็น 1.0 แต่ widthPixels / heightPixels ไม่ได้รับการเปลี่ยนแปลงให้ตรงกัน เกี่ยวกับปัญหาที่อ้างถึงดูเหมือนว่าพฤติกรรมจะเปลี่ยนกลับเป็นพฤติกรรม 3.1 (เช่นฉันเห็น heightPixels มีแถบสถานะ ... แต่ดูเหมือนว่าจะผิดหน่วย)
Don Hatch

@DonHatch ขอบคุณ - จริง ๆ แล้วฉันพยายามที่จะสรรเสริญคำถามที่มีความคิดแปลก ๆ ที่ StackExchange ไม่ค่อยได้รับการต้อนรับ - สังเกตว่าคำถามที่มากกว่า "ของจริง" ไม่ได้รับอะไรเลยในคำตอบการพูดถึง (ต่ำ ) คุณภาพของความรู้ของผู้ชมในหัวข้อ ตอนนี้ฉันอาจจะรู้สึกชอกช้ำกับคำถามของตัวเองที่ถูกปิดลงทีละคำถามเพราะ "ไม่จริง" และอารมณ์ขันอาจทำให้ฉันล้มเหลว แต่มันเริ่มดูเหมือนคำถามที่มีคำตอบที่ "น่ารัก" จริงๆ ทั้งหมดนี้จะเป็นอย่างไร ... และแน่นอนฉันโหวตให้คุณ :)
mlvljr

ครับ! นี่คือบางสิ่งบางอย่างตามแนวความสงสัยของฉัน: michael.richter.name/blogs/… (โดยเฉพาะดูจุด (1) ของเขาซึ่งเป็นคำตอบที่สร้างขึ้นอย่างรวดเร็ว - จริง ๆ แล้วในกรณีของ Q นี้!) Happy NY ยังไงก็ได้ (ของฉันมาใน 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} Pixels ไม่ได้ให้คำตอบที่ถูกต้องเมื่ออยู่ในโหมดความเข้ากันได้ของหน้าจอ
ดอนฟัก

ฉันค้นพบด้วย: ดูเหมือนว่าเมตริก Lite ความสูงอาจให้ความกว้างในกรณีที่หน้าจอหมุนและในทางกลับกัน!
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

ฉันใช้ทฤษฎีบท Pythagoras เพื่อค้นหาขนาดเส้นทแยงมุมของหน้าจอโทรศัพท์ / แท็บเล็ต 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

Pythagoras ต้องเป็น genios เขารู้จักการเขียนโปรแกรมสมาร์ทโฟนเมื่อหลายปีก่อน: p


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;
}

วิธีนี้เลิกใช้แล้ว โปรดใช้วิธี displaymetrics
Simon

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);

ดาวน์โหลดซอร์สโค้ดและทดสอบบนสตูดิโอ Android ของคุณ


0

สิ่งนี้ใช้ได้กับฉัน:

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

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

ฉันใช้สิ่งนี้เพื่ออัปเดตความกว้างของรายการของฉันในมุมมองรีไซเคิลแนวนอน (ตามความต้องการของฉัน) หวังว่าจะช่วยใครสักคน!


-1

สำหรับวิธีแก้ปัญหานี้ในKotlinให้ลองทำดังนี้:

private fun yourFunction(){
   val metrics = DisplayMetrics()
   windowManager.defaultDisplay.getMetrics(metrics)
   val width = metrics.widthPixels
   val height = metrics.heightPixels
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.