54. 【Android教程】图片资源:Drawable

简介: 54. 【Android教程】图片资源: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("mybj.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));
    }
}

6. 小结

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


相关文章
|
5月前
|
网络协议 Android开发 数据安全/隐私保护
Android手机上使用Socks5全局代理-教程+软件
Android手机上使用Socks5全局代理-教程+软件
4618 2
|
7天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
2月前
|
存储 缓存 编解码
Android经典面试题之图片Bitmap怎么做优化
本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。
64 20
Android经典面试题之图片Bitmap怎么做优化
|
3月前
|
数据处理 开发工具 数据安全/隐私保护
Android平台RTMP推送|轻量级RTSP服务|GB28181接入之文字、png图片水印的精进之路
本文探讨了Android平台上推流模块中添加文字与PNG水印的技术演进。自2015年起,为了满足应急指挥及安防领域的需求,逐步发展出三代水印技术:第一代为静态文字与图像水印;第二代实现了动态更新水印内容的能力,例如实时位置与时间信息;至第三代,则优化了数据传输效率,直接使用Bitmap对象传递水印数据至JNI层,减少了内存拷贝次数。这些迭代不仅提升了用户体验和技术效率,也体现了开发者追求极致与不断创新的精神。
|
3月前
|
自然语言处理 定位技术 API
Android经典实战之如何获取图片的经纬度以及如何根据经纬度获取对应的地点名称
本文介绍如何在Android中从图片提取地理位置信息并转换为地址。首先利用`ExifInterface`获取图片内的经纬度,然后通过`Geocoder`将经纬度转为地址。注意操作需在子线程进行且考虑多语言支持。
226 4
|
3月前
|
XML Android开发 数据格式
"探秘Android Drawable魔法:一篇文章教你玩转StateListDrawable与AnimationDrawable!"
【8月更文挑战第18天】Drawable是Android中用于屏幕绘制的图形对象,StateListDrawable与AnimationDrawable是两种实用类型。StateListDrawable可根据控件状态变化显示不同图形,如按钮的点击反馈;AnimationDrawable则用于实现帧动画效果,常用于加载提示或动态图标。两者均可通过XML定义或代码创建,并轻松应用于View的背景中,有效增强应用的交互性和视觉体验。
54 0
|
3月前
|
监控 Java 开发工具
### 绝招揭秘!Android平台GB28181设备接入端如何实现资源占用和性能消耗的极限瘦身?
【8月更文挑战第14天】本文介绍在Android平台优化GB28181标准下设备接入的性能方法,涵盖环境搭建、SDK集成与初始化。重点讲解内存管理技巧如软引用、按需加载资源,以及通过硬件加速解码视频数据和图像缩放来减轻CPU与GPU负担。同时采用线程池异步处理视频流,确保UI流畅性。这些策略有助于提高应用效率和用户体验。
46 0
|
3月前
|
XML 前端开发 Android开发
Android经典实战之Kotlin中实现圆角图片和圆形图片
本文介绍两种实现圆角图像视图的方法。第一种是通过自定义Kotlin `AppCompatImageView`,重写`onDraw`方法使用`Canvas`和`Path`进行圆角剪裁。第二种利用Android Material库中的`ShapeableImageView`,简单配置即可实现圆角效果。两种方法均易于实现且提供动态调整圆角半径的功能。
72 0
|
5月前
|
Android开发
杨老师课堂_安卓教程第一篇之入门
杨老师课堂_安卓教程第一篇之入门
37 0
|
Android开发 数据格式 XML
Android异步加载图片详解之方式二(3)
main.xml如下:   listviewitem.xml如下:   ...
815 0