Can the Android drawable directory contain subdirectories? - android

In the Android SDK documentation, all of the examples used with the #drawable/my_image xml syntax directly address images that are stored in the res/drawable directory in my project.
I am wondering if it is explicitly not okay to create a sub directory within the drawable directory.
For example, if I had the following directory layout:
res/drawable
-- sandwiches
-- tunaOnRye.png
-- hamAndSwiss.png
-- drinks
-- coldOne.png
-- hotTea.png
Could I reference the image of a tuna salad sandwich as #drawable/sandwiches/tunaOnRye
Or do I have to keep the hierarchy flat in the drawable directory.

No, the resources mechanism doesn't support subfolders in the drawable directory, so yes - you need to keep that hierarchy flat.
The directory layout you showed would result in none of the images being available.
From my own experiments it seems that having a subfolder with any items in it, within the res/drawable folder, will cause the resource compiler to fail -- preventing the R.java file from being generated correctly.

The workaround I'm using (and the one Android itself seems to favor) is to essentially substitute an underscore for a forward slash, so your structure would look something like this:
sandwich_tunaOnRye.png
sandwich_hamAndSwiss.png
drink_coldOne.png
drink_hotTea.png
The approach requires you to be meticulous in your naming and doesn't make it much easier to wrangle the files themselves (if you decided that drinks and sandwiches should really all be "food", you'd have to do a mass rename rather than simply moving them to the directory); but your programming logic's complexity doesn't suffer too badly compared to the folder structure equivalent.
This situation sucks indeed. Android is a mixed bag of wonderful and terrible design decisions. We can only hope for the latter portion to get weeded out with all due haste :)

Actually, on Android Studio it is possible. You can have nested resources as shown here :
There is also a plugin to group resources here.
I recommend to avoid this though.

Yes - it does suck :) However you can use the assets folder and have sub directories in there and load images that way.

Use assets folder.
sample code:
InputStream is = null;
try {
is = this.getResources().getAssets().open("test/sample.png");
} catch (IOException e) {
;
}
image = BitmapFactory.decodeStream(is);

I've wrote an eclipse plugin which allows to create virtual subfolder by separating the file name with two underscores __. The project is in early stages, but don't worry it won't crash your IDE
more details can be found here, feel free to fork and send pull requests:
https://github.com/kirill578/Android-Sorted-Res-Folder

I like to use a simple script to flatten an organized directory structure provided by designers to something that can be used to generate an R file.
Run with current path in 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

In android studio with gradle you can have multiple source directors which will allow you to separate resources. For example:
android {
....
android.sourceSets {
main.res.srcDirs = ['src/main/extraresdirnamed_sandwiches', 'src/main/res']
}
....
}
However the names must not collide which means you will still need to have names such as sandwiches_tunaOnRye but you will be able to have a seperate section for all of your sandwiches.
This allows you to store your resources in different structures (useful for auto generated content such as actionbargenerator)

One way to partially get around the problem is to use the API Level suffix.
I use res/layout-v1, res/layout-v2 etc to hold multiple sub projects in the same apk.
This mechanism can be used for all resource types.
Obviously, this can only be used if you are targeting API levels above the res/layout-v? you are using.
Also, watch out for the bug in Android 1.5 and 1.6.
See Andoroid documentation about the API Level suffix.

With the advent of library system, creating a library per big set of assets could be a solution.
It is still problematic as one must avoid using the same names within all the assets but using a prefix scheme per library should help with that.
It's not as simple as being able to create folders but that helps keeping things sane...

There is a workaround for this situation: you can create a resVector (for example) folder on the same level as default res folder. There you can add any drawable-xxx resource folders there:
resVector
-drawable
-layout
-color
After that all you need is to add
sourceSets {
main.res.srcDirs += 'src/main/resVector'
}
into your build.gradle file (inside android { }).

This is not perfect methods. You have to implement same way which is display here.
You can also call the image under the folder through the code you can use
Resources res = getResources();
Drawable shape = res. getDrawable(R.drawable.gradient_box);
TextView tv = (TextView)findViewByID(R.id.textview);
tv.setBackground(shape);

Not mine but I found this thread when looking for this issue, if your using Android Studio and Gradle Build system its pretty easy no plugins necessary just a little build file editing
https://stackoverflow.com/a/22426467/618419

Gradle with Android Studio could do it this way (link).
It's in the paragraph "Configuring the Structure"
sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}

create a folder in main.
like: 'res_notification_btn'
and create tree folder in. like 'drawable' or 'layout'
then in 'build.gradle' add this
sourceSets
{
main
{
res
{
srcDirs = ['src/main/res_notification_btn', 'src/main/res']
or
srcDir 'src/main/res_notification_btn'
}
}
}

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

Check Bash Flatten Folder script that converts folder hierarchy to a single folder

assets/
You can use it to store raw asset files. Files that you save here are compiled into an .apk file as-is, and the original filename is preserved. You can navigate this directory in the same way as a typical file system using URIs and read files as a stream of bytes using the AssetManager. For example, this is a good location for textures and game data.
http://developer.android.com/tools/projects/index.html

