安卓Java开发技术学习——工具类的封装(DisplayUtil类与ResUtil类)

287 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 25 天,点击查看活动详情

前言

上一篇文章中(安卓Java开发记录——工具类的封装使用(ToastUtil提示工具类) - 掘金 (juejin.cn))我们在封装ToastUtil的时候,提到了另外两个工具类,今天我们就来具体看看它们。

正篇

首先,我们安卓开发的时候常用一些测量单位比如dp、px,其中dp全称为density-independent pixel(dip),是一种与屏幕密度无关的长度度量单位,dp可以直接与距离相互换算,160dp为1英寸(注:1英寸等于25.4毫米),而px则是安卓中用来描述手机屏幕上的一个个可以用来显示颜色的物理点,我们可以把px理解为像素点pixel。而这两个单位有时候需要我们换算,所以我们可以在DisplayUtil类中封装一下它们的转换方法设置为全局的静态方法:

/**
 * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
 */
public static int dp2px(Context context, float dpValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (dpValue * scale + 0.5f);
}

/**
 * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
 */
public static int px2dp(Context context, float pxValue) {
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (pxValue / scale + 0.5f);
}

其中这里用到的getDisplayMetrics()方法的density参数是缩放系数

image.png

image.png 当屏幕密度为160dpi时就是1,此时10dp转10px是1:1的,而注释中也说了120dpi时此系数为0.75,这时候10dp转7.5px,所以该比例可以直接用来px和dx单位的互转,那我们为什么要转完再 +0.5f 呢?其实代码中最后转换结果需要+0.5f,是出于计算精度的考虑,当浮点数转为整型数时,会抛弃掉小数位,也就是说会进行向下取整。为了出于计算精度的考虑,我们需要对结果进行四舍五入。当我们在结果中加上0.5f后,即可实现四舍五入。

下面几个方法是用来获取我们显示器的参数集的,其中包含了显示器密度、字体缩放等信息:

public static DisplayMetrics getDisplayMetrics(Context context) {
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    if (wm == null) {
        return null;
    }
    DisplayMetrics displayMetrics = new DisplayMetrics();
    wm.getDefaultDisplay().getMetrics(displayMetrics);
    return displayMetrics;
}

public static DisplayMetrics getDisplayMetrics(WindowManager wm) {
    DisplayMetrics displayMetrics = new DisplayMetrics();
    wm.getDefaultDisplay().getMetrics(displayMetrics);
    return displayMetrics;
}

public static DisplayMetrics getRealDisplayMetrics(WindowManager wm) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getRealMetrics(displayMetrics);
        return displayMetrics;
    } else {
        return getDisplayMetrics(wm);
    }
}

有上面这个的获取我们可以用来获取各种更具体的屏幕信息,如在资源工具类ResUtil中 getDimenAttr()方法获取属性中的尺寸资源:

/**
 * 获取属性中的尺寸资源
 *
 * @param context
 * @param attr
 *
 * @return
 */
public static int getDimenAttr(Context context, int attr) {
    TypedValue typedValue = new TypedValue();
    context.getTheme().resolveAttribute(attr, typedValue, true);
    float dimen = typedValue.getDimension(DisplayUtil.getDisplayMetrics(context));
    return (int) dimen;
}

下面的方法是sp转px的,和dp转px类似,不过我们使用了scaledDensity参数,这是专门用来看屏幕显示字体的缩放系数的,而sp正是我们安卓用于文字字体的单位。

/**
 *根据手机的分辨率从 sp 的单位 转成为 px(像素)
 */
public static int sp2px(Context context, float pxValue){
    final float scale = context.getResources().getDisplayMetrics().scaledDensity;
    return (int) (pxValue * scale +0.5f);
}

再往下看,我们还有获取屏幕内容宽与高的方法:

public static int getScreenWidthInPx(Context context) {
    DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
    return dm.widthPixels;
}

public static int getScreenHeightInPx(Context context) {
    DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
    return dm.heightPixels;
}

然后是获取屏幕状态栏高的方法:

/**
 *获取状态栏高度
 */
public static float getStatusBarHeight(Context context) {
    float height = 0;
    int resourceId = context.getApplicationContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        height = context.getApplicationContext().getResources().getDimensionPixelSize(resourceId);
    }
    return height;
}

最后我们调用上面的方法和屏幕内容高的方法,获取屏幕总高:

public static int getScreenHeight(Context context) {
    return (int) (getScreenHeightInPx(context) + getStatusBarHeight(context));
}

这样,我们的DisplayUtil类就封装好了,与屏幕相关的高宽等参数可以通过这个类方法去更简单的调用获取。

下面我们来说说ResUtil类封装,这个更为简单,我们主要是为了更方便的获取资源的具体内容,比如通过文字id获取对应文字字符串内容,通过命名好的颜色id获取对应颜色资源值:

import android.content.Context;
import android.os.Build;
import android.util.TypedValue;


/**
 * 用于获取内置资源
 */
public class ResUtil {

    /**
     * 获取属性中的颜色资源
     *
     * @param context
     * @param attr
     *
     * @return
     */
    public static int getColorAttr(Context context, int attr) {
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attr, typedValue, true);
        return typedValue.data;
    }

    /**
     * 获取属性中的尺寸资源
     *
     * @param context
     * @param attr
     *
     * @return
     */
    public static int getDimenAttr(Context context, int attr) {
        TypedValue typedValue = new TypedValue();
        context.getTheme().resolveAttribute(attr, typedValue, true);
        float dimen = typedValue.getDimension(DisplayUtil.getDisplayMetrics(context));
        return (int) dimen;
    }

    /**
     * 获取颜色资源
     *
     * @param context
     * @param colorRes
     *
     * @return
     */
    public static int getColor(Context context, int colorRes) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return context.getResources().getColor(colorRes, context.getTheme());
        } else {
            return context.getResources().getColor(colorRes);
        }
    }

    /**
     * 获取string资源
     *
     * @param context
     * @param res
     *
     * @return
     */
    public static String getString(Context context, int res) {
        return context.getResources().getString(res);
    }

    /**
     * 获取string数组资源
     *
     * @param context
     * @param res
     *
     * @return
     */
    public static String[] getStringArray(Context context, int res) {
        return context.getResources().getStringArray(res);
    }

    /**
     * 获取int资源
     *
     * @param context
     * @param res
     *
     * @return
     */
    public static int getInt(Context context, int res) {
        return context.getResources().getInteger(res);
    }

    /**
     * 获取int资源
     *
     * @param context
     * @param res
     *
     * @return
     */
    public static int[] getIntArray(Context context, int res) {
        return context.getResources().getIntArray(res);
    }

    /**
     * 获取bool资源
     *
     * @param context
     * @param res
     *
     * @return
     */
    public static boolean getBool(Context context, int res) {
        return context.getResources().getBoolean(res);
    }
}

这就节省了我们去不断getResources()方法去获取各种值的麻烦,直接传入context与对应int类型的id(如R.id.xxx)即可。

以上就是我们封装好的工具类,放入我们的项目中,平时开发就直接传入相应参数调用就能获取我们想要的值,提高我们的开发效率。

总结

我们的工具类就先讲到这,后续如果有其他比较方便的工具类封装,我们再去开新文章介绍。此外,本文章后面根据作者本人的Kotlin的学习情况,再去更新到对应的Kotlin语言封装。