yunshuipiao / Potato

Read the fucking source code for the Android interview
Apache License 2.0
80 stars 12 forks source link

Android:Drawable 和 Bitmap #63

Open yunshuipiao opened 5 years ago

yunshuipiao commented 5 years ago

Android:Drawable 和 Bitmap

[TOC]

这篇文章简单介绍下不同的 Drawable 和 Bitmap 的关系,以及各种的 Drawable。

Drawable

其中 Drawable 的注释如下:

A Drawable is a general abstraction for "something that can be drawn." Most often you will deal with Drawable as the type of resource retrieved for drawing things to the screen; the Drawable class provides a generic API for dealing with an underlying visual resource that may take a variety of forms. Unlike a View, a Drawable does not have any facility to receive events or otherwise interact with the user.

public abstract class Drawable {
 ......
}

这里看到 Drawable 只是一个抽象概念, 表示"something that can be drawn".

下面紧接着有一段话:

Though usually not visible to the application, Drawables may take a variety of forms:

  • Bitmap: the simplest Drawable, a PNG or JPEG image.
  • Nine Patch: an extension to the PNG format allows it to specify information about how to stretch it and place things inside of it.
  • Vector: a drawable defined in an XML file as a set of points, lines, and curves along with its associated color information. This type of drawable can be scaled without loss of display quality.
  • Shape: contains simple drawing commands instead of a raw bitmap, allowing it to resize better in some cases.
  • Layers: a compound drawable, which draws multiple underlying drawables on top of each other.
  • States: a compound drawable that selects one of a set of drawables based on its state.
  • Levels: a compound drawable that selects one of a set of drawables based on its level.
  • Scale: a compound drawable with a single child drawable, whose overall size is modified based on the current level.

Drawable 是一个抽象的概念, 而 Bitmap 是其存在的实体之一.

Bitmap

类的定义如下:

public final class Bitmap implements Parcelable { 
...
}

没有实现 Drawable, 而是通过 BitmapDrawable 将两者联系起来。

public class BitmapDrawable extends Drawable {
... 
}

在 Drawable 类中有一个方法:

    private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np,
            Rect pad, Rect layoutBounds, String srcName) {

        if (np != null) {
            return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
        }

        return new BitmapDrawable(res, bm);
    }

通过 Bitmap 的构造函数,可以将 Bitmap 转换为 Drawable。

在 BitmapDrawable 中同样可以得到 Bitmap 对象:

    public final Bitmap getBitmap() {
        return mBitmapState.mBitmap;
    }

简单来说:

可以简单地理解为 Bitmap 储存的是 像素信息,Drawable 储存的是 对 Canvas 的一系列操作

而 BitmapDrawable 储存的是「把 Bitmap 渲染到 Canvas 上」

这个操作。

各种 Drawable

android内置了如下几种Drawable类型:ColorDrawable、GradientDrawable、BitmapDrawable、 NinePatchDrawable、InsetDrawable、ClipDrawable、ScaleDrawable、 RotateDrawable、AnimationDrawable、LayerDrawable、LevelListDrawable、 StateListDrawable、TransitionDrawable ShapeDrawable。 Android把可绘制的对象抽象为Drawable,不同的图形图像资源就代表着不同的drawable类型。Android FrameWork提供了一些具体的Drawable实现,通常在代码中都不会直接接触Drawable的实现类。

ColorDrawable

ColorDrawable通常设置在colors.xml文件中,比如设置View背景为纯色,实际设置的就是ColorDrawable.

public void setBackgroundColor(@ColorInt int color) {
        if (mBackground instanceof ColorDrawable) {
            ((ColorDrawable) mBackground.mutate()).setColor(color);
            computeOpaqueFlags();
            mBackgroundResource = 0;
        } else {
            setBackground(new ColorDrawable(color));
        }
    }

颜色可绘制类。类构造时指定一个颜色,或者调用setColor指定颜色,setAlpha函数会把设置的透明度和本来的颜色的透明度相乘。这个可绘制类用来实现简单的单颜色的绘制。

GradientDrawable

GradientDrawable通常用来设置渐变色。写在XML文件中通常和shape结合使用


<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:startColor="#FFF"
        android:endColor="#000"
        android:angle="45" />
</shape>

BitmapDrawable 位图可绘制类

位图可绘制类。在构造时指定一个Bitmap对象或者一个位图文件。位图显示时需要指定:像素和设备尺寸的映射,显示的位置,显示模式三种属性

