章节索引 :

图片资源:Drawable

在学习 View 的时候,我们学习过 ImageView。它除了在 xml 的 src 属性中设置图片之外,还可以通过setImageDrawable( )setBackgroundDrawable( )两个 API 设置图片资源。这两个 API 都包含一个关键词——Drawable,那么我们这一节就来看看,Drawable 到底是个什么东西。

1. Drawable 是什么

Drawable 从字面上理解就是一个可绘制的图形对象,最简单的例子就是常用的 Bitmap 对象,在 Android 中可以通过一个 BitmapDrawable 对象来呈现。
每一个 Drawable 内部都保存了一个“res/drawable”目录下的私有文件,比如我们会将不同分辨率的图片资源存储在“mdpi”、“hdpi”、“xhdpi”以及“xxhdpi”里面,这些目录是在创建工程的时候 Android Studio 自动帮我们生成好的,然后在运行的时候系统会根据当前的设备类型自动选择一种合适的 bitmap 图片资源为我们所用。

2. 为 View 设置 Drawable

在 xml 中使用是很最常见的用法,而且我们一直在用,回顾一下我们设置的图片资源,比如一个 TextView 的背景样式,通常会这么写:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textview"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/text"
    android:text="@string/hello_world" />

其中 background 属性的值就是一个 Drawable 对象,同样我们可以在 Java 代码中给 View 设置一个 Drawable 参数:

ImageView imageView = (ImageView) findViewById(R.id.imageview);
imageView.setImageResource(R.drawable.image);

3. 加载 Bitmap 和 Drawable

Android 提供了一个Bitmap类来处理 bitmap 图片相关的功能,接下来我们看看如何通过 Java 代码创建一个 Bitmap 并将 Bitmap 转换成 Drawable:

        ​AssetManager manager = getAssets();

       ​// 从 assets 中读取 bitmap
       ​InputStream open = null;
       ​try {
           ​open = manager.open("imooc.png");
           ​Bitmap bitmap = BitmapFactory.decodeStream(open);
           ​// 给 imageView 设置 bitmap 对象
           ​ImageView view = (ImageView) findViewById(R.id.imageView1);
           ​view.setImageBitmap(bitmap);
       ​} catch (IOException e) {
           ​e.printStackTrace();
       ​} finally {
           ​if (open != null) {
               ​try {
                   ​open.close();
               ​} catch (IOException e) {
                   ​e.printStackTrace();
               ​}
           ​}

除此之外,还可以从“res/drawable”文件夹中获取 Drawable,并在代码中转换成 Bitmap 对象,如下:

Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap);

在获取的同时,我们还可以对图像进行任意比例的缩放:

Bitmap originalBitmap = getBitmap();

Bitmap resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, false);

反过来,我们也可以将 Bitmap 转换成一个 Drawable 对象:

Drawable drawable = new BitmapDrawable(getResources(),bitmap);

4. 通过 xml 声明 Drawable

我们可以在 xml 中声明很多种类型的 Drawable,用于对各种动画、背景、状态等等进行描述。

4.1 Shape Drawables

Shape Drawables 可以用来定义一个 View 的外形、颜色、渐变等等属性,它的最大的有点就是可以根据任意尺寸的 View
进行自适应,代码示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <stroke
        android:width="10dp"
        android:color="#FFFFFFFF" />
    <gradient
        android:endColor="#EF3434AB"
        android:startColor="#FF98df9d"
        android:angle="45" />
    <corners
        android:bottomRightRadius="10dp"
        android:bottomLeftRadius="10dp"
        android:topLeftRadius="5dp"
        android:topRightRadius="5dp" />
</shape>

以上代码分别为背景设置了边框、渐变、角弧度,编写完直接作为背景资源设置即可:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/myshape"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
     >
    </EditText>

    <RadioGroup
        android:id="@+id/radioGroup1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <RadioButton
            android:id="@+id/radio0"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:checked="true"
            android:text="@string/celsius" >
        </RadioButton>

        <RadioButton
            android:id="@+id/radio1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/fahrenheit" >
        </RadioButton>
    </RadioGroup>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/calc"
        android:onClick="myClickHandler">
    </Button>

</LinearLayout>

4.2 State Drawables

State Drawables 用来描述一个 View 在不同状态下的形态,我们可以给每一种状态设置一中背景样式,比如我们可以让我们的 Button 在点击、选择和默认态下呈现不同的样式:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/button_pressed"
        android:state_pressed="true" />
    <item android:drawable="@drawable/button_checked"
        android:state_checked="true" />
    <item android:drawable="@drawable/button_default" />

</selector>

4.3 Animation Drawables

Animation Drawables 是一种动画资源,我们可以将动画的时长、形态、起终点等信息描述在 xml 中,如下:

 <animation-list android:id="@+id/selected" android:oneshot="false">
    <item android:drawable="@drawable/phase1" android:duration="100" />
    <item android:drawable="@drawable/phase2" android:duration="200" />
    <item android:drawable="@drawable/phase3" android:duration="300" />
 </animation-list>

