从 Resources 对象中检索所有 Drawable 资源

发布于 2024-09-08 19:27:23 字数 353 浏览 4 评论 0原文

在我的 Android 项目中,我想循环遍历整个 Drawable 资源集合。通常,您只能使用以下内容通过其 ID 检索特定资源:

InputStream is = Resources.getSystem().openRawResource(resourceId)

但是,我想获取所有我不会事先知道其 ID 的 Drawable 资源。是否有一个我可以循环遍历的集合,或者是否有一种方法可以获取项目中给定资源的资源 ID 列表?

或者,我在 Java 中是否有一种方法可以从 R.drawable 静态类中提取所有属性值?

In my Android project, I want to loop through the entire collection of Drawable resources. Normally, you can only retrieve a specific resource via its ID using something like:

InputStream is = Resources.getSystem().openRawResource(resourceId)

However, I want to get all Drawable resources where I won't know their ID's beforehand. Is there a collection I can loop through or perhaps a way to get the list of resource ID's given the resources in my project?

Or, is there a way for me in Java to extract all property values from the R.drawable static class?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

深者入戏 2024-09-15 19:27:23

好吧,这感觉有点 hack,但这是我通过 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 调用,我可能不知道的,我绝对想见见他们!

Okay, this feels a bit hack-ish, but this is what I came up with via Reflection. (Note that resources is an instance of class 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 */
}

If anyone has a better solution that makes better use of Android calls I might not be aware of, I'd definitely like to see them!

风启觞 2024-09-15 19:27:23

我采用了马特·哈金斯(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);

I have taken Matt Huggins great answer and refactored it to make it more generic:

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 */
    }   
}

Usage:

loadDrawables(R.drawable.class);
最美不过初阳 2024-09-15 19:27:23

我使用 getResources().getIdentifier 扫描资源文件夹中按顺序命名的图像。为了安全起见,我决定在第一次创建 Activity 时缓存图像 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();
}

i used getResources().getIdentifier to scan through sequentially named images in my resource folders. to be on a safe side, I decided to cache image ids when activity is created first time:

    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();
}
旧瑾黎汐 2024-09-15 19:27:23

您应该使用 Raw 文件夹和 AssetManager,但如果您想使用可绘制对象,因为为什么不呢,方法如下...

假设我们有一个很长的 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
}

You should use the Raw folder and AssetManager, but if you want to use drawables because why not, here is how...

Let's suppose we have a very long file list of JPG drawables and we want to get all the resource ids without the pain of retrieving one by one (R.drawable.pic1, R.drawable.pic2, ... etc)

//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
}
我家小可爱 2024-09-15 19:27:23

添加一张名为 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
  }
}

这对我有用。

Add a picture named aaaa and another named zzzz, then iterate through the following:

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
  }
}

This worked for me.

各自安好 2024-09-15 19:27:23

如果您发现自己想要这样做,您可能正在滥用资源系统。查看资产和 AssetManager 如果您想迭代 .apk 中包含的文件。

If you find yourself wanting to do this you're probably misusing the resource system. Take a look at assets and AssetManager if you want to iterate over files included in your .apk.

烟燃烟灭 2024-09-15 19:27:23

我想反射代码会起作用,但我不明白为什么你需要这个。

一旦安装了应用程序,Android 中的资源就是静态的,因此您可以拥有资源列表或数组。类似于:

<string-array name="drawables_list">
    <item>drawable1</item>
    <item>drawable2</item>
    <item>drawable3</item>
</string-array>

从您的 Activity 中,您可以通过执行以下操作来获取它:

getResources().getStringArray(R.array.drawables_list);

I guess the reflection code will work but I don't understand why you need this.

Resources in Android are static once the application is installed so you can have a list of resources or an array. Something like:

<string-array name="drawables_list">
    <item>drawable1</item>
    <item>drawable2</item>
    <item>drawable3</item>
</string-array>

And from your Activity you can get it by doing:

getResources().getStringArray(R.array.drawables_list);
撩人痒 2024-09-15 19:27:23

