簡體   English   中英

如何使用不調整大小的全屏背景圖像(帶中心裁剪)

[英]How to have a Fullscreen Background Image (with center-crop) that doesn't Resize

我正在嘗試將照片設置為Activity的背景。 我希望背景是一個全屏圖像(沒有邊框)

因為我希望圖像在沒有拉伸/擠壓的情況下填充整個活動的背景(即X和Y的不成比例的縮放),我不介意是否必須裁剪照片,我正在使用帶有ImageViewRelativeLayout (帶有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>

問題是布局的其余部分有一些EditText視圖,當軟鍵盤出現時,ImageView會重新調整大小。 我希望背景保持不變,無論軟鍵盤是否可見。

我已經看到很多關於ImageViews重新調整大小的問題但是(imo)沒有令人滿意的答案。 其中大多數只是設置android:windowSoftInputMode="adjustPan" - 這並不總是實用的,特別是如果你希望用戶能夠滾動活動 - 或使用getWindow().setBackgroundDrawable()不裁剪圖像。

我設法將ImageView子類化並覆蓋其onMeasure() (請參閱我的答案: ImageView在鍵盤打開時調整大小 )以便它可以強制固定的高度和寬度 - 等於設備的屏幕尺寸 - 根據標志但是我想知道是否有更好的方法來實現我想要的結果。

總而言之,我的問題是: 如何將活動的背景設置為全屏照片

  • 使用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並將其設置為根視圖的背景。

試試這個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);
    }
}

將所有內容放在FrameLayout中,第一個子圖像將與其父圖像(frameLayout)相匹配,並將其配置為您想要的背景,並在圖像視圖前放置您想要的任何內容(我猜想是LinearLayout)

抓了一會兒后,這是我的“現在好”的解決方案。

共享可能對任何人都有用的示例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某種程度上的尺寸變化非常小,但結果現在已經足夠好了。 如果有人知道更好的解決方案,請告訴我。

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

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及以上版本。

更改您的ScaleType

 android:scaleType="FitXY"

在你的清單中

<activity
           android:name=".activity.MainActivity"
            android:windowSoftInputMode="adjustPan|stateHidden" />

在xml中創建一個ImageView。 將它放在Layout標簽下面。 將translationZ設置為正值,例如10dp,將scaleType設置為centerCrop。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM