如何使全屏背景图像(带有居中裁剪图)无法调整大小

我正在尝试将照片设置为.我希望背景是全屏图像(无边框)。Activity

由于我希望图像填充整个活动的背景而不拉伸/挤压(即X和Y的非比例缩放),并且我不介意是否必须裁剪照片,因此我使用的是带有(with)的a,并且我的布局的其余部分由a及其子级组成。RelativeLayoutImageViewandroid:scaleType="centerCrop"ScrollView

<!-- Tried this with a FrameLayout as well... -->
<RelativeLayout> 
   <!-- Background -->
   <ImageView  
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:scaleType="centerCrop"/>
   <!-- Form -->
   <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent">
      <ScrollView>
        <LinearLayout>
          ...
          <EditText/>
        </LinearLayout>
      </ScrollView>
   </LinearLayout>
</RelativeLayout>

问题在于布局的其余部分具有一些视图,当软键板出现时,ImageView会重新调整大小。我希望背景保持不变,无论软键板是否可见。EditText

我在SO上看到很多关于ImageViews被调整大小的问题,但(imo)没有令人满意的答案。它们中的大多数只是包括设置 - 这并不总是实用的,特别是如果您希望用户能够在活动中滚动 - 或者使用不会裁剪图像的内容。android:windowSoftInputMode="adjustPan"getWindow().setBackgroundDrawable()

我已经设法对ImageView进行了子类并覆盖了它(请参阅我的答案:ImageView在键盘打开时调整大小),以便它可以根据标志强制固定高度和宽度 - 等于设备的屏幕尺寸 - 但我想知道是否有更好的方法来实现我想要的结果。onMeasure()

因此,总而言之,我的问题是:如何将活动的背景设置为全屏照片。

  • 比例类型=“centerCrop”,使照片均匀缩放(保持其长宽比),因此两个尺寸(宽度和高度)将等于或大于视图的相应尺寸;

  • 当弹出软键板时不会调整大小;


答:

我最终听从了@pskink的建议,并进行了细分(见下面的答案)。我必须做一些调整,以确保始终以填充屏幕的方式缩放和裁剪。BitmapDrawableBackgroundBitmapDrawable

这是我的最后一堂课,改编自他的答案:

public class BackgroundBitmapDrawable extends BitmapDrawable {
    private Matrix mMatrix = new Matrix();
    private int moldHeight;
    boolean simpleMapping = false;

    public BackgroundBitmapDrawable(Resources res, Bitmap bitmap) {
        super(res, bitmap);
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        if (bounds.height() > moldHeight) {
            moldHeight = bounds.height();
            Bitmap b = getBitmap();
            RectF src = new RectF(0, 0, b.getWidth(), b.getHeight());
            RectF dst;

            if (simpleMapping) {
                dst = new RectF(bounds);
                mMatrix.setRectToRect(src, dst, ScaleToFit.CENTER);
            } else {
                // Full Screen Image -> Always scale and center-crop in order to fill the screen
                float dwidth = src.width();
                float dheight = src.height();

                float vwidth = bounds.width(); 
                float vheight = bounds.height();

                float scale;
                float dx = 0, dy = 0;

                if (dwidth * vheight > vwidth * dheight) {
                    scale = (float) vheight / (float) dheight; 
                    dx = (vwidth - dwidth * scale) * 0.5f;
                } else {
                    scale = (float) vwidth / (float) dwidth;
                    dy = (vheight - dheight * scale) * 0.5f;
                }

                mMatrix.setScale(scale, scale);
                mMatrix.postTranslate(dx, dy);

            }
        }
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawColor(0xaa00ff00);
        canvas.drawBitmap(getBitmap(), mMatrix, null);
    }
}

然后,只需创建一个并将其设置为根视图的背景即可。BackgroundBitmapDrawable


答案 1

试试这个分层可绘制(res/drawable/backlayer.xml):

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
>
    <item>
        <shape>
        <solid android:color="#f00" />
        </shape>
    </item>
<item>
        <bitmap
        android:gravity="top" android:src="@drawable/back1">
        </bitmap>
    </item>
</layer-list>

并将其设置为您的顶级布局:android:background=“@drawable/backlayer”

更新:试试这个BitmapDrawadle,将其设置为顶级布局(setBackgroundDrawable()),如果simpleMapping == true足够好,你可以删除“else”分支:

class D extends BitmapDrawable {
    private Matrix mMatrix = new Matrix();
    private int moldHeight;

    public D(Resources res, Bitmap bitmap) {
        super(res, bitmap);
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        if (bounds.height() > moldHeight) {
            moldHeight = bounds.height();
            Bitmap b = getBitmap();
            RectF src = new RectF(0, 0, b.getWidth(), b.getHeight());
            RectF dst;

            // if simpleMapping is good enough then remove "else" branch and
            // declare "dst" as:
            // RectF dst = new RectF(bounds);
            boolean simpleMapping = true;
            if (simpleMapping) {
                dst = new RectF(bounds);
            } else {
                float x = bounds.exactCenterX();
                dst = new RectF(x, 0, x, bounds.height());
                float scale = bounds.height() / src.height();
                float dx = scale * src.width() / 2;
                dst.inset(-dx, 0);
            }
            mMatrix.setRectToRect(src, dst, ScaleToFit.CENTER);
        }
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawColor(0xaa00ff00);
        canvas.drawBitmap(getBitmap(), mMatrix, null);
    }
}

答案 2

答案中的解决方案是最好的,使用它:

Resources res = getActivity().getResources();
Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.some_image);
BackgroundBitmapDrawable background = new BackgroundBitmapDrawable(res, bitmap);
view.setBackgroundDrawable(background);

view.setBackground(background);

对于 API 16 及更高版本。


推荐