ImageViewの幅を埋め、アスペクト比を維持するために画像を拡大縮小する


198

私は持っていGridViewます。のデータはGridViewサーバーからのリクエストです。

のアイテムレイアウトはGridView次のとおりです。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/analysis_micon_bg"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="@dimen/half_activity_vertical_margin"
    android:paddingLeft="@dimen/half_activity_horizontal_margin"
    android:paddingRight="@dimen/half_activity_horizontal_margin"
    android:paddingTop="@dimen/half_activity_vertical_margin" >

    <ImageView
        android:id="@+id/ranking_prod_pic"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:contentDescription="@string/app_name"
        android:scaleType="centerCrop" />

    <TextView
        android:id="@+id/ranking_rank_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/ranking_prod_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/ranking_prod_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

サーバーにデータをリクエストし、画像のURLを取得して画像を読み込む Bitmap

public static Bitmap loadBitmapFromInputStream(InputStream is) {
    return BitmapFactory.decodeStream(is);
}

public static Bitmap loadBitmapFromHttpUrl(String url) {
    try {
        return loadBitmapFromInputStream((InputStream) (new URL(url).getContent()));
    } catch (Exception e) {
        Log.e(TAG, e.getMessage());
        return null;
    }
}

getView(int position, View convertView, ViewGroup parent)アダプタにメソッドのコードがあります

Bitmap bitmap = BitmapUtil.loadBitmapFromHttpUrl(product.getHttpUrl());
prodImg.setImageBitmap(bitmap);

画像サイズは210*210です。Nexus 4でアプリケーションを実行しています。画像はImageView幅いっぱいに表示ImageViewされますが、高さは拡大縮小されません。ImageView画像全体は表示されません。

この問題を解決するにはどうすればよいですか?

回答:


544

カスタムクラスまたはライブラリを使用しない場合:

<ImageView
    android:id="@id/img"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter" />

scaleType="fitCenter" (省略時のデフォルト)

  • 親が許す限りの幅にし、必要に応じてアスペクト比を維持しながら拡大/縮小します。

scaleType="centerInside"

  • の固有の幅がsrc親の幅よりも小さい場合
    、画像は水平方向に中央揃えになります
  • の固有の幅がsrc親の幅よりも大きい場合、親の幅
    と同じ幅になり、アスペクト比を維持して縮小されます。

android:srcまたはImageView.setImage*メソッドを使用しているかどうかは関係なく、キーはおそらくadjustViewBoundsです。


5
android:layout_height = "wrap_content" android:adjustViewBounds = "true" android:scaleType = "fitCenter"がトリック
James Tan

fill_parent幅の@JamesTan はちょうど良い習慣です。固定サイズでも機能します。
TWiStErRob 2015

@TWiStErRob私はそれにandroid:adjustViewBounds = "true"が必要であることを理解しています。はい、親に合わせる幅は完全版です
James Tan

9
API 19以降ではチャームのように機能しますが、API 16(テスト済み)では機能しません。Alex SemeniukのカスタムビューはAPI 16でも動作します。
Ashkan Sarlak 2015

1
@ F.Mysir whops ps、はい、どちらが問題になるかは問題ではありませんが、優れた実践を広めるために、私は完全に同意します。
TWiStErRob

42

私はarnefmの回答が好きですが、彼は小さな間違いを犯しました(コメントを参照)。

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

/**
 * ImageView that keeps aspect ratio when scaled
 */
public class ScaleImageView extends ImageView {

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

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

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

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    try {
      Drawable drawable = getDrawable();
      if (drawable == null) {
        setMeasuredDimension(0, 0);
      } else {
        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
        int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
        if (measuredHeight == 0 && measuredWidth == 0) { //Height and width set to wrap_content
          setMeasuredDimension(measuredWidth, measuredHeight);
        } else if (measuredHeight == 0) { //Height set to wrap_content
          int width = measuredWidth;
          int height = width *  drawable.getIntrinsicHeight() / drawable.getIntrinsicWidth();
          setMeasuredDimension(width, height);
        } else if (measuredWidth == 0){ //Width set to wrap_content
          int height = measuredHeight;
          int width = height * drawable.getIntrinsicWidth() / drawable.getIntrinsicHeight();
          setMeasuredDimension(width, height);
        } else { //Width and height are explicitly set (either to match_parent or to exact value)
          setMeasuredDimension(measuredWidth, measuredHeight);
        }
      }
    } catch (Exception e) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
  }

}

したがって、ImageView適切にスケーリングされ、(たとえば)の内部に配置した場合、次元の問題は発生しませんScrollView


