O diretório drawable do Android pode conter subdiretórios?


497

Na documentação do Android SDK, todos os exemplos usados ​​com a sintaxe @ drawable / my_image xml abordam diretamente as imagens armazenadas no diretório res / drawable em meu projeto.

Gostaria de saber se não é explicitamente permitido criar um subdiretório dentro do diretório drawable.

Por exemplo, se eu tivesse o seguinte layout de diretório:

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

Posso referenciar a imagem de um sanduíche de salada de atum como @ drawable / sandwiches / tunaOnRye

Ou eu tenho que manter a hierarquia plana no diretório drawable.


16
Observe que letras maiúsculas não são permitidas no diretório res.
Tyler

1
Você só pode fazer isso com o Gradle: stackoverflow.com/a/19859379
Yair Kukielka 7/4

2
É possível ter diretórios SIBLING para drawable, com a funcionalidade drawable? Então, res / tanks / drawble- [hdpi .. etc] e assim por diante?
Fattie

Respostas:


546

Não, o mecanismo de recursos não suporta subpastas no diretório drawable, então sim - você precisa manter essa hierarquia plana.

O layout do diretório que você mostrou resultaria em nenhuma das imagens disponíveis.

De meus próprios experimentos, parece que ter uma subpasta com itens dentro da res/drawablepasta fará com que o compilador de recursos falhe - impedindo que o R.javaarquivo seja gerado corretamente.


136
A partir do Android 2.2, isso não causa um erro do compilador, mas todos os subdiretórios são ignorados ao gerar a classe R. Isso é péssimo e dificulta o gerenciamento de projetos maiores. = /
Nik Reiman

70
Concordo plenamente. Eles precisam apresentar uma solução melhor para o suporte a subpastas. Não pode ser tão difícil assim.
znq 6/09/10

13
Espero que isso seja resolvido em breve, tenho mais de 100 ativos e mesmo assim codifiquei alguns deles. Égua noturna total tentando gerenciar qualquer projeto marginalmente complexo.
Emile

14
Este é o problema correspondente no rastreador de problemas do Android: code.google.com/p/android/issues/detail?id=2018
espinchi


149

A solução alternativa que estou usando (e a que o próprio Android parece favorecer) é substituir essencialmente um sublinhado por uma barra, para que sua estrutura fique assim:

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

A abordagem exige que você seja meticuloso na nomeação e não facilita muito a organização dos arquivos (se você decidiu que bebidas e sanduíches realmente deveriam ser todos " food", seria necessário renomear em massa em vez de simplesmente movendo-os para o diretório); mas a complexidade da sua lógica de programação não sofre muito em comparação com o equivalente da estrutura de pastas.

Esta situação é realmente péssima. O Android é uma mistura de decisões maravilhosas e terríveis de design. Só podemos esperar que a última parte seja eliminada com toda a pressa :)


31
Apenas observe que letras maiúsculas não são permitidas na pasta de desenho. Eu recebo o erro: "Nome de arquivo inválido: deve conter apenas [a-z0-9_.]"
Jason Axelson

5
+1 para "mescla de decisões de design maravilhosas e terríveis"
Brent Faust

1
Dificilmente uma solução alternativa: sim "o que você deve fazer para não ficar completamente louco". É ridículo limitar-se a um diretório.
21714 RichieHH

35

Na verdade, no Android Studio é possível. Você pode ter recursos aninhados, como mostrado aqui :

insira a descrição da imagem aqui

Há também um plug-in para agrupar recursos aqui .


Olá, desenvolvedor @android! Tentei adicionar isso ao arquivo build.gradle: sourceSets {main {res {srcDir 'src / main / res / drawable / ic-toggle'}}}, mas tenho "Uri não está registrado" para xmlns : android =" schemas.android.com/apk/res/android .? o que poderia ser o caso
AlexKost

@AlexKost Na verdade, tentei isso apenas uma vez. Não tenho experiência suficiente para ajudar. Desculpa.
android developer

@RahulMandaliya Mesmo sendo possível, sugiro não usá-lo.
desenvolvedor android

@androiddeveloper Por que não?
21418 Josh Hansen #

1
@JoshHansen É uma bagunça.
desenvolvedor android

34

Sim - é péssimo :) Entretanto, você pode usar a pasta assets e ter subdiretórios lá e carregar imagens dessa maneira.


6
o problema não é apenas para a pasta drawable, mas também para a pasta de layout :( A pasta do meu layout contém mais de 100 arquivos xml, e é difícil para mim abrir o layout xml correto nisso.
anticafe

Além de outras objeções, os recursos podem ser facilmente localizados, mas no AFAIK não há um mecanismo de l10n embutido para ativos.
27512 Fran Franzozo

uso @anticafe "Vai para o recurso" em seu IDE (Eclipse: CTRL + SHIFT + R, IDEA / Android Estúdio: CTRL + SHIFT + N)
TWiStErRob

23

Use a pasta de ativos.

Código de amostra:

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

image = BitmapFactory.decodeStream(is);

5
O único problema desse método é que há muito mais trabalho de casa envolvido no uso de bitmaps. O sistema de recursos do Android faz um trabalho muito melhor de gerenciamento de memória. Por que você reconstruiria um sistema de gerenciamento de memória quando o Android já o faz? Espeicamente, se ele tem mais de 100 imagens, é muito carregamento e liberação de bitmaps.
Rev Tyler

18
Esse é um problema real: você planeja localizar seu aplicativo, também se você tiver recursos diferentes para diferentes densidades de tela, portanto, não é uma solução, apenas uma solução alternativa válida para apenas alguns casos.
27512 Fran Franzozo

1
Eu preciso dar comentário @Fran 's pelo menos mil upvotes :)
HGPB

22

Eu escrevi um plug-in do eclipse que permite criar subpastas virtuais, separando o nome do arquivo com dois sublinhados __. O projeto está nos estágios iniciais, mas não se preocupe, não irá travar seu IDE

mais detalhes podem ser encontrados aqui, fique à vontade para enviar e enviar solicitações pull:

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

insira a descrição da imagem aqui


2
Agradável! Alguma chance de portar isso para o Android Studio também?
BVB 5/05

1
No momento, eu nem estou usando o android studio, então acho que teremos que esperar alguns experientes para portá-lo.
Kirill Kulakov 5/05

9

Eu gosto de usar um script simples para nivelar uma estrutura de diretório organizada fornecida pelos designers para algo que pode ser usado para gerar um arquivo R.

Execute com o caminho atual em 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
Seu script não funcionará se houver subpastas nas pastas. Eu acho que você precisa substituir todos '/' por '_' em $ {dir}.
Seunghoon

9

No android studio com gradle, você pode ter vários diretores de origem, que permitem separar recursos. Por exemplo:

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

No entanto, os nomes não devem colidir, o que significa que você ainda precisará ter nomes como sandwiches_tunaOnRye, mas poderá ter uma seção separada para todos os seus sanduíches.

Isso permite que você armazene seus recursos em diferentes estruturas (útil para conteúdo gerado automaticamente, como actionbargenerator)


4

Uma maneira de contornar parcialmente o problema é usar o sufixo no nível da API. Eu uso res / layout-v1, res / layout-v2 etc para manter vários subprojetos no mesmo apk. Este mecanismo pode ser usado para todos os tipos de recursos.

Obviamente, isso só pode ser usado se você estiver direcionando os níveis da API acima do res / layout-v? você está usando.

Além disso, atente para o bug no Android 1.5 e 1.6. Consulte a documentação do Andoroid sobre o sufixo no nível da API .


Para quem rebaixou esta resposta: Você pode explicar o porquê? Esse mecanismo, embora não seja bonito, funciona bem para mim.
OferR

4

Com o advento do sistema de bibliotecas, criar uma biblioteca por grande conjunto de ativos pode ser uma solução.

Ainda é problemático, pois é preciso evitar o uso dos mesmos nomes em todos os ativos, mas o uso de um esquema de prefixo por biblioteca deve ajudar nisso.

Não é tão simples como criar pastas, mas isso ajuda a manter as coisas sãs ...


Sim, acho que isso é bom. Se eu adicionar bandeiras do país às minhas pastas drawable-ldpi etc., elas serão inundadas. Penso que a criação de um projeto de biblioteca para todos os recursos genéricos ajudará a reduzir a confusão no projeto em que você está trabalhando ativamente. Surpreso, você tem apenas 1 voto positivo.
22413 Tom

3

Existe uma solução alternativa para esta situação: você pode criar uma resVectorpasta (por exemplo) no mesmo nível da respasta padrão . Lá você pode adicionar quaisquer drawable-xxxpastas de recursos:

resVector
-drawable
-layout
-color

Depois disso, tudo o que você precisa é adicionar

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

no seu build.gradlearquivo (dentro android { }).


Infelizmente eles estão juntos de mesclagem no painel do projeto no Android Studio quando usando a perspectiva "Android" :(
AjahnCharles

@AjahnCharles - prefiro não usar essa perspectiva (de qualquer maneira - estou sempre trabalhando no 'modo livre de distração') ... Mas você está certo - o "Android" mescla tudo.
Anton Derevyanko 03/04

1

Este não é um método perfeito. Você deve implementar da mesma maneira que é exibida aqui .

Você também pode chamar a imagem na pasta através do código que pode usar

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

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


1

Gradle com o Android Studio poderia fazê-lo desta maneira ( link ).

Está no parágrafo "Configurando a estrutura"

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

1

crie uma pasta no main. como: 'res_notification_btn'

e crie uma pasta na árvore em. como 'drawable' ou 'layout'

depois em 'build.gradle' adicione este

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?("/")
}

Tudo isso faz é automatizar a solução alternativa sugerida por Cheezmeister. Está funcionando para mim ... gostaria de explicar o voto negativo?
Blake Miller


0

ativos / Você pode usá-lo para armazenar arquivos de ativos brutos. Os arquivos que você salva aqui são compilados em um arquivo .apk como estão e o nome do arquivo original é preservado. Você pode navegar neste diretório da mesma maneira que um sistema de arquivos típico usando URIs e ler arquivos como um fluxo de bytes usando o AssetManager. Por exemplo, este é um bom local para texturas e dados de jogos. http://developer.android.com/tools/projects/index.html


0

Os subdiretórios não são permitidos, o recurso deve conter apenas [a-z0-9_.].

Não, você tem letras maiúsculas e sem barras.


-3
  1. Clique com o botão direito do mouse em Drawable
  2. Selecione Novo ---> Diretório
  3. Digite o nome do diretório. Por exemplo: logo.png (o local já mostrará a pasta de desenho por padrão)
  4. Copie e cole as imagens diretamente na pasta drawable. Ao colar, você tem a opção de escolher mdpi / xhdpi / xxhdpi etc para cada uma das imagens de uma lista. Selecione a opção apropriada e insira o nome da imagem. Certifique-se de manter o mesmo nome que o nome do diretório, ie logo.png
  5. Faça o mesmo para as imagens restantes. Todos eles serão colocados na pasta principal logo.png.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.