画像をImageViewに合わせ、アスペクト比を維持してから、ImageViewのサイズを画像のサイズに変更しますか?


164

ランダムなサイズの画像をどのように合わせるのImageViewですか?
いつ:

  • 最初のImageViewサイズは250 dp * 250 dp
  • 画像の大きい方のサイズを250 dpに拡大/縮小する必要があります
  • 画像は縦横比を維持する必要があります
  • ImageView寸法は、スケーリング後のスケーリングされた画像の大きさと一致している必要があり

たとえば、100 * 150の画像の場合、画像とはImageView166 * 250になります。
たとえば、150 * 100の画像の場合、画像とはImageView250 * 166になります。

境界を次のように設定した場合

<ImageView
    android:id="@+id/picture"
    android:layout_width="250dp"
    android:layout_height="250dp"
    android:layout_gravity="center_horizontal"
    android:layout_marginTop="20dp"
    android:adjustViewBounds="true" />

画像はに正しく収まりますImageViewが、ImageView常に250dp * 250dpです。


ええと、のサイズをImageView画像サイズに変更するつもりですか?たとえば、100dp x 150dpの画像はImageView同じ尺度にスケーリングされますか?または、画像をImageView境界に合わせて拡大縮小する方法を意味しますか?たとえば、1000dp x 875dpの画像は250dp x 250dpにスケーリングされます。アスペクト比を維持する必要がありますか?
ヤルノアルギランダー、

ImageViewに画像のサイズを設定し、画像の最大サイズを250dpにしてアスペクト比を維持したいと思います。たとえば、100 * 150の画像の場合、画像とImageViewを166 * 250にしたいと思います。質問を更新します。
7月

アクティビティを表示するとき(1回だけ)、またはギャラリー/ Webから画像を選択するなどのアクティビティで何かを実行するとき(何度も実行しますが、ロードではありません)、またはその両方でスケーリング/調整を実行しますか?
ヤルノアルギランダー

私が変更した回答を参照してください。これは、希望どおりに動作するはずです:)
Jarno Argillander '22

回答:


136

(元の質問を明確にした後、回答は大幅に変更されました)

明確化後:
これはxmlのみでは実行できません。画像との両方を拡大縮小することはできません。そのImageViewため、画像の1次元は常に250dpになり、ImageViewは画像と同じ次元になります。

このコード Drawableは、ImageView250dp x 250dpのような正方形にとどまり、1次元が正確に250dpでアスペクト比を維持するようにスケーリングします。次に、ImageViewスケーリングされた画像のサイズに合わせてサイズが変更されます。コードはアクティビティで使用されます。ボタンクリックハンドラーでテストしました。

楽しい。:)

private void scaleImage(ImageView view) throws NoSuchElementException  {
    // Get bitmap from the the ImageView.
    Bitmap bitmap = null;

    try {
        Drawable drawing = view.getDrawable();
        bitmap = ((BitmapDrawable) drawing).getBitmap();
    } catch (NullPointerException e) {
        throw new NoSuchElementException("No drawable on given view");
    } catch (ClassCastException e) {
        // Check bitmap is Ion drawable
        bitmap = Ion.with(view).getBitmap();
    }

    // Get current dimensions AND the desired bounding box
    int width = 0;

    try {
        width = bitmap.getWidth();
    } catch (NullPointerException e) {
        throw new NoSuchElementException("Can't find bitmap on given view/drawable");
    }

    int height = bitmap.getHeight();
    int bounding = dpToPx(250);
    Log.i("Test", "original width = " + Integer.toString(width));
    Log.i("Test", "original height = " + Integer.toString(height));
    Log.i("Test", "bounding = " + Integer.toString(bounding));

    // Determine how much to scale: the dimension requiring less scaling is
    // closer to the its side. This way the image always stays inside your
    // bounding box AND either x/y axis touches it.  
    float xScale = ((float) bounding) / width;
    float yScale = ((float) bounding) / height;
    float scale = (xScale <= yScale) ? xScale : yScale;
    Log.i("Test", "xScale = " + Float.toString(xScale));
    Log.i("Test", "yScale = " + Float.toString(yScale));
    Log.i("Test", "scale = " + Float.toString(scale));

    // Create a matrix for the scaling and add the scaling data
    Matrix matrix = new Matrix();
    matrix.postScale(scale, scale);

    // Create a new bitmap and convert it to a format understood by the ImageView 
    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    width = scaledBitmap.getWidth(); // re-use
    height = scaledBitmap.getHeight(); // re-use
    BitmapDrawable result = new BitmapDrawable(scaledBitmap);
    Log.i("Test", "scaled width = " + Integer.toString(width));
    Log.i("Test", "scaled height = " + Integer.toString(height));

    // Apply the scaled bitmap
    view.setImageDrawable(result);

    // Now change ImageView's dimensions to match the scaled image
    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); 
    params.width = width;
    params.height = height;
    view.setLayoutParams(params);

    Log.i("Test", "done");
}

private int dpToPx(int dp) {
    float density = getApplicationContext().getResources().getDisplayMetrics().density;
    return Math.round((float)dp * density);
}

のxmlコードImageView

<ImageView a:id="@+id/image_box"
    a:background="#ff0000"
    a:src="@drawable/star"
    a:layout_width="wrap_content"
    a:layout_height="wrap_content"
    a:layout_marginTop="20dp"
    a:layout_gravity="center_horizontal"/>


スケーリングコードに関するこの議論のおかげで:http :
//www.anddev.org/resize_and_rotate_image_-_example-t621.html


更新2012年11月7日:
コメントで提案されているようにnullポインターチェックを追加


1
ImageViewは常に250 * 250になります。
2011

2
OK。これはxmlだけでは実行できません。Javaコードが必要です。xmlを使用すると、画像またはのいずれかをスケーリングできますImageView。両方をスケーリングすることはできません。
ヤルノアルギランダー

92
android:を次のものに置き換えることができることに気づかなかった:
StackOverflowed

2
Ionは非同期ネットワーキングと画像読み込みのためのフレームワークです:github.com/koush/ion
Thomas

1
Javaは、このような単純なタスクのために非常に多くのコードを記述する必要があるため、非常に醜い言語です。
ドミトリー

245

この特定の質問の答えにはならないかもしれませんが、私のように、maxWidthアスペクト比を維持しながらImageViewで画像を制限されたサイズ(たとえば)に収める方法を探しており、ImageViewが占める過度のスペースを取り除く場合は、最も簡単な解決策は、XMLで次のプロパティを使用することです。

    android:scaleType="centerInside"
    android:adjustViewBounds="true"

13
これは、画像が小さすぎて画像を拡大したくない場合に機能します。
Janusz 2014年

小さすぎる場合はどのようにスケールアップし、アスペクト比も維持しますか?
Kaustubh Bhagwat 2017年

誰かが必要な場合、「fitCenter」はscaleTypeの別の属性であり、画像を拡大しませんが、大きな画像の場合は、縦横比を維持してビューボックス内の画像の最大サイズに適合します
yogesh prajapati

小さな画像を拡大するには、代わりにscaleType = "centerCrop"を使用します。
Eaweb

このソリューションで作業するもう1つのことは、「android:background」ではなく「android:src」を使用して画像を参照することです。
Codingpan

45
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>

23

以下のコードは、imageviewと同じサイズで完全にビットマップを作成します。ビットマップ画像の高さと幅を取得し、imageviewのパラメーターを使用して新しい高さと幅を計算します。これにより、最高のアスペクト比で必要な画像が得られます。

int currentBitmapWidth = bitMap.getWidth();
int currentBitmapHeight = bitMap.getHeight();

int ivWidth = imageView.getWidth();
int ivHeight = imageView.getHeight();
int newWidth = ivWidth;

newHeight = (int) Math.floor((double) currentBitmapHeight *( (double) new_width / (double) currentBitmapWidth));

Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap, newWidth, newHeight, true);

imageView.setImageBitmap(newbitMap)

楽しい。


3
これにより、幅が削減されたのと同じ係数で元の高さが削減されます。これは、そのnewHeight <ivHeightを保証しません。理想的には、どちらの比率が大きいか(currentBitmapHeight / ivHeight、currentBitmapWidth / ivWidth)を確認し、これに基づいてさらに決定する必要があります。
Sumit Trehan 2016年

1
これは実際には完全に機能しますが、ivHeightやnewWidthは必要ありませんが、代わりにivWidthを計算に入れてください。
Stuart

14

に追加android:scaleType="fitXY"してみてくださいImageView


