Android的drawable目录可以包含子目录吗?

558
在Android SDK文档中,所有使用@drawable/my_image xml语法的示例都直接引用存储在我的项目中res/drawable目录中的图像。
我想知道是否明确不允许在drawable目录中创建子目录。
例如,如果我有以下目录布局:
res/drawable
-- sandwiches
  -- tunaOnRye.png
  -- hamAndSwiss.png
-- drinks
  -- coldOne.png
  -- hotTea.png

我能用 @drawable/sandwiches/tunaOnRye 引用一张金枪鱼沙拉三明治的图片吗?

或者说,我必须在 drawable 目录下保持层级扁平?


19
请注意,在 res 目录中不允许使用大写字母。 - Tyler
1
你只能使用Gradle来完成这个任务:https://dev59.com/KWQn5IYBdhLWcg3wxZni#19859379 - Yair Kukielka
2
是否可以在drawable目录下创建SIBLING(类似的)目录,并具有drawable功能?例如:res/tanks/drawble-[hdpi等等],这样行吗? - Fattie
3
现在是2023年3月24日,您的翻译请求是:“It's 2021. Has this been solved yet?” 我可以帮助您将其翻译为中文:“现在已经是2023年了,这个问题是否已经得到解决?” 我会尽力使翻译简洁明了并保持原意不变。 - Leszek
4
2022年了,这个问题解决了吗? - Evgeniy Mishustin
显示剩余3条评论
22个回答

592

不支持在drawable目录中使用子文件夹,所以是的,您需要保持该层次结构平坦。

您展示的目录布局将导致所有图像都不可用。

根据我的实验,似乎在 res/drawable 文件夹中有任何项目的子文件夹会导致资源编译器失败--防止正确生成 R.java 文件。


155
从Android 2.2开始,这不会导致编译错误,但生成R类时会忽略任何子目录。这真的很糟糕,使得管理更大的项目变得困难。 =/ - Nik Reiman
79
完全同意。他们需要想出一个更好的解决方案来支持子文件夹,这不可能那么难。 - znq
16
希望这个问题能够很快解决,我有超过100个资产,而且其中一些还需要编码处理。管理稍微复杂一点的项目真是噩梦般的体验。 - Emile
16
这是在Android问题跟踪器中对应的问题:http://code.google.com/p/android/issues/detail?id=2018 - espinchi
14
100个资产...试试用16,000个资产。 - Mytheral
显示剩余10条评论

164

我正在使用的解决方法(也是 Android 本身似乎更喜欢的)是将下划线替换为正斜杠,因此您的结构看起来会像这样:

sandwich_tunaOnRye.png
sandwich_hamAndSwiss.png
drink_coldOne.png
drink_hotTea.png

这种方法需要您在命名方面非常细致,但并不能使文件本身更易管理(如果您决定饮料和三明治都应该被称为“food”,那么你必须进行批量重命名而不是简单地将它们移动到目录中)。但与文件夹结构相当的逻辑复杂度相比,您的编程逻辑复杂度并没有受到太大的影响。

这种情况确实很糟糕。 Android是一个美妙和可怕设计决策混杂的包。我们只能希望后者尽快被清除 :)


33
请注意,在drawable文件夹中不允许使用大写字母。您会收到错误提示:“无效的文件名:必须仅包含[a-z0-9_.]”。请将文件名中的大写字母改为小写字母或使用下划线或点号代替。 - Jason Axelson
6
+1 表示同意 "设计决策好坏参半" 的说法。 - Brent Faust
1
很难说这是一个解决方法,更像是“为了不彻底疯掉而应该做的事情”。被限制在一个目录下是荒谬的。 - RichieHH

45

实际上,在 Android Studio 上是可以实现的。你可以像这里展示的那样拥有嵌套资源:

enter image description here

此外,还有一个插件可以对资源进行分组,在这里

不过我建议避免使用这种方式。


嗨,@android开发者!我尝试将以下内容添加到build.gradle文件中: sourceSets { main { res { srcDir 'src/main/res/drawable/ic-toggle' } } }, 但是在xmlns:android="http://schemas.android.com/apk/res/android"处出现了“Uri未注册”的错误。可能是什么原因? - AlexKost
@RahulMandaliya 虽然这是可能的,但我建议不要使用它。 - android developer
1
@JoshHansen 这很混乱。 - android developer
1
如果来自不同文件夹的两个文件具有相同的名称,则可能会出现错误。 - Mallikarjun M
2
@BenjaminMesing 我知道这个解决方案存在,但我反对使用它,因为它似乎是一个大的变通方法。 - android developer
显示剩余4条评论

37

是的-确实很糟糕 :) 但是您可以使用assets文件夹,并在其中拥有子目录,以此方式加载图像。


11
问题不仅限于可绘制文件夹,也包括布局文件夹 :( 我的布局文件夹有100多个xml文件,很难找到正确的xml布局。 - anticafe
除了其他的反对意见,资源可以很容易地本地化,但据我所知,没有内置的机制来处理资产的本地化。 - Fran Marzoa
@anticafe 在你的IDE中使用“转到资源”功能(Eclipse:CTRL+SHIFT+R,IDEA/Android Studio:CTRL+SHIFT+N) - TWiStErRob

24

使用assets文件夹。

示例代码:

InputStream is = null;
try {
    is = this.getResources().getAssets().open("test/sample.png");
} catch (IOException e) {
    ;
}

image = BitmapFactory.decodeStream(is);

5
使用位图的唯一问题在于需要更多的作业量。Android的资源系统在内存管理方面做得更好。如果已经有了一个内存管理系统,为什么要重新建立一个呢?特别是如果有100多个图像,那么加载和释放位图的工作量就很大了。 - Rev Tyler
23
如果您计划本地化您的应用程序,这将是一个真正的问题,尤其是如果您有不同的资源针对不同的屏幕密度,因此这不是一个解决方案,只是一个有效的权宜之计,仅适用于某些情况。 - Fran Marzoa
1
我需要给@Fran的评论至少一千个赞 :) - HGPB

22

我编写了一个Eclipse插件,可以通过使用双下划线__将文件名分隔来创建虚拟子文件夹。该项目处于早期阶段,但不用担心,它不会导致您的IDE崩溃。

更多详细信息可以在此处找到,欢迎派生并发送拉取请求:

https://github.com/kirill578/Android-Sorted-Res-Folder

输入图像描述


2
不错!有没有将它移植到Android Studio的机会? - BVB
1
我目前甚至没有使用Android Studio,所以我猜我们必须等待有经验的人来移植它。 - Kirill Kulakov

9
我喜欢使用简单的脚本来将设计师提供的有组织的目录结构扁平化,以便生成R文件。

在drawable-hdpi中使用当前路径运行:

#! /bin/bash
DIRS=`find * -type d`
for dir in ${DIRS} ; do 
  for file in `ls ${dir}` ; do
    mv ${dir}/${file}  ${dir}_${file};
  done 
  rmdir ${dir};
done

1
如果文件夹下有子文件夹,你的脚本将无法正常工作。我认为你需要在${dir}中用'_'替换所有'/'。 - Seunghoon

9
在Android Studio和Gradle中,您可以具有多个源目录,这将允许您分离资源。例如:
android {
    ....
    android.sourceSets {
        main.res.srcDirs = ['src/main/extraresdirnamed_sandwiches', 'src/main/res']
    }
    ....
}

然而,名称不能相互冲突,这意味着您仍然需要使用像sandwiches_tunaOnRye这样的名称,但您可以为所有三明治拥有一个单独的部分。
这使您能够以不同的结构存储资源(对于自动生成的内容非常有用,例如actionbargenerator)。

6

部分解决该问题的方法是使用API级别后缀。我使用res/layout-v1、res/layout-v2等来在同一个apk中容纳多个子项目。这种机制可用于所有资源类型。

显然,只有当您的目标API级别高于您正在使用的res/layout-v?时才能使用此功能。

此外,请注意Android 1.5和1.6中的错误。请参阅Android文档中关于API级别后缀的内容


给那位降低了这个回答的人:您能解释一下吗?虽然这种机制看起来不太好,但对我来说很有效。 - OferR
这也是我的做法,而且效果还不错。我有一堆小图片,不想扩展它们的大小,所以我把它们放在自己的文件夹里。 - AaronC
对我来说很有效。而且对我来说很漂亮。我正在尝试将第二版的逻辑加入我的应用程序中,所以v2很好。 - undefined

5

对于这种情况,有一个解决方法:您可以在与默认res文件夹相同的级别上创建一个名为resVector(例如)的文件夹。在那里,您可以添加任何drawable-xxx资源文件夹:

resVector
-drawable
-layout
-color

此时,你只需添加

即可。该标签与

标签相对应,用于结束段落。

sourceSets {
        main.res.srcDirs += 'src/main/resVector'
    }

将以下代码添加到你的 build.gradle 文件中(在 android { } 内部):

1
很遗憾,在使用“Android”视角时,它们会在Android Studio的项目面板中合并在一起 :( - charles-allen
@AjahnCharles - 我更喜欢完全不使用这个视角(无论如何 - 我总是在“无干扰模式”下工作)...但你是对的 - “Android”将一切都合并了。 - Anton Derevyanko
这个解决方案很好用,比res/drawable-v2解决方案更好。很容易将所有内容复制到另一个模块或项目中。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接