以编程方式设置可绘制对象的大小

107

这些图片(图标)大致相同大小,但我需要调整它们的大小,以便按钮保持相同的高度。

我该怎么做?

Button button = new Button(this);
button.setText(apiEventObject.getTitle());
button.setOnClickListener(listener);

/*
 * set clickable id of button to actual event id
 */
int id = Integer.parseInt(apiEventObject.getId());
button.setId(id);

button.setLayoutParams(new LayoutParams(
        android.view.ViewGroup.LayoutParams.FILL_PARENT,
        android.view.ViewGroup.LayoutParams.WRAP_CONTENT));

Drawable drawable = LoadImageFromWebOperations(apiSizeObject.getSmall());
//?resize drawable here? drawable.setBounds(50, 50, 50, 50);
button.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);

你找到了如何调整可绘制对象(位图)大小的方法了吗? - Zelimir
2
早已过期,但是想知道为什么您没有调用 setCompoundDrawables() ? “Intrinsic” 在 Android 中的其他位置中指的是原始图像大小,例如 Drawable.getIntrinsicHeight() - William T. Mallard
16个回答

177

setBounds() 方法并不适用于每种类型的容器(虽然在某些 ImageView 上有效)。

尝试使用以下方法来缩放可绘制对象本身:

// Read your drawable from somewhere
Drawable dr = getResources().getDrawable(R.drawable.somedrawable);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
// Scale it to 50 x 50
Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, 50, 50, true));
// Set your new, scaled drawable "d"

对我来说,这里的问题是它在可绘制图像周围绘制了一个白色矩形。 - noloman
8
BitmapDrawable(Bitmap) 构造函数已被弃用。请使用:Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, 50, 50, true)); - Andy
2
当放大可绘制对象时,这将导致像素化。即使它们是矢量可绘制对象。 - Sanket Berde
1
你可能想使用 ContextCompat.getDrawable(context, resourceid) - Pierre
顺便提一下,您可以通过编程方式创建StateListDrawable并使用addState方法与“转换后的可绘制对象”一起使用,以使其适用于在setPasswordVisibilityToggleDrawable中使用的selector's item大小。 - 林果皞
1
将Drawable转换为BitmapDrawable会在Android 10、9和8上引发转换异常。但在Android 5上不会引发异常。我没有在6和7上尝试过。 - Ashraf Alshahawy

34

使用setBounds()指定尺寸,例如使用50x50的大小:

drawable.setBounds(0, 0, 50, 50);

public void setBounds (int left, int top, int right, int bottom)


该方法用于设置对象的边界,需要传入左侧、顶部、右侧和底部四个参数。

2
设置边界后大小仍然保持不变。可能需要一些无效化吗? - Kostadin
11
实际上,setBounds适用于GradientDrawables。它只是不适用于Image Drawables。 - gregm
当我将图像放入按钮中时,它对我有效,但是当我将其放入ImageView中时则否。原帖作者使用了一个按钮,但也调用了setCompoundDrawables()函数的内在特性。 - William T. Mallard
有趣的是,您还可以使用setSize()为GradientDrawable设置大小。 - 6rchid

15

我没时间深究为什么setBounds()方法在位图可绘制对象上没有像预期那样工作,但我稍微修改了@androbean-studio的解决方案来实现setBounds应该做的事情...

/**
 * Created by ceph3us on 23.05.17.
 * file belong to pl.ceph3us.base.android.drawables
 * this class wraps drawable and forwards draw canvas
 * on it wrapped instance by using its defined bounds
 */
public class WrappedDrawable extends Drawable {

    private final Drawable _drawable;
    protected Drawable getDrawable() {
        return _drawable;
    }

    public WrappedDrawable(Drawable drawable) {
        super();
        _drawable = drawable;
    }

    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        //update bounds to get correctly
        super.setBounds(left, top, right, bottom);
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.setBounds(left, top, right, bottom);
        }
    }

    @Override
    public void setAlpha(int alpha) {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.setAlpha(alpha);
        }
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.setColorFilter(colorFilter);
        }
    }

    @Override
    public int getOpacity() {
        Drawable drawable = getDrawable();
        return drawable != null
                ? drawable.getOpacity()
                : PixelFormat.UNKNOWN;
    }

    @Override
    public void draw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable != null) {
            drawable.draw(canvas);
        }
    }

    @Override
    public int getIntrinsicWidth() {
        Drawable drawable = getDrawable();
        return drawable != null
                ? drawable.getBounds().width()
                : 0;
    }

    @Override
    public int getIntrinsicHeight() {
        Drawable drawable = getDrawable();
        return drawable != null ?
                drawable.getBounds().height()
                : 0;
    }
}

使用方法:

// get huge drawable 
final Drawable drawable = resources.getDrawable(R.drawable.g_logo);
// create our wrapper           
WrappedDrawable wrappedDrawable = new WrappedDrawable(drawable);
// set bounds on wrapper 
wrappedDrawable.setBounds(0,0,32,32); 
// use wrapped drawable 
Button.setCompoundDrawablesWithIntrinsicBounds(wrappedDrawable ,null, null, null);

结果

之前:输入图像描述 之后:输入图像描述


如何添加左边距? - reegan29
1
我不知道它为什么能够工作,但它确实可以。这是唯一对我有效的解决方案。 - arenaq
1
这应该是被接受的答案。干杯 - Sahil Garg
1
@arenaq它之所以起作用是因为覆盖了固有的宽度和高度。这就是其他setBounds解决方案缺少的地方 - 如果设置边界而不覆盖宽度和高度,它仍然会被忽略。 - 0101100101
如果你要这样做,请使用androidx.appcompat.graphics.drawable.DrawableWrapperCompat的子类,并重写你需要的方法。其余的工作将会被很好地委托给你。 - TWiStErRob

14

在应用 .setBounds(..) 之前,尝试将当前的 Drawable 转换为 ScaleDrawable

drawable = new ScaleDrawable(drawable, 0, width, height).getDrawable();

之后

drawable.setBounds(0, 0, width, height);

会工作


3
为什么需要这一步?在ScaleDrawable中包装的作用是什么,相对于不包装有什么不同的选择? - azizbekian

9

使用方法:

textView.setCompoundDrawablesWithIntrinsicBounds()

您的build.gradle文件中minSdkVersion应该为17

    defaultConfig {
    applicationId "com.example..."
    minSdkVersion 17
    targetSdkVersion 25
    versionCode 1
    versionName "1.0"
}

更改可绘制对象的大小:

    TextView v = (TextView)findViewById(email);
    Drawable dr = getResources().getDrawable(R.drawable.signup_mail);
    Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
    Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, 80, 80, true));

    //setCompoundDrawablesWithIntrinsicBounds (image to left, top, right, bottom)
    v.setCompoundDrawablesWithIntrinsicBounds(d,null,null,null);

4

使用LayerDrawable已经解决了这个问题:

fun getResizedDrawable(drawable: Drawable, scale: Float) =
    LayerDrawable(arrayOf(drawable)).also { it.setLayerSize(0, (drawable.intrinsicWidth * scale).toInt(), (drawable.intrinsicHeight * scale).toInt()) }

fun getResizedDrawable(drawable: Drawable, scalex: Float, scaleY: Float) =
    LayerDrawable(arrayOf(drawable)).also { it.setLayerSize(0, (drawable.intrinsicWidth * scalex).toInt(), (drawable.intrinsicHeight * scaleY).toInt()) }

fun getResizedDrawableUsingSpecificSize(drawable: Drawable, newWidth: Int, newHeight: Int) =
    LayerDrawable(arrayOf(drawable)).also { it.setLayerSize(0, newWidth, newHeight) }

示例:

val drawable = AppCompatResources.getDrawable(this, android.R.drawable.sym_def_app_icon)!!
val resizedDrawable = getResizedDrawable(drawable, 3f)
textView.setCompoundDrawablesWithIntrinsicBounds(resizedDrawable, null, null, null)
imageView.setImageDrawable(resizedDrawable)

3

可能有点晚了。但这是最终在任何情况下都适用于我的解决方案。

思路是创建一个具有固定内置大小的自定义可绘制对象,并将绘图任务传递给原始可绘制对象。

Drawable icon = new ColorDrawable(){
        Drawable iconOrig = resolveInfo.loadIcon(packageManager);

        @Override
        public void setBounds(int left, int top, int right, int bottom){
            super.setBounds(left, top, right, bottom);//This is needed so that getBounds on this class would work correctly.
            iconOrig.setBounds(left, top, right, bottom);
        }

        @Override
        public void draw(Canvas canvas){
            iconOrig.draw(canvas);
        }

        @Override
        public int getIntrinsicWidth(){
            return  mPlatform.dp2px(30);
        }

        @Override
        public int getIntrinsicHeight(){
            return  mPlatform.dp2px(30);
        }
    };

什么是mPlatform? - batsheva
@batsheva 这只是他用来将 dp 转换为 px 的工具。 - android developer

3

虽然这个问题被问了很久,


但对于许多人来说,如何做到这一点仍然不清楚。

如果在TextView(Button)上使用Drawable作为复合Drawable,则非常简单。

所以你需要做2件事:

第1步:设置边界:

drawable.setBounds(left, top, right, bottom)

2. 适当设置可绘制对象(不使用固有边框):


button.setCompoundDrawablesRelative(drawable, null, null, null)
  • 无需使用位图。
  • 无需使用ScaleDrawable、ColorDrawable或LayerDrawable等绕过方法(它们明显是为其他目的而创建)。
  • 无需自定义可绘制对象!
  • 不需要通过post方法进行绕过。
  • 这是一种本地且简单的解决方案,正如Android所期望的那样。
最初的回答:
  • Use ImageView with android:src attribute.

如何缩放可绘制对象以匹配 TextView 的文本大小?应该使用什么边界来实现? - Ashwin

3
使用POST方法来实现所期望的效果:
{your view}.post(new Runnable()
    {
        @Override
        public void run()
        {
            Drawable image = context.getResources().getDrawable({drawable image resource id});
            image.setBounds(0, 0, {width amount in pixels}, {height amount in pixels});
            {your view}.setCompoundDrawables(image, null, null, null);
        }
    });

2
如果您正在使用Kotlin,可以为其创建一个扩展。
fun Drawable.resizeTo(context: Context, size: Int) =
    BitmapDrawable(context.resources, toBitmap(size, size))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接