Масштабировать изображение, чтобы заполнить ширину ImageView и сохранить пропорции

У меня есть 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 не отображает изображение целиком.

Как решить эту проблему?

Без использования каких-либо пользовательских классов или библиотек:

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

scaleType="fitCenter" (по умолчанию при scaleType="fitCenter" )

  • Сделает ее такой же широкой, как позволяет родитель, и увеличивая / уменьшая масштаб по мере необходимости, сохраняя соотношение сторон.

scaleType="centerInside"

  • Если внутренняя ширина src меньше родительской ширины
    Центрирует изображение по горизонтали
  • Если внутренняя ширина src больше родительской ширины
    Сделает его таким же широким, как и родительский, и уменьшит пропорции.

Не имеет значения, используете ли вы методы android:src или ImageView.setImage* а ключ – это, вероятно, adjustViewBounds .

Мне нравится отвечать на 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

Однажды у меня была аналогичная проблема. Я решил это, создав собственный ImageView.

 public class CustomImageView extends 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); } 

Это позволит растянуть изображение, чтобы он соответствовал экрану, сохраняя соотношение сторон.

Использовать android:scaleType="centerCrop" .

Я сделал что-то подобное выше, а затем ударил головой о стену в течение нескольких часов, потому что он не работал внутри 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> -  <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> 

Используйте эти свойства в ImageView, чтобы сохранить соотношение сторон:

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

Это не будет применимо, если вы установите изображение в качестве фона в ImageView, необходимо установить в src (android: src).

Благодарю.

Вы можете попытаться сделать то, что вы делаете, вручную загрузив изображения, но я очень рекомендую взглянуть на Universal Image Loader .

Недавно я включил его в свой проект, и я должен сказать его фантастический. Все беспокоиться о том, чтобы сделать вещи асинхронными, изменять размер, кэшировать изображения для вас. Это очень легко интегрировать и настроить. В течение 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); 

Это может ленить загружать изображения, правильно вписывать их в размер изображенияView, отображая изображение-заглушку во время загрузки, и показывать значок по умолчанию, если загрузка не выполняется и кэширование ресурсов.

– Я должен также добавить, что эта текущая конфигурация поддерживает соотношение сторон изображения, следовательно, применима к вашему первоначальному вопросу

Попробуйте это: он решил проблему для меня

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

Используйте picasso, который прост в использовании.

В вашем адаптере ..

 @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/ Введите описание изображения здесь

Просто используйте UniversalImageLoader и установите

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

И никаких настроек масштаба в ImageView

Yo не нужен какой-либо Java-код. Вам просто нужно:

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

Ключ находится в родительском матче для ширины и высоты

Чтобы создать изображение с шириной равным ширине экрана, а высота пропорционально задана в соответствии с соотношением сторон, сделайте следующее.

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

Надеюсь это поможет.