• [Android]图片资源管理学习


    一.概念

    几个概念:
    1.像素:
    像素是组成图像的最基本单位:点
    该点自身有大小,其中保存了颜色值

     

    2.屏幕尺寸:screen size
    手机屏幕的物理尺寸。
    单位:inch(英寸)
    ex:4.0英寸 3.8英寸

     

    3.分辨率:resolution
    分辨率是指在长和宽的两个方向上各拥有的像素点
    屏幕中物理像素点的总数.
    单位:px (pixels)
    ex: 480 x 800 , 1920 x 1080

     

    4.屏幕像素密度:dots per inch.
    每英寸中有多少个像素.
    单位:dpi
    ex:160dpi,表示1英寸中存在160个像素
    dpi由屏幕尺寸和分辨率决定

     

    5.密度:density
    resolution  / screen size

     

    6.密度无关像素:desity-independent pixel
    与设备无关的像素,可以理解为是[逻辑像素]
    >它用于在开发时,通过声明的方式(XML)定义UI元素之间的位置关系,当程序运行在
    具体设备上之后,操作系统将会根据此dip值,换算像素,此像素值就是当前UI元素
    在具体设备上的大小<
    换算公式为:
    pixel = dip * (dpi / 160);


     

    二.布局单位

    android布局文件中常见的几个单位:
    px:像素
    dip = dp:逻辑像素
    sp:
    (其他的pt,in,mm基本不用)

    在android的xml布局文件中,Google建议控件的大小(width,height),外边距(margin),内边距(padding)使用dip(dp)定义
    字号(textSize)使用sp定义

    设计时通过Eclipse中的Graphical Layout可以看到控件之间的位置关系,此时的设计时界面是可以看到屏幕物理尺寸和分辨率的
    在此尺寸和分辨率进行布局之后,到真机运行时,系统会根据真机的dpi,把设计时定义的控件的大小,边距从dip换算成实际的px

    ex:
    设计时我设置ImageView的width和height都为150dip,当程序运行在魅族MX2上时,获取ImageView的Width和Height看到其值为300px,
    由于魅族MX2分辨率为:800 x 1280,即对应xhpdi,其屏幕密度为:320,
    系统根据上文中的公式:pixel = dip * (dpi / 160) 进行换算: 300px = 150dip * (320dpi / 160);


     

    三.目录

    项目中的几个目录:
    drawable-mdpi
    drawable-hdpi
    drawable-xhdpi
    drawable-xxhdpi

    drawable资源(更多时候是图片)被放在上述几个目录中,当程序启动时,系统会根据手机的硬件信息从合适的
    drawable目录中加载资源,比如如果程序运行在魅族MX2上,那么就会从drawable-xhdpi中加载资源,如果运行在
    Nexus One上,便从drawable-hdpi中加载资源

    显然为了达到图片像素点与屏幕像素点一一对应,则需要多套图片资源,分别放在上述目录下,当时通常情况是
    只会有一套资源,那只能放在一个目录下。

    假设:
    资源都放在drawable-mdpi中,当程序在魅族MX2运行时,由于手机dpi为320,则对应到drawable-xhdpi中加载资源,
    但是由于此目录中没有资源,只能到其他目录中找,发现资源在drawable-mdpi中,便获取资源,载入程序中

    由于在drawable-mdpi中的资源被认为其dpi为160,而当前真实dpi为320,那么要求在显示时候就需要每一英寸中的像素点从160个
    增大到320个,所以系统对Bitmap进行了自动缩放,把图片放大了2倍.

    那么这里就有一个疑问了。
    假设,我们只有一套图片资源,是基于800 x 1280设计并且裁剪的,那么我们应该把它放在drawable-xhdpi目录下,没问题,
    如果我把这些图片,放到drawable-mdpi下,那么就出现问题了,图片在绘制到屏幕上之后,必然会被放大,反之缩小了
    所以,对应的图片资源,必须被放到适合的地方

    如何禁止系统自动缩放图片资源?
    如果我们不需要系统为我们自动缩放图片资源,可以把图片放到res/drawable-nodpi/目录下

     

    getWidth和getHeight方法:

    1.为什么同一张图片,在放入drawable-mdpi/drawable-hdpi/drawable-xhdpi/drawable-xxhdpi 目录中之后
    创建Bitmap,getWidth()/getHeight(),不同目录下,结果不同

    查看Bitmap源码发现,getWidth()方法是调用了nativeWidth(),至于nativeWidth()是调用SkBitmap类中的width()方法
    SkBitmap与图片文件编码有关(头疼啊 - -)
    那我就自作聪明的这么来理解SkBitmap的width()方法:

    伪代码:
    int width()
    {
       //pixel = dip * (dpi / 160);
       // 获取设计时dpi
       // mdpi = 160
       // hdpi = 240
       // xhdpi = 320
       // xxhdpi = 480
       int desgin_dpi = get_desgin_dpi();
       // 获取设备相关真实dpi
       int system_dpi = get_system_dpi();

       // 获取设计dpi与实际dpi的比例
       float rate = desgin_dpi / system_dpi * 1.0;
       // 获取图片实际像素数,即公式中的dip , 此值固定不便
       int img_file_width_piexls = get_img_width_pixels();

       // 得到宽度,此值一致被Bitmap的getWidth()方法调用到
       return img_file_piexls * rate * (system_dpi / 160);
    }

    如果上述的假设是对的,那么说明,图片在不同目录时候,获取到的设计时dpi就不同,那么rate不同,
    所以导致最终的结果不同.
    (以上阐述未经过证明,纯属我yy)

     

    2.上面也解释了为什么不同目录下获取到的数值不同,但是既然说getWidth()和getHeight获取到的是图片的宽高
    图片是同一张图啊,一会640px,一会1280px,是图片的像素便了吗?

    答:图片像素没变,宽高变了。getWidth和getHeight这个两个方法的返回值被用来描述Bitmap的宽和高,其单位为px,
    在使用getWdith时,就不要用横向像素点个数来理解了,就简单的理解为是图片的宽。
    getWidth为1280px时候,说明我们的图片被拉伸了,但是像素点个数没变,只是单个像素点的大小变大了,这样会
    比较容易理解。(但是好像还是不知其所以然的样子,悲剧)

    综上所述,清楚每一个目录的设计时对应分辨率和dpi是很重要的
    基准dpi为160:
    drawable-ldpi         -> 120dpi -> 0.75倍 -> 360  x 600
    drawable-mdpi      -> 160dpi -> 1倍       -> 480  x 800
    drawable-hdpi       -> 240dpi -> 1.5倍    -> 720  x 1200
    drawable-xhdpi     -> 320dpi -> 2倍       -> 800  x 1280
    drawable-xxhdpi   -> 480dpi -> 3倍       -> 1440 x 3840
    drawable-xxxhdpi -> 640dpi -> 4倍       -> ...........


     

    四.Examples

    1.获取屏幕相关信息

    DisplayMetrics metric = new DisplayMetrics(); 
    getWindowManager().getDefaultDisplay().getMetrics(metric); 
    int width = metric.widthPixels;                // 屏幕宽度(像素)
    int height = metric.heightPixels;              // 屏幕高度(像素)
    float density = metric.density;                // 屏幕密度(0.75 / 1.0 / 1.5)
    int densityDpi = metric.densityDpi;            // 屏幕密度DPI(120 / 160 / 240)
    double diagonalPixels = Math.sqrt(Math.pow(width, 2)+Math.pow(height, 2)) ; 
    double screenSize = diagonalPixels/(160*density) ;

    2.图片自动缩放后的宽高

    Bitmap.getWidth()
    Bitmap.getHeight()

    3.获取图片真实尺寸(其像素值与在pc下查看到的一致)

    // scaledWidth为图片在自动缩放资源目录中通过getWidth()获取到的数值
    private int getImageRealWidth(int scaledWidth)
    {
    	DisplayMetrics metric = new DisplayMetrics(); 
    	getWindowManager().getDefaultDisplay().getMetrics(metric); 
    	int densityDpi = metric.densityDpi;
    		
    	return scaledWidth * 160 / densityDpi;
    }
    	
    // scaledHeight为图片在自动缩放资源目录中通过getHeight()获取到的数值
    private int getImageRealHeight(int scaledHeight)
    {
    	DisplayMetrics metric = new DisplayMetrics(); 
    	getWindowManager().getDefaultDisplay().getMetrics(metric); 
    	int densityDpi = metric.densityDpi;
    		
    	return scaledHeight * 160 / densityDpi;
    }

    4.px –> dip , dip –> px

    public static int dip2px(Context context, float dipValue)
    { 
         final float scale = context.getResources().getDisplayMetrics().density; 
         return (int)(dipValue * scale + 0.5f); 
    } 
            
    public static int px2dip(Context context, float pxValue)
    { 
        final float scale = context.getResources().getDisplayMetrics().density; 
        return (int)(pxValue / scale + 0.5f); 
    } 
  • 相关阅读:
    headfirst设计模式(6)—单例模式
    headfirst设计模式(5)—工厂模式体系分析及抽象工厂模式
    headfirst设计模式(4)—工厂模式
    headfirst设计模式(3)—装饰者模式
    headfirst设计模式(2)—观察者模式
    headfirst设计模式(1)—策略模式
    BeanFactory 与 FactoryBean
    两个List集合取交集、并集、差集
    服务编排
    oracle报错ORA-01843: not a valid month
  • 原文地址:https://www.cnblogs.com/hellenism/p/3685101.html
Copyright © 2020-2023  润新知