因为位图里面的像素是一个抽象的概念他没有具体的物理尺寸,而设备的像素则是物理的,他有大小。因此需要有一个方法来指定位图像素转化为物理像素的映射关系,这样位图的像素才可以真正的显示在设备上。下面就是提供的三种映射设置方法:

//画布上的密度比值
 public void setTargetDensity(Canvas canvas)

//当前屏幕的密度比值
public void setTargetDensity(DisplayMetrics metrics)

//指定密度比值,注意这里的密度是DisplayMetrics中的DENSITY_XXX。
public void setTargetDensity(int density)

系统会根据密度公式:* 位图尺寸 density / 屏幕的密度 ** 来将位图显示在具体的设备上。

你需要为位图指定绘制到画布上的位置以及缩放到区域的方式:

//这里的android.view.Gravity参考值。比如显示在左上角,比如拉伸显示在整个画布中等等
public void setGravity(int gravity)

ClipDrawable 裁剪可绘制类

这个是一个Drawable的修饰派生类,构造函数是对某个Drawable对象进行裁剪显示。裁剪的范围设置通过setLevel来设置,0为全部不显示,10000为全部显示,设置了范围之后还需要设置裁剪的方向和从什么地方开始裁剪,参考构造函数:

public ClipDrawable(Drawable drawable, int gravity, int orientation)

ClipDrawable主要的应用场景是让某个Drawable逐渐进行展开或者收缩显示,而这都是通过调用setLevel方法来完成的。

AnimationDrawable 帧动画可绘制类

这是一个容器可绘制类,用于定期播放一批指定的Drawable。不可以和ClipDrawable结合起来播放逐渐展开的动画。这个类里面的一个Drawable对象就是一帧。下面的一系列方法分别用来管理这些帧动画:

public void addFrame(Drawable frame, int duration)  //添加要播放的Drawable帧以及播放时长。
public int getDuration(int i)   //每帧时长
public Drawable getFrame(int index) //获取帧
public int getNumberOfFrames()   //得到总帧数
public void setOneShot(boolean oneShot)  //单次还是循环

InsetDrawable缩进可绘制类

这个是一个容器类。实现容器内Drawable四个方向缩进或者某个方向的缩进。如果为负数则是外缩进,这个类也可以实现缩放的功能,注意这里不是裁剪,而是会有缩放效果。

ScaleDrawable 缩放可绘制类

这个一个容器类,可以用来缩放另外一个Drawable对象。你可以在构造中指定缩放的比例和缩放的中心点,注意的是所缩放的Drawable对象的level不能为0.

RotateDrawable 旋转可绘制类

这个可绘制类不支持代码建立,只支持XML文件构造。可以指定开始角度,结束角度,旋转的中心点。 最后可以通过setLevel来控制从开始到结束的角度中间的过程。下面是一个XML来设置旋转可绘制类的方法.

ShapeDrawable 形状可绘制类。

用于建立各种形状。对于形状的边线来说可以通过如下方法来获取一个Paint对象并设置画笔和阴影效果.

PaintDrawable 圆角矩形可绘制类。

这个类是ShapeDrawable的派生类。是圆角矩形RoundRectShape的简化版本,只会设置外圆角,只需要设置一个或者8个即可。一般用这个类来设置圆角按钮背景。

LayerDrawable 图层可绘制类。

用于重叠多个可绘制对象。这是一个容器可绘制类,里面可以添加多个子可绘制对象,每个子可绘制对象就是其中的一层。

TransitionDrawable 淡入淡出可绘制类

这个类是LayerDrawable的子类,可以实现动画效果。这个类只支持2个子可绘制对象,所展示的效果是第0层慢慢变淡消失,第一层慢慢清楚显示。

NinePatchDrawable .9格式的可绘制类

.9格式的可绘制类,一般用于那些需要特定区域拉伸显示的场景,比如气泡对话框。.9格式的图片一般用png文件来实现。

GradientDrawable 渐变的可绘制类。

渐变可绘制类提供了一种多颜色过渡显示效果的可绘制类。根据颜色过渡的方式系统默认提供的渐变有线性渐变(LINEAR_GRADIENT)放射渐变(RADIAL_GRADIENT)旋转扫描渐变(SWEEP_GRADIENT)三种类型。你可以通过如下方法来设置可绘制对象的渐变类型: