Подогнать изображение в ImageView, сохранить соотношение сторон, а затем изменить его размер до размеров изображения?

165

Как подобрать изображение произвольного размера к ImageView?
Когда:

  • Первоначально ImageViewразмеры 250dp * 250dp
  • Размер изображения должен быть увеличен до 250dp
  • Изображение должно сохранять соотношение сторон
  • Этих ImageViewразмеры должны соответствовать размерам масштабируемого изображения после масштабирования

Например, для изображения 100 * 150 изображение ImageViewдолжно быть 166 * 250.
Например, для изображения 150 * 100 изображение и ImageViewдолжно быть 250 * 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 имел размеры изображения, а изображение должно иметь наибольший размер, равный 250 dp, и сохранять соотношение сторон. Например, для изображения 100 * 150 я хочу, чтобы изображение и ImageView были 166 * 250. Я обновлю свой вопрос.
июл
Хотите ли вы выполнять масштабирование / настройку только при отображении действия (сделать один раз) или при выполнении чего-либо в упражнении, например при выборе изображения из галереи / сети (сделать много раз, но не при загрузке), или и то, и другое?
Ярно Аргиландер
Смотрите мой измененный ответ, который должен делать именно так, как вы этого хотели :)
Ярно Аргиландер

Ответы:

138

(Ответ был сильно изменен после пояснений к исходному вопросу)

После разъяснений:
это не может быть сделано только в XML . Невозможно масштабировать как изображение, так и ImageViewтак, чтобы одно измерение изображения всегда было 250dp и ImageViewимело те же размеры, что и изображение.

Этот код шкала Drawable соединяемого , ImageViewчтобы остаться в квадрате , как 250dp х 250dp с одним размером точно 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


ОБНОВЛЕНИЕ 7 ноября 2012:
добавлена ​​проверка нулевого указателя, как это предлагается в комментариях

Ярно Аргиландер
источник
1
ImageView всегда будет 250 * 250.
июл
2
Хорошо. Это не может быть сделано только в XML. Требуется код Java. С XML вы можете масштабировать изображение или ImageView, а не оба.
Ярно Аргиландер
94
не понимал, что можно заменить Android: a:
StackOverflowed
2
Ion - это структура для асинхронной сети и загрузки изображений: github.com/koush/ion
Томас,
1
Java - очень уродливый язык, потому что он требует написания большого количества кода для таких простых задач.
Дмитрий
246

Может не быть ответом на этот конкретный вопрос, но если кто-то, как и я, ищет ответ, как подогнать изображение в ImageView с ограниченным размером (например, maxWidth), сохранив соотношение сторон, а затем избавиться от чрезмерного пространства, занимаемого ImageView, тогда самое простое решение - использовать следующие свойства в XML:

    android:scaleType="centerInside"
    android:adjustViewBounds="true"
Отображаемое имя
источник
14
Это работает, если вы не хотите, чтобы изображение было увеличено, если оно слишком маленькое.
Януш
Как я могу увеличить его, если он слишком мал, а также сохранить соотношение сторон?
Каустуб Бхагват
если кому-то нужно, «fitCenter» - это еще один атрибут для scaleType, и он не будет масштабировать изображение, но для любого большого изображения он будет соответствовать максимальному размеру изображения в окне просмотра, сохраняя соотношение сторон
yogesh prajapati
чтобы увеличить маленькие изображения, используйте scaleType = "centerCrop".
Eaweb
Еще одна вещь для меня, чтобы работать с этим решением, это использовать «android: src», а не «android: background» для ссылки на мое изображение.
Codingpan
45
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>
дизель
источник
23

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

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), а затем на основе этого принять дальнейшее решение.
Сумит Трехан
1
Это на самом деле работает отлично, хотя вам не нужны ivHeight или newWidth, просто вместо этого поместите ivWidth в расчет.
Стюарт
14

попробуйте добавить android:scaleType="fitXY"в свой ImageView.

DeeFour
источник
5
Это изменит соотношение сторон, если исходное изображение не в квадрате.
Июль
1
fitXYпочти всегда меняет соотношение сторон изображения. OP четко упоминает, что соотношение сторон ДОЛЖНО поддерживаться.
IcyFlame
7

После поиска в течение дня, я думаю, что это самое простое решение:

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);
MikeyB
источник
2
Спасибо за ваш хороший ответ, но я думаю, что лучше добавить adjustViewBoundsв XML
7

Лучшее решение, которое работает в большинстве случаев, это

Вот пример:

<ImageView android:id="@+id/avatar"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY"/>
Никита Вишвакарма
источник
1
Не полагайтесь на устаревший API (fill_parent)
fdermishin
как это отвечает на вопрос ОП. Это не будет поддерживать соотношение
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">
Thunderstick
источник
4

Используйте этот код:

<ImageView android:id="@+id/avatar"
           android:layout_width="fill_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY" />
Абхай Ананд
источник
4

Отредактированный ответ Ярно Аргиландерса :

Как подогнать изображение под ваши ширину и высоту:

1) Инициализировать ImageView и установить изображение:

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

2) Теперь измените размер:

scaleImage(iv);

Отредактированный scaleImageметод: ( вы можете заменить ОЖИДАЕМЫЕ ограничивающие значения )

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.
Джей Джейкобс
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" />

это работает хорошо, как шарм

введите описание изображения здесь

Harvinder Singh
источник
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, когда внутри растровое изображение.

результат

Важно, чтобы ImageView имел wrap_content и AdjustViewBounds в true, тогда 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. */
alekshandru
источник
0

Мне нужно было сделать это в макете ограничений с помощью Picasso, поэтому я собрал воедино некоторые из приведенных выше ответов и нашел это решение (я уже знаю соотношение сторон загружаемого изображения, так что это помогает):

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

чувак пребывает
источник
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);

Мои картинки добавляются динамически в сетку. Когда вы делаете эти настройки для просмотра изображений, изображение может автоматически отображаться в соотношении 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" />
myworldbox
источник