Android:アスペクト比を維持しながら画像を画面の幅に拡大する方法は?


118

画像(サイズは不明ですが、常にほぼ正方形)をダウンロードして、水平方向に画面いっぱいに表示され、垂直方向に拡大されて、どの画面サイズでも画像の縦横比を維持するように表示したいと思います。これが私の(動作しない)コードです。画像を水平方向に引き伸ばしますが、垂直方向には引き伸ばさないため、押しつぶされます...

ImageView mainImageView = new ImageView(context);
    mainImageView.setImageBitmap(mainImage); //downloaded from server
    mainImageView.setScaleType(ScaleType.FIT_XY);
    //mainImageView.setAdjustViewBounds(true); 
    //with this line enabled, just scales image down
    addView(mainImageView,new LinearLayout.LayoutParams( 
            LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

すべてのAndroidデバイスの幅と高さの比率はまったく同じですか?そうでない場合、元の比率を維持しながら画像を幅/高さ全体に合わせて拡大縮小することは単に不可能です...
NoozNooz42

4
いいえ、画像が画面全体に表示されるのではなく、画面の幅に合わせて拡大縮小されます。画像が適切な比率である限り、画像が垂直方向に占める画面の大きさは気にしません。
フレドリー

1
同様の質問、良い答え:stackoverflow.com/questions/4677269/...
PēterisCaune

1
「adjustViewBounds」は機能しませんでしたか?
ダーパン2015年

回答:


132

これをカスタムビューで実現しました。layout_width = "fill_parent"とlayout_height = "wrap_content"を設定し、適切なドローアブルを指定します。

public class Banner extends View {

  private final Drawable logo;

  public Banner(Context context) {
    super(context);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  public Banner(Context context, AttributeSet attrs) {
    super(context, attrs);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  public Banner(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    logo = context.getResources().getDrawable(R.drawable.banner);
    setBackgroundDrawable(logo);
  }

  @Override protected void onMeasure(int widthMeasureSpec,
      int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = width * logo.getIntrinsicHeight() / logo.getIntrinsicWidth();
    setMeasuredDimension(width, height);
  }
}

12
ありがとうございました!!これが正解です!:)私はこの投稿で少し柔軟性を高めるためにこれを調整しました:stackoverflow.com/questions/4677269/…ここでImageViewを使用して、XMLでドローアブルを設定したり、コードで通常のImageViewのように使用して画像を設定したりできます。よく働く!
Patrick Boos、2011年

1
フレキンの天才!それはチャンピオンのように機能しました!おかげで、すべての画面サイズで正しくない上部の画像バナーの問題が解決しました!どうもありがとうございます!
JPM 2011

1
ロゴがnullであることに注意してください(インターネットからコンテンツをダウンロードしている場合)。それ以外の場合、これはうまく機能します。XMLスニペットについてはPatrickの投稿に従ってください。
Artem Russakovskii

44
iOSとWindows Phoneで簡単にできることをAndroidで行うのがどれほど難しいかは信じられません。
mxcl 2012年

1
いくつか変更を加えましたが、他の場所に投稿する代わりに、この回答をコミュニティWikiに変えることはできますか?私の変更点はすべて、ここで説明した特殊なケースを処理するものであり、レイアウト定義によってどちらの側をサイズ変更するかを選択する機能です。
スティーブポメロイ

24

最後に、手動で寸法を生成しました。

DisplayMetrics dm = new DisplayMetrics();
context.getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = width * mainImage.getHeight() / mainImage.getWidth(); //mainImage is the Bitmap I'm drawing
addView(mainImageView,new LinearLayout.LayoutParams( 
        width, height));

私はこの種の問題を解決するためのこのような解決策を探していました。この計算の助けを借りて、アスペクト比を低下させることなく画像を正常にロードしました。
スティーブ

21

私はソースコードを読んだだけで、ImageViewこのスレッドでサブクラス化ソリューションを使用しないと基本的に不可能です。ではImageView.onMeasure、私たちは、これらの行を取得します:

        // Get the max possible width given our constraints
        widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);

        // Get the max possible height given our constraints
        heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);

ここで、hとは、w画像の大きさであり、p*パディングです。

その後:

private int resolveAdjustedSize(int desiredSize, int maxSize,
                               int measureSpec) {
    ...
    switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            /* Parent says we can be as big as we want. Just don't be larger
               than max size imposed on ourselves.
            */
            result = Math.min(desiredSize, maxSize);

つまり、layout_height="wrap_content"設定されている場合widthSize = w + pleft + pright、つまり、最大幅は画像の幅と同じになります。

つまり、正確なサイズを設定ない限り、画像は決して拡大されません。私はこれをバグだと考えていますが、Googleに知らせて修正してもらうように頑張ってください。編集:自分の言葉を食べて、バグレポートを提出しましが、将来のリリースで修正されると言われています!

別の解決策

ここにサブクラス化された別の回避策がありますが、(理論的には、実際にはあまりテストしていません!)どこでも使用できるようにする必要がありますImageView。それを使用するにはlayout_width="match_parent"、セット、およびlayout_height="wrap_content"。これも、受け入れられているソリューションよりもかなり一般的です。たとえば、高さに合わせるだけでなく幅に合わせることができます。

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

// This works around the issue described here: http://stackoverflow.com/a/12675430/265521
public class StretchyImageView extends ImageView
{

    public StretchyImageView(Context context)
    {
        super(context);
    }

    public StretchyImageView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public StretchyImageView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        // Call super() so that resolveUri() is called.
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // If there's no drawable we can just use the result from super.
        if (getDrawable() == null)
            return;

        final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);

        int w = getDrawable().getIntrinsicWidth();
        int h = getDrawable().getIntrinsicHeight();
        if (w <= 0)
            w = 1;
        if (h <= 0)
            h = 1;

        // Desired aspect ratio of the view's contents (not including padding)
        float desiredAspect = (float) w / (float) h;

        // We are allowed to change the view's width
        boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;

        // We are allowed to change the view's height
        boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

        int pleft = getPaddingLeft();
        int pright = getPaddingRight();
        int ptop = getPaddingTop();
        int pbottom = getPaddingBottom();

        // Get the sizes that ImageView decided on.
        int widthSize = getMeasuredWidth();
        int heightSize = getMeasuredHeight();

        if (resizeWidth && !resizeHeight)
        {
            // Resize the width to the height, maintaining aspect ratio.
            int newWidth = (int) (desiredAspect * (heightSize - ptop - pbottom)) + pleft + pright;
            setMeasuredDimension(newWidth, heightSize);
        }
        else if (resizeHeight && !resizeWidth)
        {
            int newHeight = (int) ((widthSize - pleft - pright) / desiredAspect) + ptop + pbottom;
            setMeasuredDimension(widthSize, newHeight);
        }
    }
}

