res下的 drawable 是如何解析成 Drawable 对象?

Android语言基础教程(142)Android资源访问之Drawable资源:Android资源访问秘籍:Drawable资源全解析,让你的应用颜值飙升! 在Android开发世界里,Drawable资源就像是应用的“衣服”,直接影响用户体验和视觉效果。无论是按钮背景、图标还是动画,都离不开Drawable资源的身影。掌握Drawable资源的正确使用方式,能让你的应用从“能用”升级到“好用”,甚至成为应用商店中的颜值担当。 阅读详情

Drawable 可以方便的作为View的背景使用,也可以做为 ListView 的 divider 等等。在res/drawable下通过xml可以很方便的定义一个Drawable,显然我们的 View 是无法直接使用这个 xml 文件的,它必须先解析成 Drawable 对象才能供我们的 View 显示。那么这个xml文件是如何解析为 Drawable 对象的呢?

Drawable简单使用

在 res/drawable/新建一个 bg.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/black" />
</shape>

有了这个 bg.xml 我们就可以为 View 指定一个background属性了,当然也可以在 java 代码中设置:

Drawable d = getResources().getDrawable(R.drawable.bg);
view.setBackground(d);

实际上在 layout 中指定 background属性最终也会走上面的代码。接下来分析下Resources#getDrawable(int id)这个方法。这个方法负责将给定资源 id 的 drawable 文件解析成 Drawable 对象。

Resources#getDrawable(int id)

Resources#getDrawable(int id) 最终会调用 getDrawable(int id,Theme theme) ,我们看下这个方法:

public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException {
    TypedValue value;
    synchronized (mAccessLock) {
        value = mTmpValue;
        if (value == null) {
            value = new TypedValue();
        } else {
            mTmpValue = null;
        }
        getValue(id, value, true);
    }
    // 传入 id, 返回 Drawable, 重点关注
    final Drawable res = loadDrawable(value, id, theme);
    synchronized (mAccessLock) {
        if (mTmpValue == null) {
            mTmpValue = value;
        }
    }
    return res;
}

首先 getValue(value, id, theme)方法先检查指定id的xml文件是否存在。这个方法可能会对TypeValue进行一些赋值。比如后面用到的 typeValue.string应该就是制定id的文件名(带后缀的)。

然后调用loadDrawable(value, id, theme)去获取 Drawable对象。
显然重点方法是loadDrawable(value, id, theme)。跟进去这个方法:

Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
    // 省略...
    Drawable dr;
    if (cs != null) {
        dr = cs.newDrawable(this);
    } else if (isColorDrawable) {
        dr = new ColorDrawable(value.data);
    } else {
        dr = loadDrawableForCookie(value, id, null);
    }
    // 省略...
}

省略部分源码,我们重点关注 id 传入哪个方法,该方法返回值是不是 Drawable 对象。如果是,就应该重点关注。

根据这个规则猜测 loadDrawableForCookie 可能是我们想要寻找的方法,跟进去看下:

private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
    // value.string: xml 文件名
    if (value.string == null) {
        throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
                + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
    }

    final String file = value.string.toString();

    // false ,不看
    if (TRACE_FOR_MISS_PRELOAD) {
        // Log only framework resources
        if ((id >>> 24) == 0x1) {
            final String name = getResourceName(id);
            if (name != null) {
                Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
                        + ": " + name + " at " + file);
            }
        }
    }

    if (DEBUG_LOAD) {
        Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
    }

    final Drawable dr;

    Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
    try {
        // file 为我们的 drawable 文件,比如 bg.xml
        if (file.endsWith(".xml")) {
            final XmlResourceParser rp = loadXmlResourceParser(
                    file, id, value.assetCookie, "drawable");
            dr = Drawable.createFromXml(this, rp, theme);
            rp.close();
        } else {
            final InputStream is = mAssets.openNonAsset(
                    value.assetCookie, file, AssetManager.ACCESS_STREAMING);
            dr = Drawable.createFromResourceStream(this, value, is, file, null);
            is.close();
        }
    } catch (Exception e) {
        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
        final NotFoundException rnf = new NotFoundException(
                "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
        rnf.initCause(e);
        throw rnf;
    }
    Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);

    return dr;
}

重点在 try 语句,if (file.endsWith(".xml"))条件成立,接着执行loadXmlResourceParser去获取一个xml Parser解析器,注意到这里传入了我们的 id。紧接着执行/*Drawable*/ dr = Drawable.createFromXml(/*Resources*/this, rp, theme) 方法。这是一个静态方法,返回的是 Drawable 对象,并且这个 Drawable 最终会作为 loadDrawableForCookie 的返回值,然后一步一步返回到最开始的Resources#getDrawable方法。到此,我们就知道Drawable.createFromXml(Resources r, XmlPullParser parser, Theme theme) 完成了 Drawable 对象的解析工作。赶紧跟进去看下:

public static Drawable createFromXml(Resources r, XmlPullParser parser, Theme theme)
        throws XmlPullParserException, IOException {
    AttributeSet attrs = Xml.asAttributeSet(parser);

    int type;
    while ((type=parser.next()) != XmlPullParser.START_TAG &&
            type != XmlPullParser.END_DOCUMENT) {
        // Empty loop
    }

    if (type != XmlPullParser.START_TAG) {
        throw new XmlPullParserException("No start tag found");
    }

    Drawable drawable = createFromXmlInner(r, parser, attrs, theme);

    if (drawable == null) {
        throw new RuntimeException("Unknown initial tag: " + parser.getName());
    }

    return drawable;
}

重点在createFromXmlInner(r, parser, attrs, theme),继续跟进:

public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,
        Theme theme) throws XmlPullParserException, IOException {
    final Drawable drawable;
    // drawable.xml 下的跟节点
    final String name = parser.getName();
    switch (name) {
        case "selector":
            drawable = new StateListDrawable();
            break;
        case "animated-selector":
            drawable = new AnimatedStateListDrawable();
            break;
        case "level-list":
            drawable = new LevelListDrawable();
            break;
        case "layer-list":
            drawable = new LayerDrawable();
            break;
        case "transition":
            drawable = new TransitionDrawable();
            break;
        case "ripple":
            drawable = new RippleDrawable();
            break;
        case "color":
            drawable = new ColorDrawable();
            break;
        case "shape":
            drawable = new GradientDrawable();
            break;
        case "vector":
            drawable = new VectorDrawable();
            break;
        case "animated-vector":
            drawable = new AnimatedVectorDrawable();
            break;
        case "scale":
            drawable = new ScaleDrawable();
            break;
        case "clip":
            drawable = new ClipDrawable();
            break;
        case "rotate":
            drawable = new RotateDrawable();
            break;
        case "animated-rotate":
            drawable = new AnimatedRotateDrawable();
            break;
        case "animation-list":
            drawable = new AnimationDrawable();
            break;
        case "inset":
            drawable = new InsetDrawable();
            break;
        case "bitmap":
            drawable = new BitmapDrawable();
            break;
        case "nine-patch":
            drawable = new NinePatchDrawable();
            break;
        default:
            throw new XmlPullParserException(parser.getPositionDescription() +
                    ": invalid drawable tag " + name);

    }
    drawable.inflate(r, parser, attrs, theme);
    return drawable;
}

到这里瞬间恍然大悟。

这个方法会获取xml定义的根节点,根据根节点构造出相应的 Drawable对象,然后调用drawable.inflate(r, parser, attrs, theme)方法把xml定义的一些属性设置到drawable对象上。如果 Drawable 的子类有自己的属性,那么就可以重写 inflate 这个方法来解析特有的属性。

另外,注意到,在Drawable.createFromXmlInner方法,发现我们在xml 定义的 shape 实际上是 GradientDrawable,而不是 ShapeDrawable。

Android图像介绍——Drawable Drawable都表示一种图像的概念,但又不全是图片,通过颜色也可以构造出各式各样的图像效果。在实际开发Drawable常被用来作为View的背景使用。Drawable一般通过XML来定义,我们也可以通过代码来创建具体的Drawable对象。在Android设计中,Drawable是一个抽象类,它是所有Drawable的基类。Drawable的内部宽高这个参数很重要,可以通过getIntrinsicWidth和getIntrinsicHeight获取。 阅读详情

相关推荐

海康VM加密狗无法识别常见问题排查

海康VM加密狗无法识别常见问题排查

视觉人机器视觉的博客 2712

Android res/drawable、res/raw、/assets 资源文件区别及获取

文件放在res/drawable、res/raw、/assets下的区别 /res 下的文件是受android系统约束的,1、放在这个文件夹下,会被映射生成R文件,即访问时通过R.xx.xxx;2、只能有一层目录,再往底层建文件夹就访问不到了;3、打包时自动只打包用的上的文件,没用上的文件不打包;获取输入流的方式:InputStream in = getResources().openRawRes...

本然233的博客 3451

从零开始:手把手教你用VOACAP软件预测短波最佳工作频率(OWF)

本文详细介绍了如何使用VOACAP软件预测短波通信的最佳工作频率(OWF),涵盖软件安装、参数配置、电离层模型设置及结果解读。通过实战案例和优化技巧,帮助用户掌握短波传播特性,提升通信效率。特别适合业余无线电爱好者和专业通信人员参考。

weixin_30897079的博客 648

android 资源种类及使用,android 资源种类及使用

android 有很多种类的资源,有7个是在res下新建目录然后将资源放在目录下:res/values,res/xml,res/layout,res/drawable,res/anim,res/menu,res/raw还有一种是存放在res同级的目录assets目录下,也就是说大体上android资源种类有8类。res/values : 存放字符串,颜色,尺寸,数组,主题,类型等资源。res/xm...

weixin_42220853的博客 631

Vivado工程备份实战:两种方法快速迁移Block Design(附路径避坑指南)

本文详细介绍了Vivado工程中Block Design(BD)备份与迁移的两种核心方法:文件夹直接复制法与TCL脚本生成法。针对FPGA工程师在项目迁移或团队协作时常见的IP丢失、路径报错等问题,提供了从原理到实战的操作指南与路径避坑策略,确保设计可复现与高效协作。

pz890123的博客 1304

Visual Studio Code 打开java项目

在 Visual Studio Code 中打开并运行一个 Java 项目之前,你需要确保你已经完成了一些初始设置。

2674

Android应用中res/drawable文件夹下定义的各种xml文件

Android应用中res/drawable文件夹下定义的各种xml文件

Qxnedy的博客 2381

在 ABAP Push Channel 里玩转 Detached Client:用 Attach Handle 把 WebSocket 连接交接给业务逻辑

摘要:本文介绍了ABAP Push Channels (APC)中的Detached Client技术,该技术通过将WebSocket连接建立与后续处理分离,实现更高效的实时通信。核心流程包括创建连接、使用connect_and_detach交接连接、以及通过attach handle重新附着发送消息。文章还探讨了PCP协议和AMC技术在企业级推送场景中的应用,并通过示例代码展示了Detached Client的具体实现方式。这种设计解决了传统轮询的资源浪费问题,特别适用于生产线监控、客服系统等需要服务端主

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2315

Android中项目中各个文件夹的含义和用途详解

Android中项目中各个文件夹的含义和用途详解 1.src:存放所有的*.java源程序。2.gen:为ADT插件自动生成的代码文件保存路径,里面的R.java将保存所有的资源ID。3.assets:可以存放项目一些较大的资源文件,例如:图片、音乐、字体等。4.res:可以存放项目中所有的资源文件,例如:图片(*.png、*.jpg)、文本等。5.res/drawable-hdpi

u013053383的专栏 1544

Python内置函数zip()——《Python内置函数手册》Python老吕编著

zip()函数是 Python 中的一个内置函数,用于将多个可迭代对象(如列表、元组、字符串等)中对应的元素打包成一个个元组,然后返回由这些元组组成的迭代器。zip()函数常用于将多个序列并行迭代,或者用于数据对齐。zip()它返回一个迭代器,这意味着你可以逐个获取打包后的元素,而不是一次性将所有元素加载到内存中。如果输入的可迭代对象长度不一致,zip()会以最短的可迭代对象为准,只打包到最短对象的末尾。它可以用来并行迭代多个序列,使得代码更加简洁和高效。在接下来的章节中,我们将详细介绍。

Python老吕的博客 680

HQChart实战教程49-点击修改K线颜色及背景色

HQChart实战教程49-点击修改K线颜色及背景色需求效果图步骤1. 注册点击监听事件2. 修改K颜色添加一个自定义颜色的K线klineoption清空所有自定义颜色的K线option交流QQ群: 950092318HQChart代码地址完整例子 需求 对点击的K线修改颜色。 效果图 步骤 1. 注册点击监听事件 事件ID JSCHART_EVENT_ID.ON_CLICK_CHART_PAINT, 注册监听事件见教程 HQChart使用教程5- K线图控件操作函数说明 this.Create=func

小银 2911

Android Drawable,Shape,ColorMatrix

Drawable的子类有StateListDrawable,NinePatchDrawable、BitmapDrawable、AnimationDrawable。

3022

倍福控制第三方伺服走CSV模式--以汇川伺服为例

在使用TwinCAT软件控制标准CiA402协议的EtherCAT伺服时使用TwinCAT软件NC自带的运动控制指令控制伺服,此时伺服驱动器一般工作在CSP/CSV/CST模式。最常见伺服驱动器工作在CSP模式,轨迹规划运行在TwinCAT软件,位置环速度环电流环运行在伺服驱动器中。该模式下速度波动较大,需要极度平稳的速度需要采用CSV模式。本文讲述的是伺服驱动器工作在CSV模式,此时轨迹规划和位置环均运行在TwinCAT软件,速度环电流环运行在伺服驱动器中。为了简化文字描述,本文采用图文结合的方式介绍伺服

weixin_41883890的博客 4848

drawable java什么意思_Android中如何查看在res中存放的drawable文件对应的JAVA类型是什么呢...

有些时候需要将res中的资源文件加载进来然后做一些修改,然后再赋值给控件使用,比如这样:Drawable drawable = getResources().getDrawable(int id);现在我需要把资源文件id所对应的Drawable对象加载进来,然后做向下转型处理,如果我不调试查看本身的类型的话,该怎么知道它到底是哪种类型呢?我们来通过源代码查看究竟:首先我们找到getResourc...

weixin_26821003的博客 185

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Android中如何查看在res中存放的drawable文件对应的JAVA类型是什么呢

噢噢,原来是这样啊,我定义什么样类型的图片,最后就有什么样的Java类型与之对应,原来我的selector对应StateListDrawable,恍然大悟,接下来就容易处理了。现在我需要把资源文件id所对应的Drawable对象加载进来,然后做向下转型处理,如果我不调试查看本身的类型的话,该怎么知道它到底是哪种类型呢?

weixin_67271870的博客 143

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Android Drawable介绍

Android Drawable介绍 Android系统中将可绘制对象被抽象为Drawable,不同的绘制资源对应着不同的Drawable类型。Android FrameWork提供了常用的Drawable,Android控件的绘制资源基本都是通过Drawable形式实现的。一般情况下,开发者是不会直接接触Drawable的具体实现的,Drawable资源一般都放在res/drawabl

^_虫虫_^的专栏 1039

Android Drawable全面解析:从基础到高级应用

Drawable是Android图形系统的核心抽象层,作为可绘制对象的统一接口,它封装了位图、矢量图、状态动画等多种图形表现形式。其设计原理基于资源适配与硬件加速,通过XML或代码定义实现跨设备一致性渲染。在工程实践中,Drawable的高效使用能显著提升UI性能,特别是StateListDrawable实现交互状态管理、VectorDrawable减少多分辨率资源开销等场景。针对Android应用开发,掌握Drawable的类型体系(如BitmapDrawable/ShapeDrawable)和优化技巧(

weixin_30411239的博客 443

Android Drawable

Drawable 是开发中经常用到的一个概念,我们经常用它去设置 View 的背景,背景可以一个颜色值,也可以是一张资源图片,还可以是一个自定义的 Drawable(shape、selector和layer-list等)等等。这篇文章就简单说下 Drawable 与 View 的关系,同时结合代码,简要分析一下 Drawable 如何作用于 View。 Drawable 介绍 官方介绍: A Drawable is a general abstraction for “something that can

yzpbright的博客 561

Android studio res资源文件夹

我使用vedioView的时候,感觉res我不太了解。为了vedioView,记录学习res资源文件夹。目录定义特点方法介绍应用场景具体用法总结res是Android项目工程中存放各类的目录,主要包括布局、图形与配置等等。特点特点应将各类资源放入项目 res/ 目录的特定子目录中。PS:切勿将资源文件直接保存在res/目录内,因为这样会造成编译错误。

谁呛我名字的博客 2096

drawable和mipmap的区别

在Android studio中,同时存在drawable目录和mipmap目录,二者没有明显区别,但是工作机制还是存在差别。 谷歌官方:  drawable/  For bitmap files (PNG, JPEG, or GIF), 9-Patch image files, and XML files that describe Drawable shapes or Drawable o...

Cricket_7的博客 896

Android基础之解析res目录

目录Directory 资源类型Resource Types   res/anim/ XML文件,它们被编译进逐帧动画(frame by frameanimation)或补间动画(tweened animation)对象   res/drawable/ .png、.jpg文件,它们被编译进以下的Drawa

lrx之成长记录 1443

关于Drawable的文章

Drawable资源 Drawable资源是对图像的一个抽象,你可以通过getDrawable(int)得到并绘制到屏幕上。这里有几种不同类型的Drawable: Bitmap File 一个Bitmap图像文件(.png、.jpg或.gif)。BitmapDrawable。 Nine-Patch File 一个带有伸缩区域的PNG文件,可以基于content伸缩

jokeHello的专栏 589

android下面res目录

res文件夹里面的多个文件夹的各自介绍(来自网上的Android开发指南中文版内容): 目录Directory 资源类型Resource Types res/anim/ XML文件,它们被编译进逐帧动画(frame by frame animation)或补间动画(tweened animation)对象

晚晴小筑 1274

Android Studio新手必看:如何高效管理res目录下的资源文件?

本文为Android Studio新手提供了高效管理res目录下资源文件的完整指南。从理解Android资源系统机制、建立清晰的命名与组织规范,到利用Vector Drawable、Gradle配置等工具进行优化,系统讲解了如何避免常见陷阱,从而提升项目可维护性、构建效率并优化APK体积。

ggg99的专栏 447
上一篇: Android 网络框架 Volley 源码解析
下一篇: 巧用 Drawable 之实现一个最简单的自定义电池图标
leandom
博客等级 码龄12年 3粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值