5
元の画像が正方形でない場合は、これによりアスペクト比が変更されます。
2013

1
fitXYほとんどの場合、画像のアスペクト比が変更されます。OPは、アスペクト比を維持する必要があることを明確に述べています。
IcyFlame

7

1日を検索した後、これが最も簡単な解決策だと思います。

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);

2
あなたの良い答えをありがとう、しかし私はadjustViewBoundsXML に追加するほうがいいと思います

7

ほとんどの場合に機能する最良のソリューションは

次に例を示します。

<ImageView android:id="@+id/avatar"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY"/>

1
非推奨のAPI(fill_parent)に依存しないでください
fdermishin '15年

これはOPの質問にどのように答えますか。これはaspet比率を維持しません
Alex

6

これはすべてXMLを使用して行うことができます...他の方法はかなり複雑に見えます。とにかく、高さをdpで必要なものに設定し、幅を設定してコンテンツをラップするか、その逆を行います。画像のサイズを調整するには、scaleType fitCenterを使用します。

<ImageView
    android:layout_height="200dp"
    android:layout_width="wrap_content"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true"
    android:src="@mipmap/ic_launcher"
    android:layout_below="@+id/title"
    android:layout_margin="5dip"
    android:id="@+id/imageView1">

4

このコードを使用してください:

<ImageView android:id="@+id/avatar"
           android:layout_width="fill_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY" />

4

編集されたJarno Argillanders回答:

画像を幅と高さに合わせる方法:

1)ImageViewを初期化して画像を設定します。

iv = (ImageView) findViewById(R.id.iv_image);
iv.setImageBitmap(image);

2)サイズを変更します。

scaleImage(iv);

編集されたscaleImageメソッド:(EXPECTED境界値を置き換えることができます

private void scaleImage(ImageView view) {
    Drawable drawing = view.getDrawable();
    if (drawing == null) {
        return;
    }
    Bitmap bitmap = ((BitmapDrawable) drawing).getBitmap();

    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    int xBounding = ((View) view.getParent()).getWidth();//EXPECTED WIDTH
    int yBounding = ((View) view.getParent()).getHeight();//EXPECTED HEIGHT

    float xScale = ((float) xBounding) / width;
    float yScale = ((float) yBounding) / height;

    Matrix matrix = new Matrix();
    matrix.postScale(xScale, yScale);

    Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    width = scaledBitmap.getWidth();
    height = scaledBitmap.getHeight();
    BitmapDrawable result = new BitmapDrawable(context.getResources(), scaledBitmap);

    view.setImageDrawable(result);

    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); 
    params.width = width;
    params.height = height;
    view.setLayoutParams(params);
}

そして.xml:

<ImageView
    android:id="@+id/iv_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal" />

私はこのキャストだと思います:LinearLayout.LayoutParams params =(LinearLayout.LayoutParams)view.getLayoutParams(); MarginLayoutParamsはViewGroup.LayoutParamsから継承するため、逆の方向に進む必要があります。
ジェイジェイコブス2017年

3

私の場合はこれで終わりです。

             <ImageView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:scaleType="centerCrop"
                android:adjustViewBounds="true"
                />

2

うまくいかない場合は、android:backgroundをandroid:srcに置き換えてください。

android:srcが主要なトリックを再生します

    <ImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:src="@drawable/bg_hc" />

それは魅力のようにうまく機能しています

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


1

ImageViewとBitmapが必要だったので、BitmapはImageViewサイズにスケーリングされ、ImageViewのサイズはスケーリングされたBitmapと同じです:)。

私はそれを行う方法についてこの投稿を調べていましたが、最終的にはここで説明されている方法ではなく、私がやりたいことを行いました。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/acpt_frag_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/imageBackground"
android:orientation="vertical">

<ImageView
    android:id="@+id/acpt_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:adjustViewBounds="true"
    android:layout_margin="@dimen/document_editor_image_margin"
    android:background="@color/imageBackground"
    android:elevation="@dimen/document_image_elevation" />

そしてonCreateViewメソッドで

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.fragment_scanner_acpt, null);

    progress = view.findViewById(R.id.progress);

    imageView = view.findViewById(R.id.acpt_image);
    imageView.setImageBitmap( bitmap );

    imageView.getViewTreeObserver().addOnGlobalLayoutListener(()->
        layoutImageView()
    );

    return view;
}

そして、layoutImageView()コード

private void layoutImageView(){

    float[] matrixv = new float[ 9 ];

    imageView.getImageMatrix().getValues(matrixv);

    int w = (int) ( matrixv[Matrix.MSCALE_X] * bitmap.getWidth() );
    int h = (int) ( matrixv[Matrix.MSCALE_Y] * bitmap.getHeight() );

    imageView.setMaxHeight(h);
    imageView.setMaxWidth(w);

}

その結果、画像は完全に内部に収まり、アスペクト比を維持し、ビットマップが内部にあるときに、ImageViewからの余分なピクセルが残りません。

結果

wrap_contentとadjustViewBoundsをtrueにすることはImageViewにとって重要であり、setMaxWidthとsetMaxHeightが機能します。これはImageViewのソースコードに記述されています。

/*An optional argument to supply a maximum height for this view. Only valid if
 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
 * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
 * layout params to WRAP_CONTENT. */

0

私はこれをピカソの制約レイアウトで実行する必要があったので、上記の答えのいくつかをまとめてこの解決策を思いつきました(読み込んでいる画像のアスペクト比はすでにわかっているので、それが役立ちます)。

setContentView(...)の後のどこかで私のアクティビティコードで呼び出されました

protected void setBoxshotBackgroundImage() {
    ImageView backgroundImageView = (ImageView) findViewById(R.id.background_image_view);

    if(backgroundImageView != null) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int height = (int) Math.round(width * ImageLoader.BOXART_HEIGHT_ASPECT_RATIO);

        // we adjust the height of this element, as the width is already pinned to the parent in xml
        backgroundImageView.getLayoutParams().height = height;

        // implement your Picasso loading code here
    } else {
        // fallback if no element in layout...
    }
}

私のXMLで

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="0dp">

    <ImageView
        android:id="@+id/background_image_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="fitStart"
        app:srcCompat="@color/background"
        android:adjustViewBounds="true"
        tools:layout_editor_absoluteY="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginBottom="0dp"
        android:layout_marginRight="0dp"
        android:layout_marginLeft="0dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <!-- other elements of this layout here... -->

</android.support.constraint.ConstraintLayout>

constraintBottom_toBottomOf属性がないことに注意してください。ImageLoaderは、utilメソッドと定数をロードする画像の静的クラスです。


0

私は非常にシンプルなソリューションを使用しています。ここに私のコード:

imageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.getLayoutParams().height = imageView.getLayoutParams().width;
imageView.setMinimumHeight(imageView.getLayoutParams().width);

私の写真はグリッドビューに動的に追加されます。これらの設定をimageviewに対して行うと、画像は自動的に1:1の比率で表示されます。


0

簡単な計算を使用して画像のサイズを変更します。ImageViewで設定するよりも、サイズを変更できるか、描画可能な画像のサイズを変更できますImageView。設定したいビットマップの幅と高さを見つけ、ImageView目的のメソッドを呼び出します。幅500が高さよりメソッドの呼び出しよりも大きいと仮定します

//250 is the width you want after resize bitmap
Bitmat bmp = BitmapScaler.scaleToFitWidth(bitmap, 250) ;
ImageView image = (ImageView) findViewById(R.id.picture);
image.setImageBitmap(bmp);

このクラスを使用して、ビットマップのサイズを変更します。

public class BitmapScaler{
// Scale and maintain aspect ratio given a desired width
// BitmapScaler.scaleToFitWidth(bitmap, 100);
 public static Bitmap scaleToFitWidth(Bitmap b, int width)
  {
    float factor = width / (float) b.getWidth();
    return Bitmap.createScaledBitmap(b, width, (int) (b.getHeight() * factor), true);
  }


  // Scale and maintain aspect ratio given a desired height
  // BitmapScaler.scaleToFitHeight(bitmap, 100);
  public static Bitmap scaleToFitHeight(Bitmap b, int height)
  {
    float factor = height / (float) b.getHeight();
    return Bitmap.createScaledBitmap(b, (int) (b.getWidth() * factor), height, true);
   }
 }

xmlコードは

<ImageView
android:id="@+id/picture"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:adjustViewBounds="true"
android:scaleType="fitcenter" />

0

素早い回答:

<ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scaleType="center"
        android:src="@drawable/yourImage"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.