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


496

在Android SDK文档中,与@ drawable / my_image xml语法一起使用的所有示例都直接解决了存储在我项目的res / drawable目录中的图像。

我想知道在drawable目录中创建子目录是否明显不可行。

例如,如果我具有以下目录布局:

res/drawable
-- sandwiches
  -- tunaOnRye.png
  -- hamAndSwiss.png
-- drinks
  -- coldOne.png
  -- hotTea.png

我可以将金枪鱼色拉三明治的图像引用为@ drawable / sandwiches / tunaOnRye

还是我必须在可绘制目录中保持层次结构平坦。


16
请注意,res目录中不允许使用大写字母。
泰勒

1
您只能使用Gradle做到这一点: stackoverflow.com/a/19859379
Yair Kukielka 2014年

2
通过可绘制功能,是否可以使SIBLING目录可绘制?那么,res / tanks / drawble- [hdpi .. etc]等等?
Fattie

Answers:


545

不可以,资源机制不支持drawable目录中的子文件夹,所以可以-您需要保持层次结构平坦。

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

根据我自己的实验,似乎在文件夹中包含子文件夹的子res/drawable文件夹将导致资源编译器失败-阻止R.java正确生成文件。


135
从Android 2.2开始,这不会导致编译器错误,但是在生成R类时会忽略所有子目录。这确实很糟糕,并且难以管理更大的项目。= /
Nik Reiman

69
完全同意。他们需要提供更好的解决方案来支持子文件夹。没那么难。
znq 2010年

13
希望这个问题能尽快解决,我拥有100多种资产,即使如此,我也将其中一些编码了。试图管理任何边际复杂项目的总夜马。
Emile

14
这是Android问题跟踪器中的相应问题:code.google.com/p/android/issues/detail?
id=2018

44
诅咒你的机器人
whitneyland

149

我正在使用的变通方法(一个Android本身似乎更喜欢)实际上是用下划线代替正斜杠,因此您的结构应如下所示:

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

该方法要求您谨慎命名,并且不要使纠缠文件本身变得容易得多(如果您确定饮料和三明治应该全部都是“ food”,则必须进行批量重命名而不是简单地将它们移至目录);但是与同等的文件夹结构相比,您的编程逻辑的复杂性不会受到太大的影响。

这种情况确实很糟糕。Android充满了各种奇妙而可怕的设计决策。我们只能希望尽一切努力赶快淘汰后者:)


31
请注意,drawable文件夹中不允许使用大写字母。我收到错误消息:“无效的文件名:必须仅包含[a-z0-9_。]”
Jason Axelson

5
+1代表“精彩绝伦的设计决策混合包”
布伦特·浮士德

1
几乎没有解决方法:而是“您应该怎么做以免完全生气”。只限于一个目录是可笑的。
RichieHH 2014年

35

实际上,在Android Studio上是可能的。你可以有嵌套的资源,如图所示这里

在此处输入图片说明

还有一个插件组资源在这里


嗨,@ android开发人员!我尝试将其添加到build.gradle文件中:sourceSets {main {res {srcDir'src / main / res / drawable / ic-toggle'}}},但是我已经为XMLns设置了“未注册Uri” :android =“ schemas.android.com/apk/res/android。可能是什么情况?
AlexKost 2015年

@AlexKost我实际上只尝试了一次。我没有足够的经验来提供帮助。抱歉。
Android开发人员

@RahulMandaliya即使有可能,我建议不要使用它。
Android开发人员

@androiddeveloper为什么不呢?
乔什·汉森

1
@JoshHansen太乱了。
Android开发人员

34

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


6
这个问题不仅是绘制文件夹,也为布局文件夹:(我布局的文件夹包含100多个XML文件,这是我很难在这个开放对xml的布局。
anticafe

对于其他异议,资源可能易于定位,但AFAIK没有内置的资产内置机制。
Fran Marzoa

@anticafe在您的IDE中使用“转到资源”(Eclipse:CTRL + SHIFT + R,IDEA / Android Studio:CTRL + SHIFT + N)
TWiStErRob 2014年

23

使用资产文件夹。

样例代码:

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

image = BitmapFactory.decodeStream(is);

5
这种方法的唯一问题是使用位图需要做更多的功课。Android的资源系统在内存管理方面做得更好。为什么在Android已经建立内存管理系统的情况下重建它?尤其是,如果他有100多张图像,那将是很多位图的加载和释放。
泰勒牧师2012年

18
这是一个真正的问题,如果您打算本地化应用程序,并且如果您有不同的资源用于不同的屏幕密度,那么这不是解决方案,只是一种仅在某些情况下有效的解决方法。
Fran Marzoa

1
我需要给@Fran至少一千个投票:)
HGPB 2012年

22

我已经编写了一个eclipse插件,该插件可以通过使用两个下划线分隔文件名来创建虚拟子文件夹 __。该项目尚处于初期阶段,但是请放心,它不会使您的IDE崩溃

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

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

在此处输入图片说明


2
真好!还有机会将其移植到Android Studio吗?
BVB 2014年

1
我目前甚至没有使用android studio,所以我想,我们将不得不等待一些经验丰富的人员来移植它。
Kirill Kulakov 2014年

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}中的所有“ /”替换为“ _”。
胜勋

9

在带有gradle的android studio中,您可以有多个源导演,这将使您可以分离资源。例如:

android {
    ....
    android.sourceSets {
        main.res.srcDirs = ['src/main/extraresdirnamed_sandwiches', 'src/main/res']
    }
    ....
}

但是,名称不能冲突,这意味着您仍然需要使用诸如sandwiches_tunaOnRye之类的名称,但是您将能够为所有三明治设置一个单独的部分。

这使您可以将资源存储在不同的结构中(对于自动生成的内容(例如actionbargenerator)有用)


4

解决该问题的一种方法是使用API​​ Level后缀。我使用res / layout-v1,res / layout-v2等将多个子项目保存在同一apk中。此机制可用于所有资源类型。

显然,仅当您将API级别定位为高于res / layout-v吗?您正在使用。

另外,请注意Android 1.5和1.6中的错误。 请参阅有关API级别后缀的Andoroid文档


对于将这个答案降级的人:您能解释为什么吗?这种机制虽然不美观,但对我来说效果很好。
OferR

4

随着图书馆系统的出现,为每套大型资产创建图书馆可能是一种解决方案。

这仍然是有问题的,因为必须避免在所有资产中使用相同的名称,但是对每个库使用前缀方案应对此有所帮助。

它不像能够创建文件夹那样简单,但是可以使事情保持理智...


是的,我认为这很好。如果将国家标志添加到我的drawable-ldpi等文件夹,则它们将被淹没。我认为为所有通用资源创建一个库项目将有助于减少您正在积极从事的项目中的混乱情况。惊讶您只有1个投票。
汤姆(Tom),

3

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

resVector
-drawable
-layout
-color

之后,您只需添加

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

放入您的build.gradle文件(在中android { })。


遗憾的是,使用“ Android”透视图时,它们在Android Studio的项目面板中合并在一起:(
AjahnCharles

@AjahnCharles-我不希望完全不使用这种观点(无论如何-我一直都在“无干扰模式”下工作)...但是您是对的-“ Android”将所有内容合并。
安东·德雷夫扬科

1

这不是完美的方法。您必须实现此处显示的相同方法。

您还可以通过可以使用的代码调用文件夹下的图片

Resources res = getResources();
Drawable shape = res. getDrawable(R.drawable.gradient_box);

TextView tv = (TextView)findViewByID(R.id.textview);
tv.setBackground(shape);


1

Android Studio的Gradle可以通过这种方式做到这一点(link)。

在“配置结构”段落中

sourceSets {
 main {
    java {
        srcDir 'src/java'
    }
    resources {
        srcDir 'src/resources'
    }
 }
}

1

在main中创建一个文件夹。像:“ res_notification_btn”

并在其中创建树文件夹,例如“ drawable”或“ layout”

然后在“ build.gradle”中添加

sourceSets
            {
                main
                {
                    res
                    {
                        srcDirs = ['src/main/res_notification_btn', 'src/main/res']
                      or
                        srcDir 'src/main/res_notification_btn'
                    }
                }
            }

0
#!/usr/bin/env ruby

# current dir should be drawable-hdpi/ etc

# nuke all symlinks
Dir.foreach('.') {|f|
    File.delete(f) if File.symlink?(f)
}

# symlink all resources renaming with underscores
Dir.glob("**/*.png") {|f|
    system "ln -s #{f} #{f.gsub('/', '_')}" if f.include?("/")
}

所有这一切都是自动执行Cheezmeister建议的解决方法的。它正在为我工​​作...愿意解释下降投票吗?
布莱克·米勒


0

资产/您可以使用它来存储原始资产文件。您在此处保存的文件将原样编译为.apk文件,并且保留了原始文件名。您可以使用与使用URI的典型文件系统相同的方式浏览此目录,并使用AssetManager将文件读取为字节流。例如,这是纹理和游戏数据的理想位置。 http://developer.android.com/tools/projects/index.html



-3
  1. 右键单击Drawable
  2. 选择新建--->目录
  3. 输入目录名称。例如:logo.png(默认情况下,该位置已经显示了drawable文件夹)
  4. 将图像直接复制并粘贴到drawable文件夹中。粘贴时,您可以从列表中为每个图像选择mdpi / xhdpi / xxhdpi等。选择适当的选项,然后输入图像的名称。确保与目录名称保持相同的名称,即logo.png
  5. 对其余图像执行相同的操作。所有这些都将放置在logo.png主文件夹下。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.