从 Resources 对象中检索所有 Drawable 资源
Posted
技术标签:
【中文标题】从 Resources 对象中检索所有 Drawable 资源【英文标题】:Retrieving all Drawable resources from Resources object 【发布时间】:2011-03-14 09:23:03 【问题描述】:在我的 android 项目中,我想遍历整个 Drawable
资源集合。通常,您只能使用以下方式通过其 ID 检索特定资源:
InputStream is = Resources.getSystem().openRawResource(resourceId)
但是,我想获取所有Drawable
资源,而我不会事先知道他们的 ID。有没有我可以循环使用的集合,或者是否有一种方法可以获取给定项目中资源的资源 ID 列表?
或者,我有没有办法在 Java 中从 R.drawable
静态类中提取所有属性值?
【问题讨论】:
【参考方案1】:好的,这感觉有点 hack-ish,但这是我通过 Reflection 想出的。 (注意resources
是类android.content.res.Resources
的一个实例。)
final R.drawable drawableResources = new R.drawable();
final Class<R.drawable> c = R.drawable.class;
final Field[] fields = c.getDeclaredFields();
for (int i = 0, max = fields.length; i < max; i++)
final int resourceId;
try
resourceId = fields[i].getInt(drawableResources);
catch (Exception e)
continue;
/* make use of resourceId for accessing Drawables here */
如果有人有更好的解决方案,可以更好地利用我可能不知道的 Android 调用,我绝对希望看到他们!
【讨论】:
这是获取我能找到的资源(相对于资产)的唯一方法。请注意,您不需要 drawableResources。由于 R 的所有字段都是静态的,因此 getInt() 可以取 null。 只是一个需要注意的细节:java.lang.reflect.Field
这会在什么时候被调用?我创建了一个返回图像数组的函数,但我收到一条错误消息,指出该数组为空,因此它没有长度 @SteveBlackwell
@PjRigor 如果不看一些代码,很难知道为什么会得到这个结果。最好发布一个新问题。【参考方案2】:
我使用 getResources().getIdentifier 扫描资源文件夹中按顺序命名的图像。为了安全起见,我决定在第一次创建活动时缓存图像 ID:
private void getImagesIdentifiers()
int resID=0;
int imgnum=1;
images = new ArrayList<Integer>();
do
resID=getResources().getIdentifier("img_"+imgnum, "drawable", "InsertappPackageNameHere");
if (resID!=0)
images.add(resID);
imgnum++;
while (resID!=0);
imageMaxNumber=images.size();
【讨论】:
【参考方案3】:我采纳了 Matt Huggins 的好答案,并对其进行了重构以使其更通用:
public static void loadDrawables(Class<?> clz)
final Field[] fields = clz.getDeclaredFields();
for (Field field : fields)
final int drawableId;
try
drawableId = field.getInt(clz);
catch (Exception e)
continue;
/* make use of drawableId for accessing Drawables here */
用法:
loadDrawables(R.drawable.class);
【讨论】:
【参考方案4】:你应该使用 Raw 文件夹和 AssetManager,但如果你想使用 drawables,为什么不呢,这里是如何...
假设我们有一个很长的 JPG 可绘制文件列表,并且我们想要获取所有资源 ID,而无需一一检索(R.drawable.pic1、R.drawable.pic2 等)
//first we create an array list to hold all the resources ids
ArrayList<Integer> imageListId = new ArrayList<Integer>();
//we iterate through all the items in the drawable folder
Field[] drawables = R.drawable.class.getFields();
for (Field f : drawables)
//if the drawable name contains "pic" in the filename...
if (f.getName().contains("image"))
imageListId.add(getResources().getIdentifier(f.getName(), "drawable", getPackageName()));
//now the ArrayList "imageListId" holds all ours image resource ids
for (int imgResourceId : imageListId)
//do whatever you want here
【讨论】:
【参考方案5】:添加一张名为 aaaa 的图片和另一张名为 zzzz 的图片,然后遍历以下内容:
public static void loadDrawables()
for(long identifier = (R.drawable.aaaa + 1);
identifier <= (R.drawable.zzzz - 1);
identifier++)
String name = getResources().getResourceEntryName(identifier);
//name is the file name without the extension, indentifier is the resource ID
这对我有用。
【讨论】:
我喜欢这个 hack 背后的创意。 ;) 多么有创意啊!非常感谢【参考方案6】:如果您发现自己想要这样做,您可能误用了资源系统。如果您想遍历 .apk 中包含的文件,请查看资产和 AssetManager
。
【讨论】:
谢谢,我去看看。我正在尝试将纹理加载到内存中以在 OpenGL 游戏中使用。 这行得通,并且不太特定于项目(由于类R
是特定于项目的),我喜欢。唯一的区别是我必须使用“assets”文件夹而不是“res”文件夹。
这不是答案。【参考方案7】:
我猜反射代码会起作用,但我不明白你为什么需要这个。
一旦安装了应用程序,Android 中的资源就是静态的,因此您可以拥有资源列表或数组。比如:
<string-array name="drawables_list">
<item>drawable1</item>
<item>drawable2</item>
<item>drawable3</item>
</string-array>
您可以通过Activity
获得它:
getResources().getStringArray(R.array.drawables_list);
【讨论】:
这行得通,但它的问题是每次我向文件夹添加一个可绘制对象时,我还必须更新这个字符串数组。我正在寻找更自动化的东西。【参考方案8】:这样做:
Field[] declaredFields = (R.drawable.class).getDeclaredFields();
【讨论】:
那么如何从字段对象中获取资源? 可以这样写代码:imageView.setImageDrawable(Utils.getDrawable(declaredFields.get(position).getName(), context))【参考方案9】:OP 想要可绘制对象,而我需要布局。这就是我想出的布局。 name.startsWith
业务让我忽略系统生成的布局,因此您可能需要稍微调整一下。通过修改clz
的值,这应该适用于任何资源类型。
public static Map<String,Integer> loadLayouts()
final Class<?> clz = R.layout.class;
Map<String,Integer> layouts = new HashMap<>();
final Field[] fields = clz.getDeclaredFields();
for (Field field : fields)
String name = field.getName();
if (
!name.startsWith("abc_")
&& !name.startsWith("design_")
&& !name.startsWith("notification_")
&& !name.startsWith("select_dialog_")
&& !name.startsWith("support_")
)
try
layouts.put(field.getName(), field.getInt(clz));
catch (Exception e)
continue;
return layouts;
【讨论】:
【参考方案10】:使用我的代码
R.drawable drawableResources = new R.drawable();
Class<R.drawable> c = R.drawable.class;
Field[] fields = c.getDeclaredFields();
for (int i = 0, max = fields.length; i < max; i++)
final int resourceId;
try
resourceId = fields[i].getInt(drawableResources);
// call save with param of resourceId
SaveImage(resourceId);
catch (Exception e)
continue;
...
public void SaveImage(int resId)
if (!CheckExternalStorage())
return;
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resID);
try
File dir = new File(path);
if (!dir.exists())
dir.mkdirs();
OutputStream fOut = null;
File file = new File(path, "image1.png");
file.createNewFile();
fOut = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 100, fOut);
fOut.flush();
fOut.close();
MediaStore.Images.Media.insertImage(this.getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
Log.i(LOGTAG, "Image Written to Exterbal Storage");
catch (Exception e)
Log.e("saveToExternalStorage()", e.getMessage());
【讨论】:
【参考方案11】:在 Kotlin 中创建一组可绘制对象:
val drawablesFields: Array<Field> = drawable::class.java.fields
val drawables: ArrayList<Drawable> = ArrayList()
for (field in drawablesFields)
context?.let ContextCompat.getDrawable(it, field.getInt(null)) ?.let
drawables.add (
it
)
【讨论】:
以上是关于从 Resources 对象中检索所有 Drawable 资源的主要内容,如果未能解决你的问题,请参考以下文章
使用 underscore.js 从对象/数组中仅检索一个字段