简体   繁体   English

如何在 Android 中以像素形式获取屏幕尺寸

[英]How to get screen dimensions as pixels in Android

I created some custom elements, and I want to programmatically place them to the upper right corner ( n pixels from the top edge and m pixels from the right edge).我创建了一些自定义元素,我想以编程方式将它们放置在右上角(距上边缘n像素,距右边缘m像素)。 Therefore I need to get the screen width and screen height and then set position:因此我需要获取屏幕宽度和屏幕高度,然后设置 position:

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

How do I get screenWidth and screenHeight in the main Activity?如何在主 Activity 中获取screenWidthscreenHeight

If you want the display dimensions in pixels you can use getSize :如果您想要以像素为单位的显示尺寸,您可以使用getSize

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

If you're not in an Activity you can get the default Display via WINDOW_SERVICE :如果您不在Activity您可以通过WINDOW_SERVICE获得默认Display

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

If you are in a fragment and want to acomplish this just use Activity.WindowManager (in Xamarin.Android) or getActivity().getWindowManager() (in java).如果您在片段中并想要完成此操作,只需使用 Activity.WindowManager(在 Xamarin.Android 中)或 getActivity().getWindowManager()(在 Java 中)。

Before getSize was introduced (in API level 13), you could use the getWidth and getHeight methods that are now deprecated:在引入getSize之前(在 API 级别 13 中),您可以使用现在已弃用的getWidthgetHeight方法:

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

For the use case, you're describing, however, a margin/padding in the layout seems more appropriate.但是,对于用例,您正在描述布局中的边距/填充似乎更合适。

Another way is: DisplayMetrics另一种方法是: DisplayMetrics

A structure describing general information about a display, such as its size, density, and font scaling.一种描述有关显示的一般信息的结构,例如其大小、密度和字体缩放。 To access the DisplayMetrics members, initialize an object like this:要访问 DisplayMetrics 成员,请像这样初始化一个对象:

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

We can use widthPixels to get information for:我们可以使用widthPixels来获取以下信息:

"The absolute width of the display in pixels." “显示的绝对宽度(以像素为单位)。”

Example:例子:

Log.d("ApplicationTagName", "Display width in px is " + metrics.widthPixels);

API level 30 update API 级别 30 更新

final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
 // Gets all excluding insets
 final WindowInsets windowInsets = metrics.getWindowInsets();
 Insets insets = windowInsets.getInsetsIgnoreVisibility(WindowInsets.Type.navigationBars()
         | WindowInsets.Type.displayCutout());

 int insetsWidth = insets.right + insets.left;
 int insetsHeight = insets.top + insets.bottom;

 // Legacy size that Display#getSize reports
 final Rect bounds = metrics.getBounds();
 final Size legacySize = new Size(bounds.width() - insetsWidth,
         bounds.height() - insetsHeight);

One way is:一种方法是:

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

It is deprecated, and you should try the following code instead.它已被弃用,您应该尝试使用以下代码。 The first two lines of code gives you the DisplayMetrics objecs.前两行代码为您提供DisplayMetrics对象。 This objects contains the fields like heightPixels , widthPixels .此对象包含诸如heightPixelswidthPixels类的字段。

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

Api level 30 update API 级别 30 更新

final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
 // Gets all excluding insets
 final WindowInsets windowInsets = metrics.getWindowInsets();
 Insets insets = windowInsets.getInsetsIgnoreVisibility(WindowInsets.Type.navigationBars()
         | WindowInsets.Type.displayCutout());

 int insetsWidth = insets.right + insets.left;
 int insetsHeight = insets.top + insets.bottom;

 // Legacy size that Display#getSize reports
 final Rect bounds = metrics.getBounds();
 final Size legacySize = new Size(bounds.width() - insetsWidth,
         bounds.height() - insetsHeight);

It may not answer your question, but it could be useful to know (I was looking for it myself when I came to this question) that if you need a View's dimension but your code is being executed when its layout has not been laid out yet (for example in onCreate() ) you can setup a ViewTreeObserver.OnGlobalLayoutListener with View.getViewTreeObserver().addOnGlobalLayoutListener() and put the relevant code that needs the view's dimension there.它可能无法回答您的问题,但知道(我在遇到这个问题时自己正在寻找它)可能很有用(例如在onCreate() )您可以使用View.getViewTreeObserver().addOnGlobalLayoutListener()设置一个ViewTreeObserver.OnGlobalLayoutListener并将需要视图维度的相关代码放在那里。 The listener's callback will be called when the layout will have been laid out.布局完成后,将调用侦听器的回调。

