Android开发知识集Android技术知识Android知识

【Android Drawable】二、BitmapDrawab

2017-04-26  本文已影响144人  秀花123

一、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=""

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

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

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

纹理映射

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

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

属性
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle|oval|line|ring"
    android:innerRadius=""
    android:innerRadiusRatio=""
    android:thickness=""
    android:thicknessRatio=""
    android:useLevel="">
    <corners android:radius=""
        android:topLeftRadius=""
        android:topRightRadius=""
        android:bottomLeftRadius=""
        android:bottomRightRadius=""/>
    <gradient
        android:type="linear|radio|sweep"
        android:startColor=""
        android:centerColor=""
        android:endColor=""
        android:centerX=""
        android:centerY=""
        android:angle=""
        android:gradientRadius=""
        android:useLevel=""/>
    <padding android:top=""
        android:bottom=""
        android:left=""
        android:right=""/>
    <size
        android:width=""
        android:height=""/>
    <solid
        android:color=""/>
    <stroke
        android:color=""
        android:width=""
        android:dashWidth=""
        android:dashGap=""/>
</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。
但是其实 <shape> 标签定义的不是 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();
        }

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

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

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

四、StateListDrawable

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

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize=""
    android:variablePadding="">
    <item android:state_accelerated=""
        android:state_active=""
        android:state_activated=""
        android:state_checkable=""
        android:state_checked=""
        android:state_drag_can_accept=""
        android:state_drag_hovered=""
        android:state_enabled=""
        android:state_first=""
        android:state_focused=""
        android:state_hovered=""
        android:state_last=""
        android:state_middle=""
        android:state_pressed=""
        android:state_selected=""
        android:state_single=""
        android:state_window_focused=""
        android:drawable="">
          <color android:color=""/>
          <bitmap android:src=""/>
          <nine-patch android:src=""/>
          <clip android:drawable="" />
          <inset android:drawable="" />
          <scale android:drawable=""/>
          <ripple android:color=""/>
          <rotate android:drawable=""/>
          <transition />
          <layer-list></layer-list>
          <level-list></level-list>
          <shape ></shape>
          <selector></selector>
         <animation-list></animation-list>
         <animated-rotate />
         <animated-selector android:fromId="" android:toId=""/>
    </item>
</selector>

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());
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读