Android开发中正确获取屏幕参数

一.概况

在平时的开发中有一些情况下是要获取屏幕的宽度,高度或者屏幕密度,状态栏的高度等等,但是现在网上的一些方法我发现有很多不恰当甚至错误的不能正确获取屏幕参数的。下面我就从最新的sdk和api中找寻正确的方法来获取这些参数。如果对dpi和ppi还有不太清除的话请看前一篇文章。

二.具体获取参数的方法

以下的各个方法均是我打log印证过过的,可以放心使用。

2.1获得屏幕的宽高

2.1.1获取屏幕宽高,先贴正确的代码,分两种方法,区别就在于第一种有一点局限性就是要在api>=17的情况下,第二种没有这个限制,我更推荐第二种,这里第一种只是为了证明它的存在。

第一种:

    //获取整个屏幕的宽
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    public static int getWidth(Activity mActivity){
        Point point = new Point();
        mActivity.getWindowManager().getDefaultDisplay().getRealSize(point);
        return point.x;
    }

   //获取整个屏幕的高
   @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
   public static int getHeight(Activity mActivity){
       Point point = new Point();
       mActivity.getWindowManager().getDefaultDisplay().getRealSize(point);
       return point.y;
   }

第二种:

    //获取整个屏幕的宽
    public static int getWidth(Activity activity){
        int dpi = 0;
        Display display = activity.getWindowManager().getDefaultDisplay();
        DisplayMetrics dm = new DisplayMetrics();
        @SuppressWarnings("rawtypes")
        Class c;
        try {
            c = Class.forName("android.view.Display");
            @SuppressWarnings("unchecked")
            Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
            method.invoke(display, dm);
            dpi = dm.widthPixels;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dpi;
    }
    //获取整个屏幕高
    public static int getHeight(Activity activity) {
        int dpi = 0;
        Display display = activity.getWindowManager().getDefaultDisplay();
        DisplayMetrics dm = new DisplayMetrics();
        @SuppressWarnings("rawtypes")
        Class c;
        try {
            c = Class.forName("android.view.Display");
            @SuppressWarnings("unchecked")
            Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
            method.invoke(display, dm);
            dpi = dm.heightPixels;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dpi;
    }

2.1.2下面是获取屏幕的实时可用高度,就是我们编程的时候我们能控制使用的部分的高度(这是一个有底部虚拟操作栏和没有的时候相差一个操作栏高度的数值),因为目前为止还没有系统级别的控件会占用屏幕的可用宽度,这里不考虑宽度的适时可用宽度。

    //获取能够使用的屏幕的高度(有和没有底部的虚拟操作栏获取值相差一个虚拟栏的高)
    public static int getRealTimeHeight(Activity activity){
        Point point = new Point();
        activity.getWindowManager().getDefaultDisplay().getSize(point);
        return point.y;
    }

2.1.3获取屏幕底部的操作栏高度

代码如下:

//获取底部虚拟操作栏的高,客观值(和显示与否无关)
    public static int getBottomBarHeight(Context context){
        int bottomVirtualHeitht = 0;
        int rId = context.getResources().getIdentifier("config_showNavigationBar", "bool", "android");
        if (rId != 0){
            int resourceId = context.getResources().getIdentifier("navigation_bar_height","dimen","android");
            bottomVirtualHeitht = context.getResources().getDimensionPixelSize(resourceId);
        }
        return bottomVirtualHeitht;
    }

2.1.4一些拓展

通过上面得到整个屏幕的高度和实时的可用高度之后我们就可以随时判断底部的操作栏的显示和隐藏了,当然还不能达到观察者模式的效果。

2.2获取屏幕密度等

2.2.1获取屏幕密度dpi,px和dp的转化的倍数值

    //获取dpi
    public static int getDensityDpi(Context context){
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        return dm.densityDpi;
    }

    //获取px和dp转化倍数值
    public static float getDensity(Context context){
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        return dm.density;
    }

2.2.2获取屏幕x,y方向上的ppi

    //获取x方向的ppi
    public static float getXDpi(Context context){
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        Log.e("getXDpi",dm.xdpi+"");
        return dm.xdpi;
    }

    //获取y方向的ppi
    public static float getYDpi(Context context){
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        Log.e("getXDpi",dm.ydpi+"");
        return dm.ydpi;
    }
从目前我接触过的使用来看,只是用这俩参数计算过屏幕的宽高和对角线尺寸(也就是屏幕的标定尺寸单位是inch)如下:
    public static int getPhysicsSize(Activity activity){
        double x = Math.pow(getWidth(activity)/ getXDpi(activity), 2);
        double y = Math.pow(getHeight(activity) / getYDpi(activity), 2);
        double screenInches = Math.sqrt(x + y);
        return ((int) screenInches);
    }

2.2.3下面是px和dp,sp之间的转化工具

    /**
     * dp转px
     * */
    public static int dp2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpVal, context.getResources().getDisplayMetrics());
    }

    /**
     * sp转px
     */
    public static int sp2px(Context context, float spVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                spVal, context.getResources().getDisplayMetrics());
    }

    /**
     * px转dp
     */
    public static float px2dp(Context context, float pxVal) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (pxVal / scale);
    }

    /**
     * px转sp
     */
    public static float px2sp(Context context, float pxVal) {
        return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
    }

三.从类工具中查找上面正确方法的依据

3.1几个重要的类

