Reputation: 1526
I have a project that has a ton of avatars. Right now, I have 20+ pictures that will be available to the user using a combination of spinner selections. Right now, there are 20 combinations they can make from just two spinners. This number will grow as I get more art assets.
Is there a way to take the selections they have and programatically choose the correct picture from the resources?
If they choose "sportscar" on the first spinner and "red" on the second spinner, I want to take those two values and load up "sportscar_red.png" by passing the strings to the next activity.
Is there any way to do this?
If not, is there something better than having a disgustingly huge cascading "if/else if" statement?
Edit: Avoiding long "if/else if" statements through other means of tedious hard-coding does not seem to gain any ground with this problem. My main priority when choosing a secondary solution is something that is easy to maintain and scale.
Upvotes: 0
Views: 61
Reputation: 17868
Use following, it's already build in android resource class:
public static int getDrawableResId(Context context, String name)
{
return context.getResources().getIdentifier(name, "drawable", context.getPackageName());
}
Just use it like following:
int selectedResource = getDrawableResId(context, "sportscar_red");
Supporting multiple languages with a special adapter (as someone mentioned it)
For supporting multiple languages, use a special data structure in your spinners, that provides the name of the selected part AND the localised display name... Something like following should work:
class Part
{
private String mName;
private String mDisplayName;
public Part(Context c, String name, int displayNameRes)
{
mName = name;
mDisplayName = c.getString(displayNameRes);
}
public String getName()
{
return mName;
}
@Override
public String toString()
{
return mName; // will be used by a simple text spinner adapter... so you don't need to write a custom adapter if you just want to display a simple text, BUT use a custom class
}
}
Now you can create the ArrayAdapter
with following list:
ArrayList<Part> cars = new ArrayList<>();
cars.add(new Part(context, "sportscar", R.string.sportscar));
...
Problem with the getField
approach
It will fail if the resource is named like "text.text"... And as there is a native support for retrieving resources by name it's not necessary...
Upvotes: 0
Reputation: 7311
You could just use the /assets
folder instead of /res
and load drawable
s for your avatars directly.
String avatarName = firstSpinner + '_' + secondSpinner + '.png';
Drawable d = Drawable.createFromStream(getAssets().open("avatars/" + avatarName), null);
Upvotes: 0
Reputation: 2528
To get a resource ID just from the resource name, with no map, the fastest way is with a method like this:
private int getResourceId(@NonNull String drawableName) {
int resourceId = -1;
try {
Field field = com.your.package.R.drawable.class.getField(drawableName);
resourceId = field.getInt(null);
} catch (Exception e) {
// Drawable id not found
}
return resourceId;
}
So, when you have the two String
s from the spinners, simply call:
int resId = getResourceId(string1 + "_" + string2)
And that will return the resource ID you need to display, or -1 if it could not be found. No need for hardcoded Map
s or if/else statements.
Other alternatives to dynamic resource names, like Resources.getIdentifier()
, are actually slower because they perform more reflection calls in the backgound. A good read on the subject by Daniel Lew can be found here
Upvotes: 1
Reputation: 3016
I think the way you describe it in your question is the solution already.
Use the value returned from each spinner, combine them using a StringBuilder and use that String to get the image.
For this to work, you need to:
- Have a very strong naming structure and stick to it.
- Don't get the value from the spinner using getText because this would prevent you from using multiple languages in your app. You need to be able to get the id value from the String rather than the string itself.
Then you pass the string in Intent. No problem there.
Upvotes: 0
Reputation: 297
I would use a HashMap if you can, have the spinner as the key, the drawable as the value. Load 'em up when you need.
static Map<String, Integer> icons = new HashMap<String, Integer>();
static
{
icons.add("icon1", R.drawable.icon);
icons.add("icon2", R.drawable.icon2);
icons.add("icon3", R.drawable.icon3);
}
Upvotes: 0