只需这样做:

Field[] declaredFields = (R.drawable.class).getDeclaredFields();

Just do this:

Field[] declaredFields = (R.drawable.class).getDeclaredFields();
夏夜暖风 2024-09-15 19:27:23

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;
}

The OP wanted drawables and I needed layouts. This is what I came up with for layouts. The name.startsWith business lets me ignore system generated layouts, so you may need to tweak that a bit. This should work for any resource type by modifying the value of 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;
}
醉生梦死 2024-09-15 19:27:23

可能的 Kotlin + Jetpack Compose 解决方案如下所示。请注意,这也仅过滤包含名称“icon”的可绘制对象,但也可以忽略过滤器:

val iconResourceIds = R.drawable::class.java.fields.filter { it.name.contains("icon") }.map {
    LocalContext.current.resources.getIdentifier(it.name, "drawable", LocalContext.current.packageName)
}

然后可以使用其资源名称和 DP 大小绘制所有图标,如下所示:

LazyVerticalGrid(
    modifier = Modifier.background(Color.White),
    columns = GridCells.Adaptive(minSize = 100.dp),
    contentPadding = PaddingValues(18.dp),
    verticalArrangement = Arrangement.spacedBy(32.dp),
    horizontalArrangement = Arrangement.spacedBy(18.dp),
) {
    items(iconResourceIds) { iconResourceId ->
        Column(horizontalAlignment = Alignment.CenterHorizontally) {
            val painter = painterResource(id = iconResourceId)
            Icon(
                painter = painter,
                contentDescription = null,
                tint = Color.Black
            )
            val name = LocalContext.current.resources.getResourceEntryName(iconResourceId)
            Text(
                text = name,
                color = Color.Black,
                textAlign = TextAlign.Center,
            )
            val widthDp = with(LocalDensity.current) { painter.intrinsicSize.width.toDp() }.value.roundToInt().toString()
            val heightDp = with(LocalDensity.current) { painter.intrinsicSize.height.toDp() }.value.roundToInt().toString()
            Text(
                text = "$widthDp x $heightDp",
                color = Color.Black,
                textAlign = TextAlign.Center,
            )
        }
    }
}

A possible Kotlin + Jetpack Compose solution would look like this. Note that this one also filters only the drawable that contain the name "icon" but one can also just leave away the filter:

val iconResourceIds = R.drawable::class.java.fields.filter { it.name.contains("icon") }.map {
    LocalContext.current.resources.getIdentifier(it.name, "drawable", LocalContext.current.packageName)
}

One can then draw all icons with their resource names and DP sizes like this:

LazyVerticalGrid(
    modifier = Modifier.background(Color.White),
    columns = GridCells.Adaptive(minSize = 100.dp),
    contentPadding = PaddingValues(18.dp),
    verticalArrangement = Arrangement.spacedBy(32.dp),
    horizontalArrangement = Arrangement.spacedBy(18.dp),
) {
    items(iconResourceIds) { iconResourceId ->
        Column(horizontalAlignment = Alignment.CenterHorizontally) {
            val painter = painterResource(id = iconResourceId)
            Icon(
                painter = painter,
                contentDescription = null,
                tint = Color.Black
            )
            val name = LocalContext.current.resources.getResourceEntryName(iconResourceId)
            Text(
                text = name,
                color = Color.Black,
                textAlign = TextAlign.Center,
            )
            val widthDp = with(LocalDensity.current) { painter.intrinsicSize.width.toDp() }.value.roundToInt().toString()
            val heightDp = with(LocalDensity.current) { painter.intrinsicSize.height.toDp() }.value.roundToInt().toString()
            Text(
                text = "$widthDp x $heightDp",
                color = Color.Black,
                textAlign = TextAlign.Center,
            )
        }
    }
}
阳光的暖冬 2024-09-15 19:27:23

使用我的代码

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());
    }
}

USE THIS MY CODE

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());
    }
}
久伴你 2024-09-15 19:27:23

要在 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
            )
        }
    }

To create an array of drawables in 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
            )
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文