【问题标题】:Android - Keep aspect ratio on background image on default ButtonAndroid - 在默认按钮上保持背景图像的纵横比
【发布时间】:2012-10-31 12:46:42
【问题描述】:

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

我尝试了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 作为背景,但无论如何这也会被拉伸。

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

【问题讨论】:

  • 图片的分辨率(以像素为单位)是多少?你也想要Button 的默认背景吗?
  • @Gagan 根据我的尝试,这取决于 40x30 到 256x256 像素之间的几个。是的。
  • 一般Buttons 的宽度不同,但高度保持不变。所以要保持图像的纵横比不变是相当困难的。
  • @Gagan 好吧,ImageButton 可以完成上述所有操作,包括缩放和保持纵横比,但我不能在这些上应用文本。我现在正在尝试是否可以将文本绘制到画布上并使其成为 ImageButtons

标签: android button background aspect-ratio


【解决方案1】:

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

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

我的解决方案采用了不同的方法,因为如果我们可以提供与View 具有相同纵横比的背景图像,就不会出现失真。

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

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) 您的 View 在您的布局 xml 中由 myView 标识,并且 (b) 您的背景图像是文件 res/drawable/background.png,请执行以下操作:

  1. 将您的Activity 声明为View.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;
    
        }
    
    }
    

【讨论】:

  • 这对我有用,但结果确实是像素化的。不过代码不错。
  • 很高兴知道;似乎 createScaledBitmap 在使用时有利于速度而不是质量。 (在我的测试中,我没有注意到像素化;可能是因为我当时使用的是高分辨率图像?)无论如何,您可能希望将过滤器参数更改为 true,看看它是否会改善您的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
  • 1970-01-01
  • 2011-06-07
相关资源
最近更新 更多