Android bitmap Drawable

参考
Drawable子类之—— BitmapDrawable (可控制对齐平铺的图像)

明明图片拉进去对应的文件之后我们就直接设置为背景,那么谷歌还要弄一个BitmapDrawable干嘛,简单说就是你直接设背景能控制背景怎么对齐吗,能控制背景如何平铺吗,不能。

一、Drawable简介

Drawable有很多种,它们都表示一种可以在Canvas上进行绘制的图像概念,但是它们又不全是图片,通过颜色也可以构造出各式各样的图像效果。Drawable使用简单,比自定义view的成本要低。另外,非图片类型的Drawable占用空间较小,这对减小apk的大小也有帮助。
在实际开发中,Drawable常被用作View的背景或者作为ImageView中的图像显示。Drawable一般都是通过XML来定义的,也可以通过代码构造。

二、Canvas

名为画布,我们可以看作是一种处理过程,使用各种方法来管理Bitmap、GL或者Path路径,同时它可以配合Matrix矩阵类给图像做旋转、缩放等操作,同时Canvas类还提供了裁剪、选取等操作。Canvas主要用于2D绘图,那么它也提供了很多相应的drawXxx()方法,方便我们在Canvas对象上画画,drawXxx()具有多种类型,可以画出:点、线、矩形、圆形、椭圆、文字、位图等的图形,这里就不再一一介绍了,只介绍几个Canvas中常用的方法:
void drawBitmap(Bitmap bitmap,float left,float top,Paint paint):
android系统不允许直接修改原图,类似Photoshop中的锁定,必须通过原图创建一个同样大小的Bitmap,并将原图绘制到该Bitmap中,以一个副本的形式来修改图像。代码如下,bm为原图,bmp为创建的副本。
<pre>
Bitmap bmp = Bitmap.createBitmap(bm.getWidth(),bm.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint();
canvas.drawBitmap(bm,0,0,paint);
</pre>

void drawLine(float startX,float startY,float stopX,float stopY,Paint paint):根据给定的起始点和结束点之间绘制连线
void drawPath(Path path,Paint paint):根据给定的path,绘制连线
void drawPoint(float x,float y,Paint paint):根据给定的坐标,绘制点
void drawText(String text,int start,int end,Paint paint):根据给定的坐标,绘制文字
int getHeight():得到Canvas的高度
int getWidth():得到Canvas的宽度
详细可参考《Android群英传》P117

三、Paint

我们可以把它看做一个画图工具,比如画笔、画刷。他管理了每个画图工具的字体、颜色、样式,主要用于设置绘图风格,包括画笔颜色、画笔粗细、填充风格等。如果涉及一些Android游戏开发、显示特效可以通过这些底层图形类来高效实现自己的应用。 Paint中提供了大量设置绘图风格的方法,这里仅列出一些常用的:
setARGB(int a,int r,int g,int b):设置ARGB颜色。
setColor(int color):设置颜色。
setAlpha(int a):设置透明度。
setPathEffect(PathEffect effect):设置绘制路径时的路径效果。
setShader(Shader shader):设置Paint的填充效果。
setAntiAlias(boolean aa):设置是否抗锯齿。
setStrokeWidth(float width):设置Paint的笔触宽度。
setStyle(Paint.Style style):设置Paint的填充风格。
setTextSize(float textSize):设置绘制文本时的文字大小。
setXfermode(Xfermode xfermode):设置绘制的渲染模式

四、Canvas,Drawable,Paint关系

Canvas就是一张画布,上面可以让你画你想画的东西,你可以想像成他就是小画家工具。那画完以后怎么办?很简单,把它装到容器里面,容器有哪些?就是我们前面讲的ImageView、GridView、ListView…等等,这是系统帮我们做好的容器,不过这次是存成属于自己的View,讲白话一点就是把我们画的东西包成一个容器,容器里面装的是我们的画布。
每个Drawable都会有一个draw的方法,它就是会帮你把这些图形贴到画布上面,然后再装到自定的容器View里面,最后就变成一种容器,看你是要装进系统的容器或者直接呈现出来都可以。
Paint就是画笔,你在小画家上面画画的时候,都会选择画笔来作画,像什么颜色啊,粗细啊之类的属性,像上面的例子当中,我们取得Drawable的画笔,然后将画笔的颜色改成蓝色,这样画出来的颜色就会变成蓝色的矩形了。那是画在哪边?当然是画布上面,通常Paint都会跟在Drawable的相关类别或者自定View类别一起使用。

五、Canvas的使用方式

以下参考Andriod中绘(画)图----Canvas的使用详解
Canvas的两种使用情形,从Canvas对象的获得角度分析:

  • 1、 自定义View和自定义SurfaceView中获得Canvas对象
    由于自定义View和SurfaceView在显示界面中已经获得了显示区域,canvas对象只不过是在其显示(绘画)区域进行界面布局的设计,当操作完毕后,系统会显示canvas的操作结果。自定义View的绘图方法为:
    <pre>
    //存在canvas对象,即存在默认的显示区域
    @Override
    public void draw(Canvas canvas) {
    //canvas绘图
    }
    </pre>

  • 2、在其他情形下,我们需要通过代码创建一个Canvas对象,并且在绘画成功后,将该画图区域转换为Drawable图片或者通过setBitmap(bitmap)显现出来。一般步骤为:
    <pre>
    //创建一个的Bitmap对象
    Bitmap bitmap = Bitmap.createBitmap(200, 100, Config.ARGB_8888);
    //创建一个canvas对象,并且开始绘图
    Canvas canvas = new Canvas (bitmap);
    ImageView imgView = new ImageView(this);//或者其他可以设置背景图片的View控件
    //为ImageView设置图像
    //将Bitmap对象转换为Drawable图像资
    Drawable drawable = new BitmapDrawable(bitmap);
    imgView .setBackgroundDrawable(drawable);
    //或者简单点:imgView.setImageBitmap(bitmap);
    </pre>

六、【Android】Drawable、Bitmap、Canvas、Paint之间区别

(1)Bitmap 转化为 byte
<pre>
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
byte[] array= out.toByteArray();
</pre>

(2)byte转化为bitmap
<pre>
private Bitmap Bytes2Bimap(byte[] b){
if(b.length!=0){
return BitmapFactory.decodeByteArray(b, 0, b.length);
}
else {
return null;
}
}
</pre>

(3)bitmap 转换 drawable
<pre>
Bitmap bitmap = new Bitmap(...);
Drawable drawable = new BitmapDrawable(bitmap);
//Drawable drawable = new FastBitmapDrawable(bitmap);
</pre>

(4)Drawable to Bitmap
<pre>
public static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
drawable.getOpacity() != PixelFormat.OPAQUE ?Bitmap.Config.ARGB_8888: Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
//canvas.setBitmap(bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
</pre>

七、自定义Drawable

通常我们没有必要自定义Drawable,这是因为自定义的Drawable无法在XML中使用,使用范围有限。如果要自定义Drawable,draw、setAlpha、setColorFilter、getOpacity这几个方法必须要实现。
以下是个圆形的drawable,半径会随着view的变化而变化。
<pre>
public class CustomDrawable extends Drawable{
private Paint mPaint;
public CustomDrawable(int color){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(color);
}
@override
public void draw(Canvas canvas){
final Rect r = getBounds();
float cx = r.exactCenterX();
float cy = r.exxactCenterY();
canvas.drawCircle(cx,cy,Math.min(cx,cy),mPaint);
}
@override
public void setAlpha(int alpha){
mPaint.setAlpha(alpha);
invalidateSelf();
}
@override
public void setColorFilter(ColorFilter cf){
mPaint.setColorFilter(cf);
invalidateSelf();
}
@override
public int getOpacity(){
return PixelFormat.TRANSLUCENT;
}
}
</pre>

八、Android中的13种Drawable小结

1.BitmapDrawable
参考Drawable子类之—— BitmapDrawable (可控制对齐平铺的图像)

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/image1"
    android:tileMode="repeat"
     />

2.NinePatchDrawable

<?xml version="1.0" encoding="utf-8"?>
<nine-patch xmlns:android="http://schemas.android.com/apk/res/android
    android:dither="false"
  android:src="@drawable/a" />

注意:@drawable/a中的a图片就是drawable中a.9.png图片

3.ShapeDrawable
参考Drawable子类之—— ShapeDrawable (图形定义)
通过颜色来构造图片,可以是纯色,也可以是渐变色。
比如给按钮背景图(纯色背景、带边框、圆角)可以用shape而不是Png图片:

Paste_Image.png
<?xml version="1.0" encoding="utf-8"?>
<selector
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <stroke android:width="0.5dp" android:color="@color/white"/>
            <gradient android:startColor="#ffffff" android:endColor="#ffffff" android:angle="0.0" />
            <corners android:topLeftRadius="4dp" android:topRightRadius="0dp" android:bottomLeftRadius="4dp" android:bottomRightRadius="0dp" />
        </shape>
    </item>
</selector>

4.LayerDrawable
参考Drawable子类之——LayoutDrawable (图层叠加)
层次化的drawable集合,有叠加效果。使用item标签来表示一个Drawable,可以有多个item.
有些需求中需要一种图片,但是明显这个图片是其他几个图片简单叠加而已,那么可以使用layer-list来达到目的.

Paste_Image.png
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <!-- 最底层的图片,以x,y轴坐标为中心进行旋转-->
        <rotate android:pivotX="0" android:pivotY="0"
                android:fromDegrees="-10" android:toDegrees="-10">
            <bitmap android:src="@drawable/chatting_bg_default_thumb"/>
         </rotate>
    </item>
    <!-- 第二层的图片,以x,y轴坐标为中心进行旋转-->
    <item>
        <rotate android:pivotX="0" android:pivotY="0"
                android:fromDegrees="15" android:toDegrees="15">
            <bitmap android:src="@drawable/chatting_bg_purecolor_thumb"/>
        </rotate>
    </item>
    <!-- 最上层的图片,以x,y轴坐标为中心进行旋转-->
    <item>
        <rotate android:pivotX="0" android:pivotY="0"
                android:fromDegrees="35" android:toDegrees="55">
            <bitmap android:src="@drawable/mark"/>
        </rotate>
    </item>
</layer-list>

5.StateListDrawable
也是一个drawable集合,每个Drawable对应view一个状态,系统会根据当前View的状态从selector中选择对应的item
<selector...>
<item...>
<item...>
<item...>
</selector>

6.LevelListDrawable
drawable集合,里面每个drawable都对应一个等级。通过setLevel方法设置不同等级可以切换具体的drawable。

7.TransitionDrawable
参考Drawable子类之——TransitionDrawable (渐变)

transition.gif

transition_simple.xml

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@mipmap/pic1" />
    <item android:drawable="@mipmap/pic2" />
</transition>

import android.app.Activity;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView image = (ImageView) findViewById(R.id.mIv);

        //得到一个Drawable,属于 TransitionDrawable 类型的
        TransitionDrawable transition = (TransitionDrawable)getResources().
                getDrawable(R.drawable.transition_simple);

        image.setImageDrawable(transition);
        transition.startTransition(2000); // 设定渐变的变化市场

    }
}