(2012 answer, may be out of date) If you want to support pre Honeycomb, you will need to put in backward compatibility prior to API 13. Something like: (2012 答案,可能已过时)如果您想支持蜂窝之前,则需要在 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();
}

Of course the deprecated methods will eventually be taken out of the the most recent SDKs, but while we still rely on most of our users having Android 2.1, 2.2 and 2.3, this is what we are left with.当然,弃用的方法最终会从最新的 SDK 中删除,但虽然我们仍然依赖大多数拥有 Android 2.1、2.2 和 2.3 的用户,但我们只剩下这些了。

I have tried all possible "solutions" unsuccessfully and I noticed that Elliott Hughes' "Dalvik Explorer" app always shows correct dimension on any Android device/OS version.我尝试了所有可能的“解决方案”都没有成功,我注意到 Elliott Hughes 的“Dalvik Explorer”应用程序在任何 Android 设备/操作系统版本上总是显示正确的尺寸。 I ended up looking at his open source project that can be found here: https://code.google.com/p/enh/我最终查看了他的开源项目,可以在这里找到: https : //code.google.com/p/enh/

Here's all the relevant code:这是所有相关代码:

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) {
}

EDIT: slightly improved version (avoid firing exceptions on non-supported OS version):编辑:稍微改进的版本(避免在不支持的操作系统版本上触发异常):

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) {
}

Simplest way:最简单的方法:

 int screenHeight = getResources().getDisplayMetrics().heightPixels;
 int screenWidth = getResources().getDisplayMetrics().widthPixels; 

For accessing the height of the status bar for Android devices, we prefer a programmatic way to get it:为了访问 Android 设备状态栏的高度,我们更喜欢以编程方式获取它:

Sample code示例代码

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

The variable result gives the height in the pixel.变量result给出了像素的高度。

For quick access为了快速访问

在此处输入图片说明

For more information about height of Title bar , Navigation bar and Content View , kindly look on Android Device Screen Sizes .有关Title barNavigation barContent View高度的更多信息,请查看Android 设备屏幕尺寸

首先获取视图(例如通过findViewById() ),然后您可以在视图本身上使用getWidth()

I have two functions, one for sending the context and the other getting height and width in pixels:我有两个函数,一个用于发送上下文,另一个用于以像素为单位获取高度和宽度:

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

and

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

For dynamically scaling using XML there is an attribute called "android:layout_weight"对于使用 XML 动态缩放,有一个名为“android:layout_weight”的属性

The below example, modified from synic's response on this thread , shows a button that takes up 75% of the screen (weight = .25) and a text view taking up the remaining 25% of the screen (weight = .75).下面的示例是从 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>

This is the code I use for the task:这是我用于任务的代码:

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

Seems clean enough and yet, takes care of the deprecation.看起来足够干净,但是,照顾了弃用。

Isn't this a much better solution?这不是更好的解决方案吗? DisplayMetrics comes with everything you need and works from API 1. 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;
}

You can also get the actual display (including screen decors, such as Status Bar or software navigation bar) using getRealMetrics , but this works on 17+ only.您还可以使用getRealMetrics获取实际显示(包括屏幕装饰,例如状态栏或软件导航栏),但这仅适用于 17+。

Am I missing something?我错过了什么吗?

Find width and height of the screen:查找屏幕的宽度和高度:

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

Using this, we can get the latest and above SDK 13.使用这个,我们可以获得最新及以上的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);
}
DisplayMetrics dimension = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dimension);
int w = dimension.widthPixels;
int h = dimension.heightPixels;

Just adding to Francesco's answer.只是添加到弗朗西斯科的答案。 The other observer that is more apt, if you want to find out the location in window or location in screen is ViewTreeObserver.OnPreDrawListener()另一个更贴切的观察者,如果你想找出窗口中的位置或屏幕中的位置是ViewTreeObserver.OnPreDrawListener()

This also can be used to find other attributes of a view that is mostly unknown at onCreate() time eg the scrolled position, the scaled position.这也可用于查找在 onCreate() 时大部分未知的视图的其他属性,例如滚动位置、缩放位置。

Using the following code in Activity.在 Activity 中使用以下代码。

DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
int wwidth = metrics.widthPixels;
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);
    }
}

Need to say, that if you are not in Activity , but in View (or have variable of View type in your scope), there is not need to use WINDOW_SERVICE .需要说的是,如果您不在Activity ,而是在View (或在您的范围内有View类型的变量),则不需要使用WINDOW_SERVICE Then you can use at least two ways.那么你至少可以使用两种方法。

First:第一的:

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

Second:第二:

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

All this methods we call here is not deprecated.我们在这里调用的所有这些方法都没有被弃用。

For getting the screen dimensions use display metrices要获取屏幕尺寸,请使用显示指标

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

Get the height and width in pixels获取以像素为单位的高度和宽度

int width  =displayMetrics.widthPixels;
int height =displayMetrics.heightPixels;

I found this did the trick.我发现这行得通。

Rect dim = new Rect();
getWindowVisibleDisplayFrame(dim);

This is not an answer for the OP, as he wanted the display dimensions in real pixels.这不是 OP 的答案,因为他想要以实际像素为单位的显示尺寸。 I wanted the dimensions in "device-independent-pixels", and putting together answers from here https://stackoverflow.com/a/17880012/253938 and here https://stackoverflow.com/a/6656774/253938 I came up with this:我想要“与设备无关的像素”中的尺寸,并将这里的答案放在一起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);

You can do get the height size using :您可以使用以下方法获取高度大小:

getResources().getDisplayMetrics().heightPixels;

and the width size using宽度大小使用

getResources().getDisplayMetrics().widthPixels; 

There is a non-deprecated way to do this using DisplayMetrics (API 1), that avoids the try/catch messiness:有一种使用 DisplayMetrics (API 1) 的非弃用方法可以避免 try/catch 混乱:

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

I would wrap the getSize code like this:我会像这样包装 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;
}

For who is searching for usable screen dimension without Status Bar and Action Bar (also thanks to Swapnil's answer):谁正在搜索没有状态栏操作栏的可用屏幕尺寸(也感谢 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);
}

First load the XML file and then write this code:首先加载 XML 文件,然后编写以下代码:

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

Show width and height according your screen resolution.根据您的屏幕分辨率显示宽度和高度。

Follow the methods below:请按照以下方法操作:

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

Kotlin科特林

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
}

There are times when you need to know the precise dimensions of the available space for a layout when in an activity's onCreate.在活动的 onCreate 中,有时您需要知道布局可用空间的精确尺寸。 After some thought I worked out this way of doing it.经过一番思考,我想出了这种方法。

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

If for some reason you don't want to add another activity to the Android manifest, you can do it this way:如果出于某种原因您不想向 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();
    }
}    

If you don't want the overhead of WindowManagers, Points, or Displays, you can grab the height and width attributes of the topmost View item in your XML, provided its height and width are set to match_parent.如果您不想要 WindowManagers、Points 或 Displays 的开销,您可以获取 XML 中最顶层 View 项的高度和宽度属性,前提是其高度和宽度设置为 match_parent。 (This is true so long as your layout takes up the entire screen.) (只要您的布局占据整个屏幕,这就是正确的。)

For example, if your XML starts with something like this:例如,如果您的 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" >

Then findViewById(R.id.entireLayout).getWidth() will return the screen's width and findViewById(R.id.entireLayout).getHeight() will return the screen's height.然后findViewById(R.id.entireLayout).getWidth()将返回屏幕的宽度, findViewById(R.id.entireLayout).getHeight()将返回屏幕的高度。

I have a splash screen activity with a LinearLayout as a root view that has match_parent for its width & height.我有一个以 LinearLayout 作为根视图的初始屏幕活动,其宽度和高度具有match_parent This is the code in the onCreate() method of that activity.这是该活动的onCreate()方法中的代码。 I use these measures in all other activities of the app.我在应用程序的所有其他活动中使用这些措施。

int displayWidth = getRawDisplayWidthPreHoneycomb();
int rawDisplayHeight = getRawDisplayHeightPreHoneycomb();
int usableDisplayHeight = rawDisplayHeight - getStatusBarHeight();
pf.setScreenParameters(displayWidth, usableDisplayHeight);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    LinearLayout myView = (LinearLayout) findViewById(R.id.splash_view);
    myView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
            if (left == 0 && top == 0 && right == 0 && bottom == 0) {
                return;
            }
            int displayWidth = Math.min(right, bottom);
            int usableDisplayHeight = Math.max(right, bottom);
            pf.setScreenParameters(displayWidth, usableDisplayHeight);
        }
    });
}

