【Android Drawable】二、BitmapDrawable、NinePatchDrawable、GradientDrawable、StateListDrawable

一、BitmapDrawable

Bitmap 是一种位图图像,Android 系统支持三种格式的位图图像,.png (preferred)(支持最好),.jpg (acceptable), .gif (discouraged)(支持最差)。

在构建应用的时候,Bitmap文件可能会被appt工具压缩自动优化为无损图像。例如,一个真彩色PNG,不需要超过256的颜色可以被转换成一个8位PNG和调色板。这将导致一个图像质量相同,但这需要更少的内存。所以要意识到,在drawable目录中图像的二进制文件在构建程序时可以改变。如果你打算读一个图像作为字节流并将它转换成一个位图,把你的图片放在在res /raw/文件夹里,在那里他们不会被优化。

属性介绍
    android:src=""
    android:alpha=""
    android:antialias=""
    android:autoMirrored=""
    android:dither=""
    android:filter=""
    android:gravity=""
    android:mipMap=""
    android:tileMode=""
    android:tileModeX=""
    android:tileModeY=""
    android:tint=""
    android:tintMode=""
  • android:antialias 抗锯齿

开启抗锯齿,图像会变的=得更平滑,但是会降低清晰度,一般开启;

  • android:dither 防抖动

让高质量的图片的比较低质量的屏幕上不失真,得到比较好的显示效果。
比如图片的色彩模式是 ARGB8888,但是手机设备的支持RGB555的色彩模式,那么开启这么就可以有效减少失真现象。
(Android中我们创建的Bitmap一般会选择ARGB888模式,ARGB每个通道各占8位,8位1个字节,一个像素4个字节,一个像素的位数总和越高,图片越逼真)

  • android:filter 过滤效果

在图片图片被拉伸或者压缩的时候开启过滤效果可以显示更加好的效果。

  • android:mipmap

纹理映射

  • android:gravity 图片位置
    可选项
  • top|bottom|left|right|center|center_vertical|center_horizontal|cneter 保持图片原来大小
  • fill_vertical|fill_horizontal|fill 拉伸图片填充容器,BitmapDrawable 作为背景时会自动拉伸为 View 宽高,所以默认的 gravity 属性值为 fill
  • clip_vertical | clip_horizontal 附加项,表示裁剪图片
  • android:tileMode 平铺模式

默认为 disabled,不为 disabled 时,gravity 属性会被忽略

  • disabled 关闭平铺模式
  • clamp 拉伸像素
  • repeat 水平和垂直方向平铺
  • mirror 镜像平铺
BitmapDrawable 内部宽高
    @Override
    public int getIntrinsicWidth() {
        return mBitmapWidth;
    }

    @Override
    public int getIntrinsicHeight() {
        return mBitmapHeight;
    }

可以看到 BitmapDrawable 返回的宽高就是 Bitmap 的宽高,Bitmap 的宽高是在 computeBitmapSize() 方法中赋值的:

private void computeBitmapSize() {
        final Bitmap bitmap = mBitmapState.mBitmap;
        if (bitmap != null) {
            mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
            mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
        } else {
            mBitmapWidth = mBitmapHeight = -1;
        }
    }

如果 mBitmapState 中的成员变量 mBitmap 不为 null 的话,把 mTargetDensity 作为参数调用 Bitmap 的 getScaledXXX 方法。
这里的 mTargetDensity 是 Drawable 的目标密度,在构造方法中会进行赋值,也可以通过 setTargetDensity 方法赋值,默认为设备的屏幕像素密度。
Bitmap 也有一个成员变量 mDensity 是自身的像素密度,在 getScaledXXX 方法中会根据 mTargetDensity / mDensity 对 Bitamp 的宽高尺寸进行缩放。

public int getScaledHeight(int targetDensity) {
        return scaleFromDensity(getHeight(), mDensity, targetDensity);
    }

    /**
     * @hide
     */
    static public int scaleFromDensity(int size, int sdensity, int tdensity) {
        if (sdensity == DENSITY_NONE || tdensity == DENSITY_NONE || sdensity == tdensity) {
            return size;
        }

        // Scale by tdensity / sdensity, rounding up.
        return ((size * tdensity) + (sdensity >> 1)) / sdensity;
    }
Bitmap 和 Drawable 的转换
  1. Bitmap --> Drawable:
    new BitampDrawable(bitmap)

二、NinePatchDrawable

.9格式的图片。BitmapDrawable 会根据 View 的大小进行拉伸,而.9图片可自动地根据所需的宽/高进行相应的缩放并保证不失真。
同样可以通过 xml 文件来描述,属性同 bitmap

三、ShapeDrawable & GradientDrawable

属性


    
    
    
    
    
    

  • android:shape 默认为 rectangle,line 和 ring 必须通过标签 来指定宽度和颜色;
    当 shape 为 ring 时,有五个特殊属性:
  • android:innerRadius 圆环内半径,会覆盖 innerRadiusRatio;
  • android:innerRadiusRatio 圆环内半径所占比率,默认为9;
  • android:thickness 圆环厚度,会覆盖 thicknessRaio;
  • android:thicknessRatio 圆环厚度所占比率,默认为3;
  • android:useLevel 常为false,除非它被当做是LevelListDrawable;
  • :表示shape的四个圆角的角度,只适用于矩形。
  • :渐变效果,与 的纯色填充相互排斥。
  • android:type:渐变的类别。有linear(线性渐变)、radial(径向渐变)、sweep(扫描线渐变),默认为linear。
  • android:centerX:渐变的中心点的X坐标。
  • android:centerY:渐变的中心点的Y坐标。
  • android:gradientRadius :渐变半径。仅当android:type="radial"时有效。
  • android:angle:渐变角度,默认为0,必须为45的倍数,0表示从左到右,90表示从上到下,仅在 linear 时有效
  • :描边。
  • android:width:描边的宽度。
  • android:color:描边的颜色。
  • android:dashWidth:虚线的宽度。
  • android:dashGap:虚线之间的间隔。
  • :填充纯色
  • :内边距
  • :大小。其android:width和android:height分别设定shape的宽/高。注意,这个表示的是shape的固有大小,但并不是其最终大小。