8.InsetDrawable
参考Drawable子类之——InsetDrawable (嵌入)
将其它Drawable嵌入自己当中,并可以在四周留出一定的间距。
InsetDrawable对应的标签是<inset>他可以将其他的Drawable内嵌到自己的里面。个人觉得其实没什么用,他能做到的,LayerDrawable也能做,或者有的时候直接设置一下padding就可以了。

Paste_Image.png
insetdrawable_simple.xml

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetBottom="60dp"
    android:insetLeft="30dp"
    android:insetRight="30dp"
    android:insetTop="60dp" >

    <!--待会要插入的一个蓝色的矩形-->
    <shape android:shape="rectangle" >
        <solid android:color="#0000ff" />
    </shape>
</inset>

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context=".MainActivity">

    <!--Inset这东西其实就没什么用,大概也就这样子吧,
    背景一个,图片一个,利用Inset让背景比较大-->
    <ImageView
        android:id="@+id/mIv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:background="@mipmap/op"
        android:src="@drawable/insetdrawable_simple"
         />
</RelativeLayout>

9.ScaleDrawable
根据自己的等级将指定的drawable缩放到一定比例。
<scale...

10.ClipDrawable
参考Drawable子类之——ClipDrawable (裁剪图像)
根据当前等级裁剪一个Drawable,裁剪方向受clipOrientation和gravity两个属性共同控制。

Paste_Image.png

clipdrawable_simple.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="@mipmap/star"
        android:layout_marginBottom="20dp"/>


    <ImageView
        android:id="@+id/mIvClip"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="@drawable/clipdrawable_simple"
        />
</LinearLayout>

import android.app.Activity;
import android.graphics.drawable.ClipDrawable;
import android.os.Bundle;
import android.widget.ImageView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView imageView = (ImageView) findViewById(R.id.mIvClip);
        //ClipDrawable clipDrawable = (ClipDrawable) imageView.getDrawable(); 这样写会报空指针异常
        ClipDrawable clipDrawable = (ClipDrawable) imageView.getBackground();
        clipDrawable.setLevel(5000);

    }
}

11.RotateDrawable
这里两个图片是两个按钮箭头,但是仅仅方向不同而已,其实可以只用其中一个图片即可,而另一个用RotateDrawable来让其“调转”180度

Paste_Image.png
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_arrow_left"
    android:fromDegrees="180"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="180" />
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容