Here are the implementations for the methods you see get called above:以下是您在上面看到的方法的实现:

private int getRawDisplayWidthPreHoneycomb() {
    WindowManager windowManager = getWindowManager();
    Display display = windowManager.getDefaultDisplay();
    DisplayMetrics displayMetrics = new DisplayMetrics();
    display.getMetrics(displayMetrics);

    int widthPixels = displayMetrics.widthPixels;
    int heightPixels = displayMetrics.heightPixels;

    return Math.min(widthPixels, heightPixels);
}

private int getRawDisplayHeightPreHoneycomb() {
    WindowManager w = getWindowManager();
    Display d = w.getDefaultDisplay();
    DisplayMetrics metrics = new DisplayMetrics();
    d.getMetrics(metrics);

    int widthPixels = metrics.widthPixels;
    int heightPixels = metrics.heightPixels;

    return Math.max(widthPixels, heightPixels);
}

public int getStatusBarHeight() {
    int statusBarHeight = 0;

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

    return statusBarHeight;
}

This results in the height and width of the usable display, excluding any type of bars (status bar, navigation bar), for all API versions and different types of devices (phones and tablets).这会导致所有 API 版本和不同类型的设备(手机和平板电脑)的可用显示的高度和宽度,不包括任何类型的栏(状态栏、导航栏)。

Above answer won't work if the Display class will not work then you can get the width and height by below method.如果 Display 类不起作用,则上述答案将不起作用,那么您可以通过以下方法获取宽度和高度。

