Le répertoire dessinable Android peut-il contenir des sous-répertoires?

497

Dans la documentation Android SDK, tous les exemples utilisés avec la syntaxe @ drawable / my_image xml concernent directement les images stockées dans le répertoire res / drawable de mon projet.

Je me demande si ce n'est explicitement pas correct de créer un sous-répertoire dans le répertoire drawable.

Par exemple, si j'avais la disposition du répertoire suivante:

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

Puis-je référencer l'image d'un sandwich à la salade de thon comme @ drawable / sandwiches / tunaOnRye

Ou dois-je garder la hiérarchie plate dans le répertoire drawable.

Poivre Lebeck-Jobe
la source
16
Veuillez noter que les majuscules ne sont pas autorisées dans le répertoire res.
Tyler
1
Vous ne pouvez le faire qu'avec Gradle: stackoverflow.com/a/19859379
Yair Kukielka
2
Est - il possible d'avoir entre frères et soeurs répertoires à étirables, avec la fonctionnalité drawable? Alors, res / tanks / drawble- [hdpi .. etc] et ainsi de suite?
Fattie

Réponses:

546

Non, le mécanisme des ressources ne prend pas en charge les sous-dossiers dans le répertoire drawable, donc oui - vous devez garder cette hiérarchie plate.

La disposition du répertoire que vous avez montrée n'entraînerait aucune image disponible.

D'après mes propres expériences, il semble que le fait d'avoir un sous-dossier contenant des éléments, dans le res/drawabledossier, entraînera l'échec du compilateur de ressources, empêchant le R.javafichier d'être généré correctement.

Reto Meier
la source
136
À partir d'Android 2.2, cela ne provoque pas d'erreur de compilation, mais tous les sous-répertoires sont ignorés lors de la génération de la classe R. Cela craint vraiment et rend difficile la gestion de projets plus importants. = /
Nik Reiman
70
Entièrement d'accord. Ils doivent trouver une meilleure solution prenant en charge les sous-dossiers. Ça ne peut pas être si difficile.
znq
13
J'espère que cela sera bientôt résolu, j'ai plus de 100 actifs, et même alors, j'ai codé certains d'entre eux. Jument de nuit totale essayant de gérer tout projet marginalement complexe.
Emile
14
Il s'agit du problème correspondant dans le suivi des problèmes Android: code.google.com/p/android/issues/detail?id=2018
espinchi
44
vous maudire android
whitneyland
149

La solution de contournement que j'utilise (et celle qu'Android lui-même semble favoriser) consiste essentiellement à substituer un trait de soulignement à une barre oblique, de sorte que votre structure ressemblerait à quelque chose comme ceci:

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

L'approche nécessite que vous soyez méticuleux dans votre dénomination et ne facilite pas beaucoup la manipulation des fichiers eux-mêmes (si vous décidiez que les boissons et les sandwichs devraient vraiment tous être " food", vous devriez faire un renommage de masse plutôt que simplement les déplacer vers le répertoire); mais la complexité de votre logique de programmation ne souffre pas trop mal par rapport à l'équivalent de la structure des dossiers.

Cette situation est vraiment nulle. Android est un mélange de décisions de conception merveilleuses et terribles. Nous ne pouvons qu'espérer que la dernière portion sera éliminée avec toute la hâte due :)

Cheezmeister
la source
31
Juste une note que les majuscules ne sont pas autorisées dans le dossier dessinable. J'obtiens l'erreur: "Nom de fichier invalide: ne doit contenir que [a-z0-9_.]"
Jason Axelson
5
+1 pour "sac mélangé de décisions de conception merveilleuses et terribles"
Brent Faust
1
À peine une solution: plutôt "ce que vous devez faire pour ne pas devenir complètement fou". Il est ridicule d'être limité à un seul répertoire.
RichieHH
35

En fait, sur Android Studio, c'est possible. Vous pouvez avoir des ressources imbriquées comme indiqué ici :

entrez la description de l'image ici

Il existe également un plugin pour regrouper les ressources ici .

développeur android
la source
Salut, développeur @android! J'ai essayé d'ajouter ceci dans le fichier build.gradle: sourceSets {main {res {srcDir 'src / main / res / drawable / ic-toggle'}}}, mais j'ai "Uri n'est pas enregistré" pour xmlns : android = " schemas.android.com/apk/res/android . Quel pourrait être le cas?
AlexKost
@AlexKost J'ai en fait essayé une seule fois. Je n'ai pas assez d'expérience avec cela pour vous aider. Désolé.
développeur Android
@RahulMandaliya Même si c'est possible, je suggère de ne pas l'utiliser.
développeur Android
@androiddeveloper Pourquoi pas?
Josh Hansen
1
@JoshHansen C'est désordonné.
développeur Android
34

Oui - ça craint :) Cependant, vous pouvez utiliser le dossier assets et y avoir des sous-répertoires et charger des images de cette façon.

dijipiji
la source
6
le problème n'est pas seulement pour le dossier dessinable mais aussi pour le dossier de mise en page :( Le dossier de ma mise en page contient plus de 100 fichiers xml, et il m'est difficile d'ouvrir la bonne mise en page xml dans ce
dossier
A part d'autres objections, les ressources peuvent être facilement localisées mais AFAIK il n'y a pas de mécanisme intégré l10n pour les actifs.
Fran Marzoa
@anticafe utilise "Aller à la ressource" dans votre IDE (Eclipse: CTRL + SHIFT + R, IDEA / Android Studio: CTRL + SHIFT + N)
TWiStErRob
23

Utilisez le dossier des ressources.

exemple de code:

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

image = BitmapFactory.decodeStream(is);
Milkia
la source
5
Le seul problème avec cette méthode est qu'il y a BEAUCOUP plus de devoirs impliqués dans l'utilisation des bitmaps. Le système de ressources d'Android fait un bien meilleur travail de gestion de la mémoire. Pourquoi reconstruiriez-vous un système de gestion de mémoire alors qu'Android le fait déjà? Surtout s'il a plus de 100 images, c'est beaucoup de chargement et de libération de bitmaps.
Rev Tyler
18
C'est un vrai problème si vous prévoyez de localiser votre application, même si vous avez des ressources différentes pour différentes densités d'écran, donc ce n'est pas une solution, juste une solution de contournement valable pour certains cas seulement.
Fran Marzoa
1
Je dois donner au moins mille commentaires positifs à @Fran :)
HGPB
22

J'ai écrit un plugin eclipse qui permet de créer un sous-dossier virtuel en séparant le nom du fichier par deux traits de soulignement __. Le projet est à ses débuts, mais ne vous inquiétez pas, il ne plantera pas votre IDE

plus de détails peuvent être trouvés ici, n'hésitez pas à bifurquer et envoyer des demandes de pull:

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

entrez la description de l'image ici

Kirill Kulakov
la source
2
Agréable! Avez-vous également la possibilité de porter cela sur Android Studio?
BVB
1
Je n'utilise actuellement même pas Android Studio, donc je suppose que nous devrons attendre que certains expérimentés le transfèrent.
Kirill Kulakov
9

J'aime utiliser un script simple pour aplatir une structure de répertoires organisée fournie par les concepteurs à quelque chose qui peut être utilisé pour générer un fichier R.

Exécuter avec le chemin actuel dans 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
René
la source
1
Votre script ne fonctionnera pas s'il y a des sous-dossiers sous les dossiers. Je pense que vous devez remplacer tous les '/' par '_' dans $ {dir}.
Seunghoon
9

Dans le studio Android avec gradle, vous pouvez avoir plusieurs directeurs de source qui vous permettront de séparer les ressources. Par exemple:

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

Cependant, les noms ne doivent pas entrer en collision, ce qui signifie que vous devrez toujours avoir des noms tels que sandwiches_tunaOnRye, mais vous pourrez avoir une section distincte pour tous vos sandwichs.

Cela vous permet de stocker vos ressources dans différentes structures (utiles pour le contenu généré automatiquement tel que actionbargenerator)

Alec Holmes
la source
4

Une façon de contourner partiellement le problème consiste à utiliser le suffixe de niveau API. J'utilise res / layout-v1, res / layout-v2 etc. pour contenir plusieurs sous-projets dans le même apk. Ce mécanisme peut être utilisé pour tous les types de ressources.

De toute évidence, cela ne peut être utilisé que si vous ciblez des niveaux d'API supérieurs à res / layout-v? vous utilisez.

Faites également attention au bogue dans Android 1.5 et 1.6. Voir la documentation d'Andoroid sur le suffixe de niveau API .

OferR
la source
À quiconque a déclassé cette réponse: pouvez-vous expliquer pourquoi? Ce mécanisme, bien que pas joli, fonctionne bien pour moi.
OferR
4

Avec l'avènement du système de bibliothèque, la création d'une bibliothèque par grand ensemble d'actifs pourrait être une solution.

C'est toujours problématique car il faut éviter d'utiliser les mêmes noms dans tous les actifs, mais l'utilisation d'un schéma de préfixe par bibliothèque devrait aider à cela.

Ce n'est pas aussi simple que de pouvoir créer des dossiers, mais cela aide à garder les choses saines d'esprit ...

Shi
la source
Oui, je pense que c'est bien. Si j'ajoute des drapeaux de pays à mes dossiers drawable-ldpi, etc., ils seront submergés. Je pense que la création d'un projet de bibliothèque pour toutes les ressources génériques contribuera à réduire l'encombrement dans le projet sur lequel vous travaillez activement. Surpris, vous n'avez qu'une seule voix positive.
Tom
3

Il existe une solution de contournement à cette situation: vous pouvez créer un resVectordossier (par exemple) au même niveau que le resdossier par défaut . Vous pouvez y ajouter n'importe quel drawable-xxxdossier de ressources:

resVector
-drawable
-layout
-color

Après cela, il vous suffit d'ajouter

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

dans votre build.gradledossier (à l'intérieur android { }).

Anton Derevyanko
la source
Malheureusement, ils fusionnent dans le panneau de projet dans Android Studio lors de l'utilisation de la perspective "Android" :(
AjahnCharles
@AjahnCharles - Je préfère ne pas du tout utiliser cette perspective (de toute façon - je travaille toujours en "mode sans distraction") ... Mais vous avez raison - "Android" fusionne tout.
Anton Derevyanko
1

Ce ne sont pas des méthodes parfaites. Vous devez implémenter la même manière qui est affichée ici .

Vous pouvez également appeler l'image sous le dossier via le code que vous pouvez utiliser

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

TextView tv = (TextView)findViewByID(R.id.textview);
tv.setBackground(shape);
user3177928
la source
1

Pas le mien mais j'ai trouvé ce fil lors de la recherche de ce problème, si vous utilisez le système Android Studio et Gradle Build, c'est assez facile, aucun plugin nécessaire juste un peu d'édition du fichier de construction

https://stackoverflow.com/a/22426467/618419

Captnwalker1
la source
1

Gradle avec Android Studio pourrait le faire de cette façon ( lien ).

C'est dans le paragraphe "Configuration de la structure"

sourceSets {
 main {
    java {
        srcDir 'src/java'
    }
    resources {
        srcDir 'src/resources'
    }
 }
}
user3290180
la source
1

créer un dossier dans main. comme: 'res_notification_btn'

et créer un dossier d'arborescence dans. comme «dessinable» ou «mise en page»

puis dans 'build.gradle' ajoutez ceci

sourceSets
            {
                main
                {
                    res
                    {
                        srcDirs = ['src/main/res_notification_btn', 'src/main/res']
                      or
                        srcDir 'src/main/res_notification_btn'
                    }
                }
            }
Ali Bagheri
la source
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?("/")
}
Blake Miller
la source
Tout cela ne fait qu'automatiser la solution de contournement suggérée par Cheezmeister. Ça marche pour moi ... tu veux expliquer le downvote?
Blake Miller
0

actifs / Vous pouvez l'utiliser pour stocker des fichiers d'actifs bruts. Les fichiers que vous enregistrez ici sont compilés dans un fichier .apk tel quel et le nom de fichier d'origine est conservé. Vous pouvez parcourir ce répertoire de la même manière qu'un système de fichiers classique à l'aide d'URI et lire des fichiers sous forme de flux d'octets à l'aide de AssetManager. Par exemple, c'est un bon emplacement pour les textures et les données de jeu. http://developer.android.com/tools/projects/index.html

Alex M
la source
0

Les sous-répertoires ne sont pas autorisés, la ressource ne doit contenir que [a-z0-9_.].

Non, vous avez des lettres majuscules et aucune barre oblique.

Ferhat Aslan
la source
-3
  1. Clic droit sur Drawable
  2. Sélectionnez Nouveau ---> Répertoire
  3. Saisissez le nom du répertoire. Par exemple: logo.png (l'emplacement affichera déjà le dossier dessinable par défaut)
  4. Copiez et collez les images directement dans le dossier dessinable. Pendant le collage, vous avez la possibilité de choisir mdpi / xhdpi / xxhdpi, etc. pour chacune des images d'une liste. Sélectionnez l'option appropriée et entrez le nom de l'image. Assurez-vous de conserver le même nom que le nom du répertoire, c'est-à-dire logo.png
  5. Faites de même pour les images restantes. Tous seront placés dans le dossier principal logo.png.
Afreen Hasheem Siraj
la source