在 Android 中调整 Drawable 的大小

Posted

技术标签:

【中文标题】在 Android 中调整 Drawable 的大小【英文标题】:Resize Drawable in Android 【发布时间】:2011-10-24 16:40:56 【问题描述】:

我正在为进度对话框 (pbarDialog) 设置可绘制对象,但我的问题是我想每次都调整可绘制对象的大小,但不知道怎么做。

这里有一些代码:

Handler progressHandler = new Handler() 

    public void handleMessage(Message msg) 
        switch (msg.what) 
            // some more code
            case UPDATE_PBAR:
                pbarDialog.setIcon(mAppIcon);
                pbarDialog.setMessage(mPbarMsg);
                pbarDialog.incrementProgressBy(mIncrement+1);
                break;
        
    
;

pbarDialog.show();

Thread myThread = new Thread(new Runnable() 

    public void run() 
        // some code
        for (int i = 0; i < mApps.size(); i++) 
            mAppIcon = mAdapter.getIcons().get(mApps.get(i).getPackageName());
            // need to resize drawable here
            progressHandler.sendEmptyMessage(UPDATE_PBAR);
        
        handler.sendEmptyMessage(DISMISS_PBAR);
    

);

myThread.start();

【问题讨论】:

你必须调整哪个drawable的大小? 使用 Bitmap.createScaledBitmap(src, dstWidth, dstHeight, filter) 【参考方案1】:

以下内容对我有用:

private Drawable resize(Drawable image) 
    Bitmap b = ((BitmapDrawable)image).getBitmap();
    Bitmap bitmapResized = Bitmap.createScaledBitmap(b, 50, 50, false);
    return new BitmapDrawable(getResources(), bitmapResized);

【讨论】:

我在第一行代码出现了这个错误:java.lang.ClassCastException: android.graphics.drawable.PictureDrawable cannot be cast to android.graphics.drawable.BitmapDrawable 使用 Drawable 作为参数并将其转换为 BitmapDrawable !?如果您确定它始终是 BitmapDrawable,那么也将参数类型更改为 BitmapDrawable,如果不是,最好在转换之前检查可绘制类型。【参考方案2】:

这就是我结束的地方,部分感谢 Saad 的回答:

public Drawable scaleImage (Drawable image, float scaleFactor) 

    if ((image == null) || !(image instanceof BitmapDrawable)) 
        return image;
    

    Bitmap b = ((BitmapDrawable)image).getBitmap();

    int sizeX = Math.round(image.getIntrinsicWidth() * scaleFactor);
    int sizeY = Math.round(image.getIntrinsicHeight() * scaleFactor);

    Bitmap bitmapResized = Bitmap.createScaledBitmap(b, sizeX, sizeY, false);

    image = new BitmapDrawable(getResources(), bitmapResized);

    return image;


【讨论】:

完美,这就是我走的路。 不错的编码。正是我需要的。谢谢你,兄弟:) 注意这一点:以前的可绘制“图像”包含尚未回收的位图。调用“image = scaleImage(image, 2)”会导致临时泄漏。因此 scaleImage 的调用者有责任回收原始图像和缩放后的图像......这在小型应用程序中可能不是问题,但它是在内存密集型应用中至关重要。 @JMLord 好点,更多内容在这里:developer.android.com/training/displaying-bitmaps/… 任何可以避免内存泄漏的解决方案或替代方案【参考方案3】:

对于调整大小,这很好而且很短(上面的代码对我不起作用),找到here:

  ImageView iv = (ImageView) findViewById(R.id.imageView);
  Bitmap bMap = BitmapFactory.decodeResource(getResources(), R.drawable.picture);
  Bitmap bMapScaled = Bitmap.createScaledBitmap(bMap, newWidth, newHeight, true);
  iv.setImageBitmap(bMapScaled);

【讨论】:

这适用于我想在将 Drawable 设置为 imageBitmap 到 ImageView 之前调整它的大小。谢谢【参考方案4】:

这是上述答案的组合作为 Kotlin 扩展

fun Context.scaledDrawableResources(@DrawableRes id: Int, @DimenRes width: Int, @DimenRes height: Int): Drawable 
    val w = resources.getDimension(width).toInt()
    val h = resources.getDimension(height).toInt()
    return scaledDrawable(id, w, h)


fun Context.scaledDrawable(@DrawableRes id: Int, width: Int, height: Int): Drawable 
    val bmp = BitmapFactory.decodeResource(resources, id)
    val bmpScaled = Bitmap.createScaledBitmap(bmp, width, height, false)
    return BitmapDrawable(resources, bmpScaled)

用法:

val scaled = context.scaledDrawableResources(R.drawable.ic_whatever, R.dimen.width, R.dimen.height)
imageView.setImageDrawable(scaled)

val scaled = context.scaledDrawable(R.drawable.ic_whatever, 100, 50)
imageView.setImageDrawable(scaled)

【讨论】:

这一款非常适合 Kotliner 同胞!【参考方案5】:

也许我的解决方案没有完全涵盖这个问题,但我需要类似“CustomDrawable”的东西。

换句话说,我想在圆形前面设置一个标志。所以我创建了一个带有背景(只是一个彩色圆圈)的 FrameLayout,并在这个圆形的前面显示了徽标。

要调整徽标的大小,我通过缩放来缩小徽标 - 这是一些代码:

iv = new ImageView(mContext);

iv.setScaleX(0.75f); // <- resized by scaling 
iv.setScaleY(0.75f);

// loading the drawable from a getter (replace this with any drawable)
Drawable drawable = ML.loadIcon(mContext, Integer.parseInt(icon));

iv.setImageDrawable(drawable);

// icon get's shown inside a ListView
viewHolder.mIvIcon.addView(iv);

这是在 ListView 行内显示图标的 FrameLayout:

<FrameLayout
    android:id="@+id/iv_card_icon"
    android:layout_
    android:layout_
    android:src="@drawable/circle"
    android:layout_marginStart="16dp"
    />

将此解决方案视为一种选择/想法。

【讨论】:

【参考方案6】:

如果源 Drawable 不是 instanceof BitmapDrawable,那么投票最多的答案将不起作用,这可能是使用矢量、颜色可绘制对象等的情况......

最合适的解决方案是把 Drawable 绘制到一个带有 set bitmap 的 Canvas 中,如下:

@NonNull final Drawable drawable = yourSourceDrawable;

// Define the Canvas and Bitmap the drawable will be drawn against
final Canvas c = new Canvas();
c.setBitmap(bitmap);

// Draw the scaled drawable into the final bitmap
if (yourSourceDrawable!= null) 
    yourSourceDrawable.setBounds(0, 0, newWidth, newHeight);
    yourSourceDrawable.draw(c);

奖励:计算要应用的比例(例如,将 Drawable 缩放到视图时):

if (drawable != null && drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) 
    // the intrinsic dimensions can be -1 in some cases such as ColorDrawables which aim to fill 
    // the whole View
    previewWidth = drawable.getIntrinsicWidth();
    previewHeight = drawable.getIntrinsicHeight();


final float widthScale = mViewWidth / (float) (previewWidth);
if (widthScale != 1f)
    newWidth = Math.max((int)(widthScale * previewWidth), 1);

final float heightScale = mViewHeight / (float) (previewHeight);
if (heightScale != 1f)
    newHeight = Math.max((int)(heightScale * previewHeight), 1);

注意:始终在工作线程中执行此操作!

【讨论】:

【参考方案7】:

科特林方式

最终对我有用的是这个简单的解决方案

fun resizeDrawable(width:Int, height:Int): Drawable 
        val drawable = ResourceUtils.getDrawable(R.drawable.ic_info)
        val bitmap = drawable.toBitmap(width, height) //here width and height are in px
        return bitmap.toDrawable(getResources())
    

【讨论】:

以上是关于在 Android 中调整 Drawable 的大小的主要内容,如果未能解决你的问题,请参考以下文章

需要调整 Android ImageView 的大小以匹配不断变化的 Drawable 大小

如何使用默认的 Android 可绘制对象

Textview drawable 不在远程视图中显示可绘制图像

求问Android高手,分辨率怎么设置

Android中的Drawable资源

Android中的Drawable资源