用代码创建

通过 inflate 方法解析 xml 文件中的属性,也可以使用构造方法来创建 ShapeDrawable 对象:

public ShapeDrawable()
public ShapeDrawable(Shape s)
private ShapeDrawable(ShapeState state, Resources res)

ShapeDrawable 有三个构造方法,第一个没有参数,第二个传入一个 Shape 对象,最终都是调用了第三个,但是第三个构造方法是 private 修饰的,第三个方法的第一个参数是一个 ShapeState 对象,ShapeState 类继承自 Drawable 类的静态内部类 ConstantState ,ShapeState 封装了当前 Drawable 的重要属性, ShapeState是Drawable 自己的保存状态量和数据的重要对象.。在该方法中给 ShapeDrawable 的成员变量 mShapeState 赋值,并初始化 PorterDuffColorFilter 类型成员变量 mTintFilter。
但是其实 标签定义的不是 ShapeDrawable 而是 GradientDrawable。
Drawable 类也有三个构造方法:

public GradientDrawable()
public GradientDrawable(Orientation orientation, @ColorInt int[] colors)
private GradientDrawable(@NonNull GradientState state, @Nullable Resources res)

最终都是调用了 private 的两个参数的构造方法,第一个参数是 ConstantState 的子类 GradientState,第二个参数还是 Resources 对象。
GradientState 的构造方法有两个:

public GradientState(Orientation orientation, int[] gradientColors) {
            mOrientation = orientation;
            setGradientColors(gradientColors);
 }
public GradientState(@NonNull GradientState orig, @Nullable Resources res)

也就是说,在创建 GradientState 时,必须要确定渐变的方向和渐变颜色:
Orientation 是一个内部枚举类:

public enum Orientation {
        TOP_BOTTOM, //从上到下 angle = 90
        TR_BL,//从右上到左下   angle = 135
        RIGHT_LEFT,//从右向左 angle = 180
        BR_TL,//从右下到左上  angle = 225
        BOTTOM_TOP,//从下到上 angle = 270
        BL_TR,//从左下到右上  angle = 315
        LEFT_RIGHT,//从左到右   angle = 0
        TL_BR,//从左上到右下 angle = 45
    }
public void setGradientColors(@Nullable int[] colors) {
            mGradientColors = colors;
            mSolidColors = null;
            computeOpacity();
        }

标签和 标签相互冲突,以及 标签定义的属性分别存储在以下三个成员变量中

        public ColorStateList mSolidColors; 
        public ColorStateList mStrokeColors;
        public @ColorInt int[] mGradientColors;

GradientDrawable 类对外提供了一系列方法设置相关属性:


  • setShape(@Shape int shape),参数为 GradientDrawable 内部定义的 int 类型常量

  • setCornerRadius(float radius)
    setCornerRadii(@Nullable float[] radii)

  • setGradientType(@GradientType int gradient) 参数也为静态常量
    setGradientCenter(float x, float y)
    setGradientRadius(float gradientRadius)

  • setColor(@ColorInt int argb)
    setColor(@Nullable ColorStateList colorStateList)

  • setStroke(int width, @ColorInt int color)
    setStroke(int width, ColorStateList colorStateList)
    setStroke(int width, @ColorInt int color, float dashWidth, float dashGap)
    setStroke(
    int width, ColorStateList colorStateList, float dashWidth, float dashGap)

  • setSize(int width, int height)

四、StateListDrawable

下面罗列了 selector 的所有 state,android:drawable 属性引用drawable 资源,也可以在 标签中定义其它 drawable 。
android:contantSize 属性为 true 时,StateListDrawable 固有大小保持不变,是内部所有 Drawable 的固有大小的最大值。false 则会随着状态的改变而改变;
android:variablePadding 属性为 true 时表示 padding 随着状态改变而改变,为 false 表示 padding 为内部所有 drawable 的 padding 最大值保持不变;


    
          
          
          
          
          
          
          
          
          
          
          
          
          
         
         
         
    

StateListDrawable 类有三个构造方法:

public StateListDrawable() 
private StateListDrawable(StateListState state, Resources res)
StateListDrawable(@Nullable StateListState state)

构造方法传入了一个 StateListState 参数,这个 StateListState 不是继承自 Drawable.ConstantState 类,而是继承自 DrawableContainer.DrawableContainerState 类,它的构造方法是 StateListState(StateListState orig, StateListDrawable owner, Resources res)
构造方法内部都是创建一个 StateListState 对象,然后调用了 setConstantState(DrawableContainerState state) 方法给 成员变量 mStateListState 赋值。
StateListState 内部有一个二维数组 mStateSets 保存着所有的状态和 Drawable。给 StateListDrawable 添加 item 就是通过调用 addState 方法,state 是放在一个 int 数组里面的。

public void addState(int[] stateSet, Drawable drawable) {
        if (drawable != null) {
            mStateListState.addStateSet(stateSet, drawable);
            // in case the new state matches our current state...
            onStateChange(getState());
        }
    }

你可能感兴趣的:(【Android Drawable】二、BitmapDrawable、NinePatchDrawable、GradientDrawable、StateListDrawable)