如何使用不会调整大小的全屏背景图像(带中心裁剪)

时间:2014-02-16 15:47:08

标签: java android android-layout android-imageview background-drawable

我正在尝试将照片设为Activity的背景。我希望背景为a full screen image (no borders)

因为我希望图像能够在没有拉伸/挤压的情况下填充整个活动的背景(即X和Y的不成比例的缩放),我不介意是否必须裁剪照片,我正在使用{{1} } RelativeLayoutImageView),其余部分由android: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会重新调整大小。无论软键盘是否可见,我都希望背景保持不变。

我已经看到plenty of questions关于ImageViews重新调整大小但是(imo)没有令人满意的答案。其中大多数只是设置EditText - 这并不总是实用的,特别是如果您希望用户能够滚动活动 - 或者使用不会裁剪图像的android:windowSoftInputMode="adjustPan"

我设法对ImageView进行子类化并覆盖其getWindow().setBackgroundDrawable()(请参阅我的答案:ImageView resizes when keyboard open),以便它可以强制固定高度&amp; width - 等于设备的屏幕尺寸 - 根据标志,但我想知道是否有更好的方法来实现我想要的结果。

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

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

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


解答:

我最后关注了@pskink的建议,并将onMeasure()隐藏了(请参阅下面的回答)。我必须做一些调整,以确保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); } } 并将其设置为根视图的背景。

6 个答案:

答案 0 :(得分: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);
    }
}

答案 1 :(得分:0)

将所有内容放在FrameLayout中,第一个子视图将匹配它的父视图(frameLayout),然后根据需要配置背景,并在图像视图前放置您想要的任何内容(LinearLayout I)假设)

答案 2 :(得分: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在某种程度上会出现非常小的变化,但结果现在已经足够好了。如果有人知道更好的解决方案,请告诉我。

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

更改您的ScaleType

fn find_end(s: &str, i: usize) -> usize {
    i + s[i..].chars().next().unwrap().len_utf8()
}

并在你的清单中

 android:scaleType="FitXY"

答案 5 :(得分:-1)

在xml中创建一个ImageView。 将它放在Layout标签下面。 将translationZ设置为正值,例如10dp,将scaleType设置为centerCrop。