Display类,DisplayMetrics类,Point类这里由于内部代码太多不贴所有代码,只是粘贴一些涉及的代码。
下面是Display内部的getWidth方法,不推荐使用了而是用上面建议的方法。(高度同理)
    /**
     * @deprecated Use {@link #getSize(Point)} instead.
     */
    @Deprecated
    public int getWidth() {
        synchronized (this) {
            updateCachedAppSizeIfNeededLocked();
            return mCachedAppWidthCompat;
        }
    }
Point类只是一个实体类存储相应的参数,这里不粘贴代码了
DisplayMetrics是用来获取dpi和ppi的,下面看一下各个参数的具体含义
    /**
     * The logical density of the display.  This is a scaling factor for the
     * Density Independent Pixel unit, where one DIP is one pixel on an
     * approximately 160 dpi screen (for example a 240x320, 1.5"x2" screen), 
     * providing the baseline of the system's display. Thus on a 160dpi screen 
     * this density value will be 1; on a 120 dpi screen it would be .75; etc.
     *  
     * <p>This value does not exactly follow the real screen size (as given by 
     * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
     * the overall UI in steps based on gross changes in the display dpi.  For 
     * example, a 240x320 screen will have a density of 1 even if its width is 
     * 1.8", 1.3", etc. However, if the screen resolution is increased to 
     * 320x480 but the screen size remained 1.5"x2" then the density would be 
     * increased (probably to 1.5).
     *
     * @see #DENSITY_DEFAULT
     */
    public float density;//用于px和dp的转化
    /**
     * The screen density expressed as dots-per-inch.  May be either
     * {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}.
     */
    public int densityDpi;//dpi,从这里知道这里获取的不是随便的一个具体值,而是一个具体的数值,DENSITY_MEDIUM,DENSITY_HIGH等,其实是这个屏幕获取真实dpi之后和附近的标定值比较靠哪个近就是哪一个。
    /**
     * A scaling factor for fonts displayed on the display.  This is the same
     * as {@link #density}, except that it may be adjusted in smaller
     * increments at runtime based on a user preference for the font size.
     */
    public float scaledDensity;//用于sp和px转化
下面是DisplayMetrics中的几个标定常数,从中可以看出几个我们上面使用的标定值
    /**
     * Standard quantized DPI for low-density screens.
     */
    public static final int DENSITY_LOW = 120;
    /**
     * Standard quantized DPI for medium-density screens.
     */
    public static final int DENSITY_MEDIUM = 160;

    /**
     * This is a secondary density, added for some common screen configurations.
     * It is recommended that applications not generally target this as a first
     * class density -- that is, don't supply specific graphics for this
     * density, instead allow the platform to scale from other densities
     * (typically {@link #DENSITY_HIGH}) as
     * appropriate.  In most cases (such as using bitmaps in
     * {@link android.graphics.drawable.Drawable}) the platform
     * can perform this scaling at load time, so the only cost is some slight
     * startup runtime overhead.
     *
     * <p>This density was original introduced to correspond with a
     * 720p TV screen: the density for 1080p televisions is
     * {@link #DENSITY_XHIGH}, and the value here provides the same UI
     * size for a TV running at 720p.  It has also found use in 7" tablets,
     * when these devices have 1280x720 displays.
     */
    public static final int DENSITY_TV = 213;

    /**
     * Standard quantized DPI for high-density screens.
     */
    public static final int DENSITY_HIGH = 240;

    /**
     * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
     * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
     * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
     */
    public static final int DENSITY_260 = 260;

    /**
     * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
     * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
     * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
     */
    public static final int DENSITY_280 = 280;

    /**
     * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
     * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
     * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
     */
    public static final int DENSITY_300 = 300;

    /**
     * Standard quantized DPI for extra-high-density screens.
     */
    public static final int DENSITY_XHIGH = 320;

    /**
     * Intermediate density for screens that sit somewhere between
     * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
     * This is not a density that applications should target, instead relying
     * on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
     */
    public static final int DENSITY_340 = 340;

    /**
     * Intermediate density for screens that sit somewhere between
     * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
     * This is not a density that applications should target, instead relying
     * on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
     */
    public static final int DENSITY_360 = 360;

    /**
     * Intermediate density for screens that sit somewhere between
     * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
     * This is not a density that applications should target, instead relying
     * on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
     */
    public static final int DENSITY_400 = 400;

    /**
     * Intermediate density for screens that sit somewhere between
     * {@link #DENSITY_XHIGH} (320 dpi) and {@link #DENSITY_XXHIGH} (480 dpi).
     * This is not a density that applications should target, instead relying
     * on the system to scale their {@link #DENSITY_XXHIGH} assets for them.
     */
    public static final int DENSITY_420 = 420;

    /**
     * Standard quantized DPI for extra-extra-high-density screens.
     */
    public static final int DENSITY_XXHIGH = 480;

    /**
     * Intermediate density for screens that sit somewhere between
     * {@link #DENSITY_XXHIGH} (480 dpi) and {@link #DENSITY_XXXHIGH} (640 dpi).
     * This is not a density that applications should target, instead relying
     * on the system to scale their {@link #DENSITY_XXXHIGH} assets for them.
     */
    public static final int DENSITY_560 = 560;

    /**
     * Standard quantized DPI for extra-extra-extra-high-density screens.  Applications
     * should not generally worry about this density; relying on XHIGH graphics
     * being scaled up to it should be sufficient for almost all cases.  A typical
     * use of this density would be 4K television screens -- 3840x2160, which
     * is 2x a traditional HD 1920x1080 screen which runs at DENSITY_XHIGH.
     */
    public static final int DENSITY_XXXHIGH = 640;
上面只是一部分,如果想很具体的了解还要去阅读类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值