thx、arnefmの回答、私が追加した最初のコメントのすぐ下に解決策を見つけました。それthereはリンクです
Joe

36

一度同様の問題がありました。カスタムImageViewを作成して解決しました。

public class CustomImageView extends ImageView

次に、imageviewのonMeasureメソッドをオーバーライドします。私はこのようなことをしたと思います:

    @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    try {
        Drawable drawable = getDrawable();

        if (drawable == null) {
            setMeasuredDimension(0, 0);
        } else {
            float imageSideRatio = (float)drawable.getIntrinsicWidth() / (float)drawable.getIntrinsicHeight();
            float viewSideRatio = (float)MeasureSpec.getSize(widthMeasureSpec) / (float)MeasureSpec.getSize(heightMeasureSpec);
            if (imageSideRatio >= viewSideRatio) {
                // Image is wider than the display (ratio)
                int width = MeasureSpec.getSize(widthMeasureSpec);
                int height = (int)(width / imageSideRatio);
                setMeasuredDimension(width, height);
            } else {
                // Image is taller than the display (ratio)
                int height = MeasureSpec.getSize(heightMeasureSpec);
                int width = (int)(height * imageSideRatio);
                setMeasuredDimension(width, height);
            }
        }
    } catch (Exception e) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

これにより、アスペクト比を維持しながら画像を画面に合わせて拡大します。


1
参照。最初の答え
Joe

まあ、この答えは正確ではありません。設定する状況を考慮してくださいandroid:layout_height="wrap_content"。この場合、結果MeasureSpec.getSize(heightMeasureSpec)は次のように0なります(不思議である必要はありません。Javafloatはそのような値を許可します)。この場合、との両方がになります。viewSideRatioInfinityheightwidth0
Alex Semeniuk 2013年

1
..私は(imageSideRatio <viewSideRatio)に(imageSideRatio> = viewSideRatio)スワップに必要なフィル仕事をするためにするためにそれ以外の場合は良い答え
マレクHalmo

23

を使用しandroid:scaleType="centerCrop"ます。


質問が正確に何を求めているかではなく、まさに私が必要とするもの!
nickjm 2015年

@Jamesonについて詳しく説明していただけますか?Androidのバージョンですか?
ミック

centerCropを使用すると、画像の上下が少しカットされます。
Sreekanth Karumanaghat

9

上記と同様の操作を行った後、頭の中を壁に数時間ぶつけましたRelativeLayout。私は次のコードで終わりました:

package com.example;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;

public class ScaledImageView extends ImageView {
    public ScaledImageView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        final Drawable d = getDrawable();

        if (d != null) {
            int width;
            int height;
            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
                height = MeasureSpec.getSize(heightMeasureSpec);
                width = (int) Math.ceil(height * (float) d.getIntrinsicWidth() / d.getIntrinsicHeight());
            } else {
                width = MeasureSpec.getSize(widthMeasureSpec);
                height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
            }
            setMeasuredDimension(width, height);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
}

そしてRelativeLayout、測定された寸法を無視しないようにするために、これを行いました:

    <FrameLayout
        android:id="@+id/image_frame"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/something">

        <com.example.ScaledImageView
            android:id="@+id/image"
            android:layout_width="wrap_content"
            android:layout_height="150dp"/>
    </FrameLayout>

5

ImageViewでこれらのプロパティを使用して、アスペクト比を維持します。

android:adjustViewBounds="true"
android:scaleType="fitXY"

9
fitXYはアスペクト比を維持しません。レイアウトの幅と高さにぴったり合うように画像を拡大します。
放棄されたカート

5

ImageViewで画像を背景として設定する場合、これは適用されません。src(android:src)で設定する必要があります。

ありがとう。


5

幅が画面の幅に等しく、アスペクト比に応じて高さが比例して設定された画像を作成するには、次の操作を行います。

Glide.with(context).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {

                        // creating the image that maintain aspect ratio with width of image is set to screenwidth.
                        int width = imageView.getMeasuredWidth();
                        int diw = resource.getWidth();
                        if (diw > 0) {
                            int height = 0;
                            height = width * resource.getHeight() / diw;
                            resource = Bitmap.createScaledBitmap(resource, width, height, false);
                        }
                                              imageView.setImageBitmap(resource);
                    }
                });

お役に立てれば。


これが私が見つけた最良の答えです、私は2日間検索しました、ありがとうファティマ
Karthick Ramanathan


4

あなたはJavaコードを必要としません。あなたはただ:

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

キーは、幅と高さの一致する親にあります


centerCropは実際に画像の一部を切り取ります。
Sreekanth Karumanaghat

2

この単純な行で試してください...この行を画像ビュータグのxmlコードに追加し、依存関係を追加しないでください。android:scaleType = "fitXY"


fitXYは縦横比を維持しないため、画像が引き伸ばされる可能性があります
ProjectDelta

2

android:ScaleType = "fitXY" im ImageView xmlを使用します


fitXYは縦横比を維持しないため、画像が引き伸ばされる可能性があります
ProjectDelta

1

手作業で画像を読み込むことで、自分がやっていることを試すことができますが、ユニバーサルイメージローダーを確認することを強くお勧めします。

私は最近それを私のプロジェクトに統合しました、そしてそれは素晴らしいと言わざるを得ません。非同期化、サイズ変更、画像のキャッシュに関する心配事をすべて行います。統合とセットアップは本当に簡単です。5分以内に、あなたはおそらくあなたが望むことをすることができます。

コード例:

//ImageLoader config
DisplayImageOptions displayimageOptions = new DisplayImageOptions.Builder().showStubImage(R.drawable.downloadplaceholder).cacheInMemory().cacheOnDisc().showImageOnFail(R.drawable.loading).build();

    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()).
            defaultDisplayImageOptions(displayimageOptions).memoryCache(new WeakMemoryCache()).discCache(new UnlimitedDiscCache(cacheDir)).build();

    if (ImageLoader.getInstance().isInited()) {
        ImageLoader.getInstance().destroy();
    }
    ImageLoader.getInstance().init(config);

    imageLoadingListener = new ImageLoadingListener() {
        @Override
        public void onLoadingStarted(String s, View view) {

        }

        @Override
        public void onLoadingFailed(String s, View view, FailReason failReason) {
            ImageView imageView = (ImageView) view;
            imageView.setImageResource(R.drawable.android);
            Log.i("Failed to Load " + s, failReason.toString());
        }

        @Override
        public void onLoadingComplete(String s, View view, Bitmap bitmap) {

        }

        @Override
        public void onLoadingCancelled(String s, View view) {

        }
    };

//Imageloader usage
ImageView imageView = new ImageView(getApplicationContext());
    if (orientation == 1) {
        imageView.setLayoutParams(new LinearLayout.LayoutParams(width / 6, width / 6));
    } else {
        imageView.setLayoutParams(new LinearLayout.LayoutParams(height / 6, height / 6));
    }
    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    imageLoader.displayImage(SERVER_HOSTNAME + "demos" + demo.getPathRoot() + demo.getRootName() + ".png", imageView, imageLoadingListener);

これにより、画像を遅延読み込みし、読み込み中にプレースホルダー画像を示し、読み込みに失敗してリソースをキャッシュした場合にデフォルトのアイコンを表示するimageViewのサイズに正しく合わせることができます。

-また、この現在の構成は画像のアスペクト比を維持するため、元の質問に適用できることも追加する必要があります


0

UniversalImageLoaderを使用して設定するだけです

DisplayImageOptions.Builder()
    .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
    .build();

そしてImageViewのスケール設定なし


0

同様の問題がありました。その理由は、を計算する必要があるためですdp。Androidのスタジオが計算されImageViewますから、それをロードするときdrawable、あなたはからの読み込みのように、別の方法を使用している場合、ビットマップdp、自動的に計上されていません

これが私のxmlです

<ImageView
  android:id="@+id/imageViewer"
  android:layout_width="match_parent"
  android:layout_height="match_parent"//dp is not automaticly updated, when loading from a other source
  android:scaleType="fitCenter"
  tools:srcCompat="@drawable/a8" />

Kotlinを使用していて、アセットファイルからドローアブルを読み込んでいます。これは、これを計算する方法です

val d = Drawable.createFromStream(assets.open("imageData/${imageName}.png"), null)
bitHeight = d.minimumHeight//get the image height
imageViewer.layoutParams.height = (bitHeight * resources.displayMetrics.density).toInt()//set the height
imageViewer.setImageDrawable(d)//set the image from the drawable
imageViewer.requestLayout()//here I apply it to the layout

-1

使いやすいピカソを使ってください。

あなたのアダプターで..

@Override
public void getView(int position, View convertView, ViewGroup parent) {

 ImageView view = (ImageView) convertView.findViewById(R.id.ranking_prod_pic);

 Picasso.with(context).load(url).into(view); //url is image url

 //you can resize image if you want

 /* Picasso.with(context) .load(url) .resize(50, 50) .centerCrop() .into(view) */

}

http://square.github.io/picasso/ ここに画像の説明を入力してください

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