同样在 Java 代码中直接作为背景设置:

ImageView image = (ImageView)findViewById(R.id.img);
img.setBackgroundResource(R.drawable.animation);

 AnimationDrawable frameAnimation = (AnimationDrawable) image.getBackground();
 frameAnimation.start();

4.4 自定义 Drawable

除了上面常用的系统提供的 Drawable 之外,我们还可以自定义自己想要的图片资源,在本节的示例中我们就来自定义一个资源样式。

5. Drawable 使用示例

我们通常使用的 ImageView 都是矩形的,但是为了让 UI 样式更

5.1 Drawable 实现

既然要自定义 Drawable 资源,那么首先需要创建一个类继承自 Drawable,然后在构造器中创建画笔“Paint”,然后在draw()方法中绘制图案即可,代码示例如下:

package com.emercy.myapplication;

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;

public class RoundCornerDrawable extends Drawable {

    private Paint mPaint;
    private Bitmap mBitmap;

    public RoundCornerDrawable(Bitmap bitmap) {
        this.mBitmap = bitmap;
        BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setShader(bitmapShader);
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawRoundRect(new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight()), 100, 100, mPaint);
    }

    @Override
    public void setAlpha(int i) {
        mPaint.setAlpha(i);
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        mPaint.setColorFilter(colorFilter);
    }

    // 返回drawable实际宽高
    @Override
    public int getIntrinsicWidth() {
        return mBitmap.getWidth();
    }

    @Override
    public int getIntrinsicHeight() {
        return mBitmap.getHeight();
    }
}

我们在构造器中创建了一个画笔,并传入了 Bitmap 对象,此后系统在绘制的时候回调draw()方法,完成圆角形状的绘制,这样就完成了一个圆角 bitmap 的裁剪工作。

5.2 MainActivity 主逻辑

在主逻辑中我们直接拿到 ImageView,然后获取我们要设置的 Bitmap 资源,直接通过setBackground()方法设置给 ImageView,这样呈现出来的图片就是圆角形状。


package com.emercy.myapplication;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;

import java.io.InputStream;

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.image);
        InputStream resource = getResources().openRawResource(R.raw.avatar);
        Bitmap bitmap = BitmapFactory.decodeStream(resource);
        image.setBackground(new RoundCornerDrawable(bitmap));
    }
}

编译后效果如下,展示一张圆角图片:

drawable

6. 小结

本节学习了一个很多人经常用到却很少留意的类,在给 View 设置背景、前景等图片及样式的时候都离不开 Drawable 的参与。首先需要学习系统提供的一些常用 Drawable 对象,这样其实在大多数场景都能应对,如果要处理一些特殊的样式可以采用自定义 Drawable 的方式。

环境搭建,开发相关
Android 系统背景及结构概述 Android 开发环境搭建 Genymotion 的安装与使用 Android 工程解析及使用 Android 程序签名打包
常用 UI 布局
Android 的 UI 根基 View与View Android 线性布局 LinearLayout Android相对布局RelativeLayout Android 表格布局 TableLayout Android 网格布局 GridLayout Android 帧布局 FrameLayout Android绝对布局AbsoluteLayout
基础控件
Android 文本框 TextView Android 文本输入框 EditText 按钮 Button/ImageButton 选择框 RadioButton/Check 开关控件ToggleButton/Switch Android 图片控件 ImageView Android 进度条 ProgressBar Android 拖动条 SeekBar Android 评分条 RatingBar Android 滚动条 ScrollView 轮播滚动视图 ViewFlipper
Adapter 相关控件
Android 适配器 Adapter Android 列表控件 ListView Android 网格视图 GridView Android 下拉选择框 Spinner 自动补全文本框 AutoCompleteText 折叠列表 ExpandableListView
提示类控件
吐司提示:Toast 的使用方法 状态栏通知:Notification 对话框:AlertDialog 悬浮窗:PopupWindow
菜单类控件
菜单:Menu
其他控件
视频页面:ViewPager 侧滑菜单:DrawerLayout
事件处理机制
基于监听的事件处理机制 Handler 消息传递机制 触摸事件分发处理 AsyncTask:异步任务 Android 手势处理
Android 四大组件
活动:Activity 服务:Service 广播接收器:Broadcast Receiver 内容提供者 - Content Provider
数据存储
文件存储 SharedPreferences 存储 数据库:SQLite 的使用
网络编程
HTTP 使用详解 xml 数据解析 JSON 数据解析 网页视图:WebView Socket 网络接口
绘图与动画
图片资源:Drawable 位图:Bitmap
多媒体开发
媒体播放器:MediaPlayer 相机:Camera 音频录制:MediaRecorder
并发编程
多线程