18

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

因为我希望图像在不拉伸/挤压的情况下填充整个活动的背景(即 X 和 Y 的不成比例缩放)并且我不介意是否必须裁剪照片,所以我使用RelativeLayout带有ImageView(with android:scaleType="centerCrop") 和我的布局的其余部分由 aScrollView及其子项组成。

<!-- 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>

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

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

我已经设法将 ImageView 子类化并覆盖它onMeasure()(在此处查看我的答案:ImageView resized when keyboard open),以便它可以根据标志强制固定高度和宽度 - 等于设备的屏幕尺寸,但我是想知道是否有更好的方法来实现我想要的结果。

所以,总而言之,我的问题是:如何将 Activity 的背景设置为全屏照片

  • 使用 scale type = "centerCrop",使照片均匀缩放(保持其纵横比),因此两个尺寸(宽度和高度)将等于或大于视图的相应尺寸;

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


回答:

我最终遵循了@pskink的建议并进行了分类BitmapDrawable(请参阅下面的答案)。我必须进行一些调整以确保BackgroundBitmapDrawable始终以填充屏幕的方式缩放和裁剪。

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

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并将其设置为根视图的背景即可。

4

6 回答 6

7

试试这个 LayerDrawable (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);
    }
}
于 2014-02-16T18:02:27.730 回答
1

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

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 及更高版本。

于 2014-04-23T15:49:48.203 回答
0

将所有内容放在 FrameLayout 中,第一个子项是一个与其父级(frameLayout)匹配的图像视图,您可以根据需要对其进行配置,然后在图像视图前面放置您想要的任何内容(我想是线性布局)

于 2014-02-16T16:57:17.600 回答
0

在摸索了一段时间后,这一直是我的“现在很好”的解决方案。

分享一个对任何人都可能有用的示例 XML。

<!-- RelativeLayout so that Views can overlap each other.
     I believe a FrameLayout would work as well. -->
<RelativeLayout
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- I've put the ImageView inside 
         a ScrollView with android:fillViewport="true" and android:isScrollContainer="false" -->
    <ScrollView
        android:id="@+id/backgroundScrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        android:isScrollContainer="false" > 

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >

            <!-- The FullScreen, Center-Cropped Image Background --> 
            <ImageView
                android:id="@+id/backgroundImage"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@drawable/background_image" />
        </LinearLayout>
    </ScrollView>

    <!-- The rest of the Views, containing the data entry form... -->
    <LinearLayout
        android:id="@+id/form"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

            <ScrollView
                android:id="@+id/formScrollView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" >

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="1"
                    android:orientation="vertical" >

                    <!-- The "Form", with EditTexts, Checkboxes and whatnot... -->

                </LinearLayout>
            </ScrollView>

    </LinearLayout>
</RelativeLayout>

通过这种布局,我完成了两件事:

  • formScrollView,其中包含带有 EditTexts 等的“表单”,当软键盘出现时,它会重新调整大小(如我所愿)并且可滚动。

  • backgroundScrollView,其中包含 ImageView,不会重新调整大小(因为android:isScrollContainer="false")并填充整个视口(android:fillViewport="true")。因此,无论键盘是否可见,背景都保持不变。

不是一个完美的解决方案,因为ImageView它的大小变化很小,但结果现在已经足够好了。如果有人知道更好的解决方案,请告诉我。

于 2014-02-16T18:10:43.637 回答
-1

Change your ScaleType

 android:scaleType="FitXY"

and in your manifest

<activity
           android:name=".activity.MainActivity"
            android:windowSoftInputMode="adjustPan|stateHidden" />
于 2017-04-07T12:31:50.183 回答
-2

在您的 xml 中创建一个 ImageView。将其放在您的布局标签下方。将 translationZ 设置为正值,例如 10dp,将 scaleType 设置为 centerCrop。

于 2015-04-30T12:56:00.453 回答