web-dev-qa-db-ja.com

サイズ変更されないフルスクリーンの背景画像(中央の切り抜きあり)を作成する方法

写真をActivityの背景として設定しようとしています。背景を フルスクリーン画像(境界線なし) にします。

画像をストレッチ/スクイーズせずにアクティビティの背景全体に塗りつぶしたいので(つまり、XとYの不均衡なスケーリング)、写真をトリミングする必要があるかどうかは気にしないので、RelativeLayoutを使用しています。 ImageViewAndroid: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のサイズが変更されることです。ソフトキーボードが表示されているかどうかに関係なく、背景は同じままにしておきたいです。

私は たくさんの質問 on SO 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を作成し、それをルートビューの背景として設定するだけです。

18
user1987392

この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);
    }
}
7
pskink

答えの解決策は、それを使用するのに最適です:

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);

aPI16以降の場合。

1
Meanman

しばらく頭をかいた後、これは私の「今のところ良い」解決策でした。

誰にとっても役立つかもしれないサンプル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>

このレイアウトで、私は2つのことを達成します。

  • EditTextsなどを含む「フォーム」を含むformScrollViewは、ソフトキーボードが表示されたときにサイズが変更され(必要に応じて)スクロール可能になります。

  • ImageViewを含むbackgroundScrollViewは、サイズが変更されません( Android:isScrollContainer="false" )そしてビューポート全体を埋めます(Android:fillViewport="true")。したがって、キーボードが表示されているかどうかに関係なく、背景は同じままです。

ImageViewはサイズのばらつきが非常に小さいため、完全な解決策ではありませんが、今のところ結果は十分です。誰かがより良い解決策を知っているなら、私に知らせてください。

0
user1987392

すべてをFrameLayoutに配置し、最初の子でその親(frameLayout)に一致するimageviewを配置し、背景に合わせて構成し、画像ビューの前に必要なものを配置します(LinearLayoutだと思います)

0
Adnane.T

ScaleTypeを変更します

 Android:scaleType="FitXY"

そしてあなたのマニフェストで

<activity
           Android:name=".activity.MainActivity"
            Android:windowSoftInputMode="adjustPan|stateHidden" />
0
Kushal Ramola