バグレポートを提出しまし。無視されるので注意してください!
Timmmm

3
どうやら私は私の言葉を食べる必要があります-彼らはそれが将来のリリースで修正されたと言います!
Timmmm

ティムさん、ありがとうございました。これが最後の正解です。私は多くの時間を検索してきましたが、あなたの解決策に勝るものはありません。
tainy

上記のStretchyImageViewを使用するときにmaxHeightを設定する必要がある場合 その解決策は見つかりませんでした。
2015年

17

adjustViewBoundsをtrueに設定し、LinearLayoutビューグループを使用すると非常にうまくいきました。サブクラス化したり、デバイスメトリックを要求したりする必要はありません。

//NOTE: "this" is a subclass of LinearLayout
ImageView splashImageView = new ImageView(context);
splashImageView.setImageResource(R.drawable.splash);
splashImageView.setAdjustViewBounds(true);
addView(splashImageView);

1
...またはImageView XMLプロパティを使用-android:adjustViewBounds = "true"
Anatoliy

パーフェクト!これはとても簡単で、画像を完璧に引き伸ばしました。この答えは正しいものではありませんか?CustomViewでの回答が
うまくいき

13

私はエージのためにこの問題に何らかの形で苦労してきました、ありがとう、ありがとう、ありがとう.... :)

Viewを拡張してonMeasureをオーバーライドするだけで、Bob Leeが行ったことから一般化可能なソリューションを取得できることを指摘したかっただけです。そうすれば、これを任意のドローアブルで使用でき、画像がない場合でも中断しません。

    public class CardImageView extends View {
        public CardImageView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        public CardImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public CardImageView(Context context) {
            super(context);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            Drawable bg = getBackground();
            if (bg != null) {
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = width * bg.getIntrinsicHeight() / bg.getIntrinsicWidth();
                setMeasuredDimension(width,height);
            }
            else {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    }

2
この問題に対する多くの多くの解決策のうち、これは最初の解決策であり、ドロップインソリューションであり、他の解決策には常に欠点があります(コードを書き直さないと実行時にイメージを変更できないなど)。ありがとうございました!
MacD 2013年

これは純粋な素晴らしさです-しばらくの間これに苦労してきており、xml属性を使用するすべての明らかな解決策は機能しませんでした。これで、ImageViewを拡張ビューに置き換えるだけで、すべてが期待どおりに機能しました。
スロット2013

これは、この問題の絶対に最善の解決策です。
erlando 2013年

それは素晴らしい答えです。次のように心配することなく、このクラスをxmlファイルで使用できます:<com.yourpackagename.CardImageView android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:background = "@ drawable / your_photo" />。すごい!
arniotaki 14

11

場合によっては、この魔法の数式が問題を美しく解決します。

別のプラットフォームから来るこれに苦労している人のために、「フィットするサイズと形状」オプションはAndroidで美しく処理されますが、見つけるのは困難です。

通常、この組み合わせが必要です。

  • 幅は親に一致し、
  • 高さラップコンテンツ
  • adjustViewBoundsがオンになりました(シック)
  • スケールフィットセンター
  • cropToPadding OFF(シック)

その後、それは自動的で驚くべきことです。

あなたがiOS開発者であれば、Androidで「完全に動的なセルの高さ」をテーブルビューで簡単に実行できることは驚くべきことです。エラー、つまりListViewです。楽しい。

<com.parse.ParseImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/post_image"
    android:src="@drawable/icon_192"
    android:layout_margin="0dp"
    android:cropToPadding="false"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:background="#eff2eb"/>

ここに画像の説明を入力してください


6

私はこのXMLコードのみを使用してこれを達成することができました。Eclipseが高さをレンダリングしてフィットして拡大することを表示しない場合があります。ただし、これをデバイスで実際に実行すると、適切にレンダリングされ、目的の結果が得られます。(少なくとも私にとっては)

<FrameLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content">

     <ImageView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:adjustViewBounds="true"
          android:scaleType="centerCrop"
          android:src="@drawable/whatever" />
</FrameLayout>

申し訳ありませんが、これは機能しません。幅は調整されますが、centerCropは縦横比を維持しません。
ricosrealm 2014

1
(多くの回答や記事に記載されているように)ImageViewを拡張するカスタムクラスに苦労し、「次のクラスが見つかりませんでした」などの例外が発生した後、そのコードを削除しました。突然、ImageViewの問題が背景属性にあることに気付きました!それをに変更するsrcと、ImageViewが比例します。
CoolMind 2016

5

LinearLayout内でこれらの値を使用してそれを行いました:

Scale type: fitStart
Layout gravity: fill_horizontal
Layout height: wrap_content
Layout weight: 1
Layout width: fill_parent

実際の例を挙げていただけますか?これらの値をxmlファイルのどこに配置すればよいですか?
ジョンスミスオプション

5

誰もがこのプログラムをやっているので、この答えはここにぴったり合うと思いました。このコードは、私のXMLで動作しました。私はまだ比率について考えていませんが、それが誰かを助けるならこの答えを置きたかったです。

android:adjustViewBounds="true"

乾杯..


3

非常に単純な解決策は、が提供する機能を使用することですRelativeLayout

標準のAndroidでこれを可能にするxmlは次のViewsとおりです。

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true">

    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
        <LinearLayout
            android:id="@+id/button_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_alignParentBottom="true"
            >
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <Button
                android:text="button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
        </LinearLayout>
        <ImageView 
            android:src="@drawable/cat"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:scaleType="centerCrop"
            android:layout_above="@id/button_container"/>
    </RelativeLayout>
</ScrollView>

トリックはImageView、画面いっぱいにを設定することですが、他のレイアウトの上にある必要があります。このようにして、必要なすべてを実現します。


2

設定adjustViewBounds="true"scaleType="fitCenter"ImageViewのXMLファイルでの簡単な問題!

<ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/image"

        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        />

注:layout_widthに設定されていますmatch_parent


1

ScaleTypeをScaleType.FIT_XYに設定しています。javadocsによると、これにより画像が領域全体に収まるように拡大され、必要に応じてアスペクト比が変更されます。それはあなたが見ている行動を説明するでしょう。

希望する動作を得るには... FIT_CENTER、FIT_START、またはFIT_ENDは近くにありますが、画像が高さより狭い場合、幅いっぱいになりません。しかし、それらがどのように実装されているかを見ることができ、おそらく目的に合わせて調整する方法を理解できるはずです。


2
私はFIT_CENTERを試しましたが、他のものは試しませんでした。残念ながら、どちらもsetAdjustViewBoundsをtrueおよびfalseに設定しても機能しません。デバイスの画面のピクセル幅、ダウンロードした画像の幅/高さを取得して手動でサイズを設定する方法はありますか?
フレドリー

1

ScaleType.CENTER_CROPは、あなたが望むことを行います:全幅にストレッチし、それに応じて高さをスケーリングします。スケーリングされた高さが画面の制限を超えると、画像がトリミングされます。


1

あなたの問題のはるかに簡単な解決策があるのを見てください:

ImageView imageView;

protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_layout);
    imageView =(ImageView)findViewById(R.id.your_imageView);
    Bitmap imageBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.your_image);
    Point screenSize = new Point();
    getWindowManager().getDefaultDisplay().getSize(screenSize);
    Bitmap temp = Bitmap.createBitmap(screenSize.x, screenSize.x, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(temp);
    canvas.drawBitmap(imageBitmap,null, new Rect(0,0,screenSize.x,screenSize.x), null);
    imageView.setImageBitmap(temp);
}

1

ドローアブルの幅と高さに応じて(幅または高さによって)縦横比を維持したStretchableImageViewを使用できます。

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;

public class StretchableImageView extends ImageView{

    public StretchableImageView(Context context) {
        super(context);
    }

    public StretchableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public StretchableImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if(getDrawable()!=null){
            if(getDrawable().getIntrinsicWidth()>=getDrawable().getIntrinsicHeight()){
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = width * getDrawable().getIntrinsicHeight()
                            / getDrawable().getIntrinsicWidth();
                setMeasuredDimension(width, height);
            }else{
                int height = MeasureSpec.getSize(heightMeasureSpec);
                int width = height * getDrawable().getIntrinsicWidth()
                            / getDrawable().getIntrinsicHeight();
                setMeasuredDimension(width, height);
            }
        }
    }
}

0

私にとってandroid:scaleType = "centerCrop"は私の問題を解決しませんでした。実際に画像をさらに拡大しました。だから私はandroid:scaleType = "fitXY"を試してみましたが、うまくいきました。


0

これは私の要件に従って正常に動作しています

<ImageView android:id="@+id/imgIssue" android:layout_width="fill_parent" android:layout_height="wrap_content" android:adjustViewBounds="true" android:scaleType="fitXY"/>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.