1

有什么方法可以在作为背景应用时保持可绘制对象的纵横比Button(不能使用ImageButton(需要文本的可能性Button),不能使用setCompoundDrawables(),因为这也不符合我的要求(我做了我自己的类来支持添加背景,同时仍保留原始的android默认按钮,另外我需要在按钮中间设置背景,而不是左、右、顶部或底部))。

我尝试了一个解决方案ScaleDrawable,但要么我做错了,要么它不起作用:

Bitmap scaled = Bitmap.createScaledBitmap(original, (int)newBmpWidth, (int)newBmpHeight, false);
BitmapDrawable bd = new BitmapDrawable(scaled);
ScaleDrawable sd = new ScaleDrawable(bd, Gravity.CENTER, a, b);
//for a and b I tried lots of different values, ranging from 0.07f to 1000
sd.setLevel(1);

然后我使用ScaleDrawable作为背景,但无论如何它都会被拉伸。

我也试过了InsetDrawable,但同样,要么我做错了什么,要么它不起作用,期待第一个:

BitmapDrawable mBitmapDrawable = new BitmapDrawable(mBitmap);
InsetDrawable mInsetDrawable = new InsetDrawable(mBitmapDrawable, mLeftOffset, 0, mRightOffset, 0);

然后我使用InsetDrawable作为背景,但无论如何这也会被拉伸。

有什么方法可以应用背景但在 a 上保持纵横比Button我可以找到很多答案ImageButtons,但遗憾的是 aButton没有 a setImageBitmap()orsetScaleType()方法。

4

1 回答 1

1

我最近在设置背景图像时遇到了同样的问题ImageView。我提出的解决方案适用于 any View,因此它也应该涵盖Button

问题在于,无论作为背景提供的 Drawable 的缩放比例如何,它View总是将其背景拉伸到 ' 的宽度和高度的全部范围。View正如您关于未能提供专门的 Drawables 的报告所暗示的那样,这不能通过在将图像设置为背景之前缩放图像的任何方式来抵消,因为它View只会获取图像尺寸,无论它们是什么,然后再次独立缩放它们以View填充区域。

我的解决方案基于以下事实采用不同的方法:如果我们可以提供与View's 具有相同纵横比的背景图像,则不会出现失真。

下面的函数scaleKeepingAspect()采用图像资源并回答BitmapDrawable包含缩放到所需宽度和高度的原始图像的 a。缩放以保持原始图像的纵横比的方式执行,并且最终剩余的空间以适合所需的框被透明像素填充。原始图像在结果图像中居中。

private BitmapDrawable scaleKeepingAspect(Resources res, int id, int dstWidth, int dstHeight) {

    Bitmap b = (new BitmapFactory()).decodeResource(res, id);
    float scaleX = (float) dstWidth / b.getWidth();
    float scaleY = (float) dstHeight / b.getHeight();
    float scale = scaleX < scaleY ? scaleX : scaleY;
    int sclWidth = Math.round(scale * b.getWidth());
    int sclHeight = Math.round(scale * b.getHeight());
    b = Bitmap.createScaledBitmap(b, sclWidth, sclHeight, false);
    int[] pixels = new int[sclWidth * sclHeight];
    b.getPixels(pixels, 0, sclWidth, 0, 0, sclWidth, sclHeight);
    b = Bitmap.createBitmap(dstWidth, dstHeight, b.getConfig());
    b.setPixels(pixels, 0, sclWidth, (dstWidth - sclWidth) / 2, (dstHeight - sclHeight) / 2, sclWidth, sclHeight);
    return new BitmapDrawable(res, Bitmap.createBitmap(b));

}

scaleKeepingAspect()设置背景的适当位置是在布局更改事件期间,因此当由于布局处理View而更改的边界时,背景会正确更新。View为此,假设 (a) 您在布局 xml 中View被标识为myView,并且 (b) 您的背景图像是 file res/drawable/background.png,请执行以下操作:

  1. 将您声明ActivityView.OnLayoutChangeListener接口的实现者:

    public class MyActivity extends Activity implements View.OnLayoutChangeListener {
    
        ...
    
    }
    
  2. 将您注册Activity为侦听器以了解您的布局更改View

    @Override public void onCreate(Bundle savedInstanceState) {
    
        ...
    
        myView = (View) findViewById(R.id.myView);
        myView.addOnLayoutChangeListener(this);
    
        ...
    
    }
    
  3. 在布局更改处理程序中检测View布局更新,并在需要时更新其背景:

    @Override public void onLayoutChange (View v,
            int left, int top, int right, int bottom,
            int oldLeft, int oldTop, int oldRight, int oldBottom) {
    
        if (left == right || top == bottom || (
                left == oldLeft && top == oldTop &&
                right == oldRight && bottom == oldBottom))
            return;
    
        switch (v.getId()) {
    
            case R.id.myView:
    
                v.setBackground(
                    scaleKeepingAspect(
                        getResources(),
                        R.drawable.background,
                        v.getWidth(),
                        v.getHeight()));
                break;
    
        }
    
    }
    
于 2016-03-08T18:27:55.547 回答