Масштабировать изображение, чтобы заполнить ширину 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
не отображает все изображение.
Как решить эту проблему?
Ответы
Ответ 1
Без использования каких-либо пользовательских классов или библиотек:
<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
.
Ответ 2
Мне нравится ответ 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
Ответ 3
У меня была аналогичная проблема. Я решил это, создав пользовательский 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);
}
Это растянет изображение, чтобы оно соответствовало экрану при сохранении формата.
Ответ 4
Используйте android:scaleType="centerCrop"
.
Ответ 5
Я сделал что-то похожее на выше, а затем ударил головой о стену в течение нескольких часов, потому что он не работал внутри 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>
Ответ 6
Это не будет применимо, если вы установите изображение в качестве фона в ImageView, необходимо установить в src (android: src).
Спасибо.
Ответ 7
Используйте эти свойства в ImageView, чтобы сохранить соотношение сторон:
android:adjustViewBounds="true"
android:scaleType="fitXY"
Ответ 8
Вы можете попытаться сделать то, что вы делаете, вручную загрузив изображения, но я очень рекомендую взглянуть на Универсальный загрузчик изображений.
Недавно я включил его в свой проект, и я должен сказать его фантастический. Все беспокоиться о том, чтобы сделать вещи асинхронными, изменять размер, кэшировать изображения для вас. Это очень легко интегрировать и настроить. В течение 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, отображая изображение-заглушку во время загрузки, и показывать значок по умолчанию, если загрузка не выполняется и кэширование ресурсов.
- Я также должен добавить, что эта текущая конфигурация поддерживает соотношение сторон изображения, поэтому применима к вашему оригинальному вопросу
Ответ 9
Попробуйте это: он решил проблему для меня
android:adjustViewBounds="true"
android:scaleType="fitXY"
Ответ 10
Используйте 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]()
Ответ 11
Просто используйте UniversalImageLoader и установите
DisplayImageOptions.Builder()
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
.build();
и никаких настроек масштаба в ImageView
Ответ 12
Мне не нужен какой-либо Java-код. Вам просто нужно:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop" />
Ключ в родительском матке для ширины и высоты
Ответ 13
Чтобы создать изображение с шириной равным ширине экрана, а высота пропорционально задана в соответствии с соотношением сторон, сделайте следующее.
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);
}
});
Надеюсь, что это поможет.
Ответ 14
попробуйте эту простую строку... добавьте эту строку в свой XML-код в теге просмотра изображения без добавления какой-либо зависимости
андроид: scaleType = "fitXY"