private static final int WIDTH_INDEX = 0;
private static final int HEIGHT_INDEX = 1;

    public static int[] getScreenSize(Context context) {
        int[] widthHeight = new int[2];
        widthHeight[WIDTH_INDEX] = 0;
        widthHeight[HEIGHT_INDEX] = 0;

        try {
            WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            Display display = windowManager.getDefaultDisplay();

            Point size = new Point();
            display.getSize(size);
            widthHeight[WIDTH_INDEX] = size.x;
            widthHeight[HEIGHT_INDEX] = size.y;

            if (!isScreenSizeRetrieved(widthHeight))
            {
                DisplayMetrics metrics = new DisplayMetrics();
                display.getMetrics(metrics);
                widthHeight[0] = metrics.widthPixels;
                widthHeight[1] = metrics.heightPixels;
            }

            // Last defense. Use deprecated API that was introduced in lower than API 13
            if (!isScreenSizeRetrieved(widthHeight)) {
                widthHeight[0] = display.getWidth(); // deprecated
                widthHeight[1] = display.getHeight(); // deprecated
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return widthHeight;
    }

    private static boolean isScreenSizeRetrieved(int[] widthHeight) {
        return widthHeight[WIDTH_INDEX] != 0 && widthHeight[HEIGHT_INDEX] != 0;
    }

Above code has been deprecated in API level 30. Now you can get using following code以上代码已在 API 级别 30 中弃用。现在您可以使用以下代码

 val width = windowManager.currentWindowMetrics.bounds.width()
 val height = windowManager.currentWindowMetrics.bounds.height()

This method reports the window size including all system bar areas, while Display#getSize(Point) reports the area excluding navigation bars and display cutout areas.该方法报告包括所有系统栏区域的窗口大小,而Display#getSize(Point)报告不包括导航栏和显示剪切区域的区域。 The value reported by Display#getSize(Point) can be obtained by using: Display#getSize(Point)报告的值可以通过使用获得:

 val metrics = windowManager.currentWindowMetrics
 // Gets all excluding insets
 val windowInsets = metrics.windowInsets
 var insets: Insets = windowInsets.getInsets(WindowInsets.Type.navigationBars())
 val cutout = windowInsets.displayCutout
 if (cutout != null) {
    val cutoutSafeInsets = Insets.of(cutout.safeInsetLeft, cutout.safeInsetTop, cutout.safeInsetRight, cutout.safeInsetBottom)
    insets = Insets.max(insets, cutoutSafeInsets)
 }

 val insetsWidth = insets.right + insets.left
 val insetsHeight = insets.top + insets.bottom

 // Legacy size that Display#getSize reports
 val legacySize =  Size(metrics.bounds.width() - insetsWidth, metrics.bounds.height() - insetsHeight)

Source : WindowManager#getCurrentWindowMetrics()来源: WindowManager#getCurrentWindowMetrics()

Simple function compatible with lower versions as well.简单的功能也兼容低版本。

/**
 * @return screen size int[width, height]
 *
 * */
public int[] getScreenSize(){
    Point size = new Point();
    WindowManager w = getWindowManager();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2){
        w.getDefaultDisplay().getSize(size);
        return new int[]{size.x, size.y};
    }else{
        Display d = w.getDefaultDisplay();
        //noinspection deprecation
        return new int[]{d.getWidth(), d.getHeight()};
    }
}

To use:使用:

int width = getScreenSize()[0];
int height = getScreenSize()[1];

This function returns the approximate screen size in inches.此函数返回以英寸为单位的近似屏幕尺寸。

public double getScreenSize()
{
        DisplayMetrics dm = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        int width=dm.widthPixels;
        int height=dm.heightPixels;
        int dens=dm.densityDpi;
        double wi=(double)width/(double)dens;
        double hi=(double)height/(double)dens;
        double x = Math.pow(wi,2);
        double y = Math.pow(hi,2);
        double screenInches = Math.sqrt(x+y);
        return screenInches;
}

Here is a simple adaptation from some answers above in a Kotlin implementation.这是 Kotlin 实现中上述一些答案的简单改编。 It requires as mentioned above windowsSoftInput="adjustResize" in the manifest:如上所述,它需要清单中的 windowsSoftInput="adjustResize" :

class KeyboardWatcher(private val layoutRooView: View) {

    companion object {
        private const val MIN_KEYBOARD_HEIGHT = 200f
    }

    private val displayMetrics: DisplayMetrics = layoutRooView.resources.displayMetrics
    private var stateVisible = false

    var observer: ((Boolean) -> Unit)? = null

    init {
        layoutRooView.viewTreeObserver.addOnGlobalLayoutListener {
            val heightDiff = layoutRooView.rootView.height - layoutRooView.height
            if (!stateVisible && heightDiff > dpToPx(MIN_KEYBOARD_HEIGHT)) {
                stateVisible = true
                observer?.invoke(stateVisible)
            } else if(stateVisible) {
                stateVisible = false
                observer?.invoke(stateVisible)
            }
        }
    }

    private fun dpToPx(valueInDp: Float): Float {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, displayMetrics)
    }
}

And to use:并使用:

val activityRootView = findViewById<ViewGroup>(R.id.activityRoot)
KeyboardWatcher(activityRootView).observer = { visible ->
    if (visible) do something here ...
}

Created Kotlin extension function to get screen width and height -创建Kotlin 扩展函数以获取屏幕宽度和高度 -

fun Context?.screenWidthInPx(): Int {
    if (this == null) return 0
    val dm = DisplayMetrics()
    val wm = this.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    wm.defaultDisplay.getMetrics(dm)
    return dm.widthPixels
}
//comment
fun Context?.screenHeightInPx(): Int {
    if (this == null) return 0
    val dm = DisplayMetrics()
    val wm = this.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    wm.defaultDisplay.getMetrics(dm)
    return dm.heightPixels
}

Now on the Api 30 level , it should be done like this现在在Api 30 级别,应该这样做

final WindowMetrics metrics = windowManager.getCurrentWindowMetrics();
 // Gets all excluding insets
 final WindowInsets windowInsets = metrics.getWindowInsets();
 Insets insets = windowInsets.getInsetsIgnoreVisibility(WindowInsets.Type.navigationBars()
         | WindowInsets.Type.displayCutout());

 int insetsWidth = insets.right + insets.left;
 int insetsHeight = insets.top + insets.bottom;

 // Legacy size that Display#getSize reports
 final Rect bounds = metrics.getBounds();
 final Size legacySize = new Size(bounds.width() - insetsWidth,
         bounds.height() - insetsHeight);
DisplayMetrics dm = getResources().getDisplayMetrics();
float fwidth = dm.density * dm.widthPixels;
float fheight = dm.density * dm.heightPixels;

