2013-08-06 3 views
128

У меня есть GridView. Данные GridView - это запрос с сервера.Масштабировать изображение, чтобы заполнить ImageView width и сохранить пропорции

Вот макет элемента в 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 не отображает изображение целиком.

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

ответ

352

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

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

scaleType="fitCenter" (по умолчанию, когда опущен)

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

scaleType="centerInside"

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

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

+19

Хороший ответ. 'adjustViewBounds' делает трюк! – KvTvK

+1

android: layout_height = "wrap_content" android: adjustViewBounds = "true" android: scaleType = "fitCenter" делает трюк –

+0

@JamesTan 'fill_parent' для ширины - это просто хорошая практика, работает фиксированный размер. – TWiStErRob

1

Вы можете попытаться сделать то, что вы делаете, вручную загрузив изображения, но я очень рекомендую взглянуть на 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); 

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

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

34

у меня была аналогичная проблема раз. Я решил это, создав собственный 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); 
    } 

Это будет растянуть изображение по размеру экрана, сохраняя пропорции.

+1

см [там] (HTTP: // StackOverflow. ком/вопросы/2991110/Android-хау к протяжению-ан-изображение-к-трафаретной ширина в то время, сохраняющей-аспект-ра). первый ответ – Joe

+0

Ну, этот ответ не точен. Рассмотрим ситуацию, когда вы устанавливаете 'android: layout_height =" wrap_content "'. В этом случае 'MeasureSpec.getSize (heightMeasureSpec)' будет '0', а ваш' viewSideRatio' приведет к 'Infinity' (не нужно удивляться, Java float допускает такие значения.) В этом случае и ваши' height', и ' width' будет '0'. –

+1

См. Ответ ниже о том, как ваш код должен быть исправлен. –

41

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

+0

thx, я нашел решение , чуть ниже ответа arnefm, первый комментарий, который я добавил. что 'there' есть ссылка – Joe

+1

Спасибо за исправление ответа arnefm – adnanyousafch

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> 
0

Использование 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/ enter image description here

16

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

+0

Не совсем то, о чем спрашивал вопрос, а именно то, что мне нужно! – nickjm

+1

Это не всегда работает. – Jameson

+0

Можете ли вы разработать @Jameson? Вы имеете в виду Android-версии? – Mick

0

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

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

и нет шкалы настройки на ImageView

2

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

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

fitXY не поддерживает соотношение сторон. Он растягивает изображение, чтобы точно соответствовать ширине и высоте макета. – LoungeKatt

1

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

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

fitXY не подходит – GvSharma

0

Вам не нужен код java. Вы просто должны:

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

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

4

Это не будет применяться, если вы установите изображение в качестве фона в ImageView, нужно установить в ГКЗ (андроида: ЦСИ).

Спасибо.

0

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

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

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

1

попробовать с этой простой линией ... добавить эту строку в коде XML в изображении вида тега с вне добавления каких-либо зависимости андроида: scaleType = «fitXY»

Смежные вопросы