Subdirectories are not allowed, the resource must contain only [a-z0-9_.].
No you have uppercase letters, and no forward slashes.

It is possible to have multiple drawable folders by having an extra folder parallel to 'res' with a subdirectory 'drawable' and then add following to gradle:
sourceSets {
main {
res.srcDirs 'src/main/<extra_res>'
}
}
Tested with gradle 6.5.1

For anyone using Xamarin (either Xamarin.Android or Xamarin.Forms), there is a way to do this.
In the .csproj file for the Android project find the line for MonoAndroidResourcePrefix (documented, though rather poorly, here). Add the subdirectories you are wanting to use here, separating each entry by semicolons. When building, Visual Studio strips these prefixes so that all of the resources end up in a flat hierarchy. You may need to reload the solution after making these changes.
These directories do not need to be subdirectories of the default Resources directory in the project.
Make sure that files you add are getting the build action set to "AndroidResource".
For Xamarin.Android, the visual editor won't recognize images and will show the error "This resource URL cannot be resolved" but the project will build and the image will be visible at runtime.

Right click on Drawable
Select New ---> Directory
Enter the directory name. Eg: logo.png(the location will already show the drawable folder by default)
Copy and paste the images directly into the drawable folder. While pasting you get an option to choose mdpi/xhdpi/xxhdpi etc for each of the images from a list. Select the appropriate option and enter the name of the image. Make sure to keep the same name as the directory name i.e logo.png
Do the same for the remaining images. All of them will be placed under the logo.png main folder.

Related

Is it possible to use strings.xml from one localization values folder for another similar language?

I've been looking on Internet for this but didn't find any article/blog (probably I have been looking poorly) so I'd decided to ask question here: is it possible to use same strings.xml (translations) from one language folder for another language, which is very similar? To be more specific, I'd like to use translations from values-sk also for values-cz language.
I was thinking about writing a Gradle script which would make a copy of strings.xml file in values-sk folder and copy it into values-cz folder on build, but I'd like to know if there's an easier/out of the box solution.
Well, I solved it using Gradle script before build. In case someone's interested, I added new task in app.gradle (at the end of the file, but that shouldn't matter):
gradle.projectsEvaluated {
preBuild.dependsOn(copySkStringsFileToCsFolder)
}
task copySkStringsFileToCsFolder(type: Copy) {
description = 'Copies strings.xml from values-sk to values-cs'
from 'src/main/res/values-sk/strings.xml'
into 'src/main/res/values-cs'
}
From what I overview, it copies the file on every Sync/Build operation - works pretty neatly for me, but I am still interested in other possibilities (if there are any).
Also I would like to apologize to Czech people that I misinterpreted the code for values folder (using -cz instead of -cs) - sorry 'bout that, I didn't know I was supposed to use the other one. :)
Create both values-sk & values-cz folder in your /res directory of your project and then copy-paste the strings.xml to each. As you can see, those will be different directories but with the same strings.xml so, it probably should work.
After that, Android will detect that you have two different directory-strings for two different localization then, you can change, modify each one of them (If needed).

Android project structure based on features

I am currently using the default android folder structure. It's now becoming very hard to manage the activities and views. I was wonder if there way to structure my project layouts and activities by features.
For example:
Following is my current project structure.
Java
-Activity
OrderListActivity.java
ProductListAcitvity.java
Res
-Layout
OrderListView.xml
ProductView.xml
I am trying to find a way to combine the view and activities into a same folder like:
Java
-Features
-OrderList
OrderListActivity.java
OrderListView.xml
-Products
ProductListActivity.java
ProductView.xml
Is this structure possible with gradle? if so could you please provide some samples gradle settings to achieve this.
Thanks
You can't place a java source file with layout file in the same directory. But you can organize each layout by features with a slight hack in your app build.gradle.
First, create a root directory for the layouts in res directory. The name should be layouts:
res/layouts
Then, you can create a directory for the layout based on the features. We use OrderList and Products. Each directory needs a layout directory inside of them. Now create the directories in the layouts like this:
res/layouts/orderlist/layout
res/layouts/products/layout
Then, add the following code to your app build.gradle:
android {
...
sourceSets {
main {
res.srcDirs = ['src/main/res',
'src/main/res/layouts',
'src/main/res/layouts/orderlist',
'src/main/res/layouts/products',
}
}
...
}
Change your project to project view like this:
Sync your project to update the build.gradle. Now, you can add your layout inside the orderlist and products
In short, not possible.
If your app contains a large amount of files, you can separate them into different modules.
You cannot have java files with xml resources inside the same folder. They belong to different categories. What you could do is associate the xml files with their corresponding java files by using appropriate naming conventions.

Regarding understanding Android resource folder

I make a research, and I delve deep into Android resources files. According to this link, it says that Android externalize and separate users' resources from the code to allow using
these resources by Ids that will be generated in R.class, here is the text:
Once you externalize your application resources, you can access them using resource IDs that are generated in your project's R class.
(1): Does being the 'res' folder exists means generating the R.java class? In other words, is R.java a representation to "ids" assigned to any values inside 'res' folder?
(2): Is it possible to place my 'layout' or 'string' files in any other folders aside from 'res'?
Is R.java a representation to "ids" assigned to any values inside
'res' folder?
It is most likely the idea of R.java.
Is it possible to place my 'layout' or 'string' files in any other
folders aside from 'res'?
Yes you can do that but before you start make sure you checked the project structure view and not the other options like android structure view.
In your build.gradle
android {
....
sourceSets {
main {
res.srcDirs = [
"src/main/module-res/compose"
];
}
}
}
Then create the desired directory similar to what you have declared.
Here is an example image showing that it will work.
What's good about it is that you can make more res folder (just add it in the array and separate it with comma). Take note that each res folder must have its own drawable, layout etc. folder.
Example:
res.srcDirs = [
"src/main/module-res/compose",
"src/main/module-res/design",
"src/main/module-res/extra"
];
R.java file is an auto-generated file by aapt (Android Asset Packaging
Tool) that contains resource IDs for all the resources of res/
directory. when you create any component in the xml file, id for the
corresponding component is automatically created in this file.
when creating an layout file using android studio it will automatically put it under layout folder, but when you create it manually it will be classified as the parent folder, eg : create layout file under drawable will be called like R.drawable.mLayout, android studio will show it as warning but it will work fine, so yes you can put any type of xml under any folder and it will work fine, put it's easier to classify as default for more readability and clearer architecture

Custom resource folder name (e.g. res\drawable-gamepad)

I'm adding gamepad support to my game. I need a lot of resources (strings, drawables) specific to gamepad. Specifying a different name for a gamepad resource is not very efficient, as I have to write a lot of code like this:
if (gamepadDetected) {
image.setImageDrawable(getResources().getDrawable(R.drawable.controls_gamepad));
} else {
image.setImageDrawable(getResources().getDrawable(R.drawable.controls_touch));
}
The easiest way would be to create a new directory, say res\drawable-gamepad and somehow instruct Android to use resources from this folder when my game detects gamepad.
This way I could use the same names for resources (say res\drawable\controls.jpg and res\drawable-gamepad\controls.jpg). But I'm guessing this is not possible.
Is there any other easy way to add alternate resources to the existing project?
custoum folders are not supported in the res folder but you can use the assets folder for you own folder structure.
see the Link: Difference between /res and /assets directories

Android: How to add R.raw to project?

How I could add R.raw class to my android project?
Now I haven't /res/raw folder at all (and class as well).
And I can't find any tools in eclipse to do that.
So how to add R.raw?
Adding a raw folder to your resource folder (/res/) should do the trick.
Read more here:
https://developer.android.com/guide/topics/resources/providing-resources.html
Right click on package or Res folder click on new on popup then click on android resource directory
a new window will be appear change the resource type to raw and hit OK copy and past song to raw folder
remember don't drag and drop song file to raw folder and song spell should be in lower case! This method is for Android Studio Also Check MY Link
If you have a res/raw folder, be sure to add a file with a valid filename, otherwise the entire folder won't show up in the R class. If there's an error with a filename, it will appear in red in the console.
Simply add a folder 'raw' to your res folder.
The R class is written when you build the project in gradle. You should add the raw folder, then build the project. After that, the R class will be able to identify R.raw.*.
To get it to recognize the raw file, make sure you create it, and add it as a raw resource file. Then go to build.gradle file and add this block of code.
sourceSets {
main {
assets.srcDirs = ['/res/raw']
}
}
You may have to restart android studio if above solutions aren't working, i restarted it and then it works.
(With reference to Android Studio)
Create a new directory in res folder. Make sure to create new "Android Resource Directory" and not new "Directory".
Then ensure that there is at least one valid file in it. It should show up now.
Using IntelliJ Idea:
1) Invalidate Caches, and
2) right click on resources, New Resources directory, type = raw
3) build
note in step 2: I was concerned that simply adding a raw directory wouldn't be enough...
You need to right-click on res->new->Android resource directory. Make sure you select directory and not file.
Select raw in resource type and it automatically selects raw as the directory name.
Drag and drop your .mp3 music file inside the res folder. Make sure that it starts with a small letter.
Here is the string to access files in raw folder.
Replace filename with name of your file.
android.resource://" + getPackageName() + "/" + R.raw.filename
Create a raw android resource directory.
Once the raw directory is created, Make sure to add a valid media file
Make sure to follow proper naming conventions (lower case letters with underscore '_' as separators)
Media file should have a proper encoding and formatted media file in one of the supported formats.
After following the above procedure, you should be able to access your media files by using R.raw.media_file
Right CLick on res folder -> New Android Resource Directory - select resource type raw -> ok and move your file to this folder
Even if its showing unresolved reference: raw in the Android Studio, it does still run. when I did the rebuild it didn't show any error during the build. just put the right path like R.raw.myrawfile and run it, the app will run.
if u want the red mark on the code to go away you probably have to restart (do invalidate cache and restart)
Try putting a + before R.xyz. That should start showing additional folders, e.g.:
+ R.raw.beep.mp3

Categories

Resources