If getSize gets you an error due to your minSDKVersion and you don't want to use deprecated methods ( getWidth & getHeight ), the getMetrics solution was originally posted on 2011 by Balaji.K... And Nik added a comment explaining getDisplayMetrics also considers the status bar size.如果getSize由于您的 minSDKVersion 而给您带来错误,并且您不想使用已弃用的方法( getWidthgetHeight ),则getMetrics解决方案最初由 Balaji.K 于 2011 年发布...并且 Nik 添加了解释getDisplayMetrics的评论也考虑状态栏大小。

Some other comments refer to multiply by the scale ( density ) in order to get the precise float value of the dimensions.其他一些评论是指乘以比例(密度)以获得尺寸的精确浮点值。 Tested in Android v2.2 (API 8) and v4.0 with good results and no errors/warnings .在 Android v2.2 (API 8) 和 v4.0 中测试,结果良好且没有错误/警告

I used above proposals and created a kotlin version for our question.我使用了上述建议并为我们的问题创建了一个 kotlin 版本。 Hope this provides some additional help for those using kotlin:希望这能为使用 kotlin 的人提供一些额外的帮助:

private val screenDimensions: Int by lazy {
    val display = (context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
    Point()
        .also { size ->
            when {
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 -> display.getRealSize(size)
                else -> display.getSize(size)
            }
        }
}

screenDimensions.x // width
screenDimensions.y // height

I think it's simplest我觉得最简单

private fun checkDisplayResolution() {
    val displayMetrics = DisplayMetrics().also {
        windowManager.defaultDisplay.getMetrics(it)
    }

    Log.i(TAG, "display width: ${displayMetrics.widthPixels}")
    Log.i(TAG, "display height: ${displayMetrics.heightPixels}")
    Log.i(TAG, "display width dpi: ${displayMetrics.xdpi}")
    Log.i(TAG, "display height dpi: ${displayMetrics.ydpi}")
    Log.i(TAG, "display density: ${displayMetrics.density}")
    Log.i(TAG, "display scaled density: ${displayMetrics.scaledDensity}")
}

Kotlin Version via Extension Property Kotlin Version通过Extension Property

There are multiple ways of achieving the screen dimensions in android, but I think the best solution could be independent of a Context instance, so you can use it everywhere in your code.在 android 中有多种实现屏幕尺寸的方法,但我认为最好的解决方案可能是独立于Context实例,因此您可以在代码中的任何地方使用它。 Here I've provided a solution via kotlin extension property, which makes it easy to know the screen size in pixels as well as dp :在这里,我通过 kotlin 扩展属性提供了一个解决方案,它可以轻松了解以像素和dp为单位的屏幕尺寸:


DimensionUtils.kt DimensionUtils.kt

import android.content.res.Resources
import android.graphics.Rect
import android.graphics.RectF
import android.util.DisplayMetrics
import kotlin.math.roundToInt

/**
 * @author aminography
 */

private val displayMetrics: DisplayMetrics by lazy { Resources.getSystem().displayMetrics }

val screenRectPx: Rect
    get() = displayMetrics.run { Rect(0, 0, widthPixels, heightPixels) }

val screenRectDp: RectF
    get() = displayMetrics.run { RectF(0f, 0f, widthPixels.px2dp, heightPixels.px2dp) }

val Number.px2dp: Float
    get() = this.toFloat() / displayMetrics.density

val Number.dp2px: Int
    get() = (this.toFloat() * displayMetrics.density).roundToInt()


Usage:用法:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val widthPx = screenRectPx.width()
        val heightPx = screenRectPx.height()
        println("[PX] screen width: $widthPx , height: $heightPx")

        val widthDp = screenRectDp.width()
        val heightDp = screenRectDp.height()
        println("[DP] screen width: $widthDp , height: $heightDp")
    }
}

Result:结果:

When the device is in portrait orientation:当设备处于portrait

[PX] screen width: 1440 , height: 2392
[DP] screen width: 360.0 , height: 598.0

When the device is in landscape orientation:当设备处于landscape

[PX] screen width: 2392 , height: 1440
[DP] screen width: 598.0 , height: 360.0


If you are not a fan of kotlin, use the java version:如果您不是 kotlin 的粉丝,请使用 java 版本:

import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.DisplayMetrics;

/**
 * @author aminography
 */
public class DimensionUtils {

    private static DisplayMetrics displayMetrics;

    private static DisplayMetrics getDisplayMetrics() {
        if (displayMetrics == null) {
            displayMetrics = Resources.getSystem().getDisplayMetrics();
        }
        return displayMetrics;
    }

    public static Rect screenRectPx() {
        return new Rect(0, 0, getDisplayMetrics().widthPixels, getDisplayMetrics().heightPixels);
    }

    public static RectF screenRectDp() {
        return new RectF(0f, 0f, px2dp(getDisplayMetrics().widthPixels), px2dp(getDisplayMetrics().heightPixels));
    }

    public static float px2dp(int value) {
        return value / getDisplayMetrics().density;
    }

    public static int dp2px(float value) {
        return (int) (value * getDisplayMetrics().density);
    }
}

KOTLIN科特林

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
}

JAVA爪哇

DisplayMetrics dimension = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dimension);
int w = dimension.widthPixels;
int h = dimension.heightPixels;

Here is Kotlin extension functions for below/above API 30 code:以下是 API 30 代码以下/以上的 Kotlin 扩展函数:

fun Activity.getScreenWidth(): Int {
    return if (Build.VERSION.SDK_INT < 30) {
        val displayMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(displayMetrics)
        displayMetrics.widthPixels
    } else {
        val metrics = windowManager.currentWindowMetrics
        val insets = metrics.windowInsets
            .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
        metrics.bounds.width() - insets.left - insets.right
    }
}

fun Activity.getScreenHeight(): Int {
    return if (Build.VERSION.SDK_INT < 30) {
        val displayMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(displayMetrics)
        displayMetrics.heightPixels
    } else {
        val metrics = windowManager.currentWindowMetrics
        val insets = metrics.windowInsets
            .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())
        metrics.bounds.height() - insets.top - insets.bottom
    }
}

Corresponding Java helper methods:对应的 Java 辅助方法:

public int getScreenWidth(Activity activity) {
    if (Build.VERSION.SDK_INT < 30) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    } else {
        WindowMetrics metrics = activity.getWindowManager().getCurrentWindowMetrics();
        Insets insets = metrics.getWindowInsets()
                .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
        return metrics.getBounds().width() - insets.left - insets.right;
    }
}


public int getScreenHeight(Activity activity) {
    if (Build.VERSION.SDK_INT < 30) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.heightPixels;
    } else {
        WindowMetrics metrics = activity.getWindowManager().getCurrentWindowMetrics();
        Insets insets = metrics.getWindowInsets()
                .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars());
        return metrics.getBounds().height() - insets.bottom - insets.top;
    }
}

create a class and a method like below:创建一个类和一个方法,如下所示:

public MyPoint getScreenDimensionsAsPixel(Context context){
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();

        Point point = new Point();
        display.getSize(point);

        return new MyPoint(point.x, point.y);
    }

    public class MyPoint{
        private int width;
        private int height;

        public MyPoint(int width, int height) {
            this.width = width;
            this.height = height;
        }

        public int getWidth() {
            return width;
        }

        public void setWidth(int width) {
            this.width = width;
        }

        public int getHeight() {
            return height;
        }

        public void setHeight(int height) {
            this.height = height;
        }
    }

and then use them in your codes:然后在您的代码中使用它们:

MyPoint myPoint = getScreenDimensionsAsPixel(MainActivity.this);
                Toast.makeText(MainActivity.this, "width: " + String.valueOf(myPoint.getWidth()) + "|" +
                        "height: " + String.valueOf(myPoint.getHeight()), Toast.LENGTH_LONG).show();

Much simpler in Kotlin.在 Kotlin 中要简单得多。

val displayMetrics = Resources.getSystem().displayMetrics
displayMetrics.heightPixels
displayMetrics.widthPixels

I suggest you create extension functions.我建议你创建扩展函数。

/**
 * Return the width and height of the screen
 */

val Context.screenWidth: Int
  get() = resources.displayMetrics.widthPixels

val Context.screenHeight: Int
  get() = resources.displayMetrics.heightPixels

/**
 * Pixel and Dp Conversion
 */

val Float.toPx get() = this * Resources.getSystem().displayMetrics.density
val Float.toDp get() = this / Resources.getSystem().displayMetrics.density

val Int.toPx get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Int.toDp get() = (this / Resources.getSystem().displayMetrics.density).toInt()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM