Вмістити зображення у ImageView, зберегти співвідношення сторін та змінити розмір ImageView до розмірів зображення?


164

Як підігнати зображення довільного розміру до 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. Чи потрібно підтримувати співвідношення сторін?
— Jarno Argillander

Я хочу, щоб у ImageView були розміри зображення, а найбільший розмір зображення дорівнював 250dp і зберігати його співвідношення сторін. Наприклад, для зображення розміром 100 * 150, я хочу, щоб зображення та ImageView були 166 * 250. Я оновлю своє запитання.
— липня

Ви хочете робити масштабування / коригування лише під час відображення діяльності (зробити один раз) або коли ви робите щось із цього виду, як-от вибір зображення з галереї / Інтернету (робити багато разів, але не під час завантаження) або обох?
— Ярно Аргіландер

Дивіться мою модифіковану відповідь, яка повинна робити саме так, як ви цього хотіли :)
— Jarno Argillander

Відповіді:


137

(Відповідь була сильно змінена після роз'яснень на початкове запитання)

Після уточнення:
Це неможливо зробити лише у форматі xml . Неможливо масштабувати як зображення, так і ImageViewтак, щоб один вимір зображення завжди був би 250dp, а розмір ImageViewматиме ті ж розміри, що і зображення.

Цей код масштабує Drawable розміщення ImageViewу квадраті, як 250dp x 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, не обидва.
— Jarno Argillander

93
не зрозумів, що ти можеш замінити android: з:
— StackOverflowed

2
Іон є основою для асинхронних мереж та завантаження зображень: github.com/koush/ion
— Томас

1
Java - надзвичайно некрасива мова, оскільки для таких простих завдань потрібно написати стільки коду.
— Дмитро

245

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

    android:scaleType="centerInside"
    android:adjustViewBounds="true"

13
Це працює, якщо ви не хочете, щоб зображення було масштабовано, якщо воно занадто мало.
— Януш

як я масштабую його, якщо його занадто мало, а також підтримувати співвідношення сторін?
— Каустуб Бхагват

якщо комусь потрібно, "fitCenter" - це ще один атрибут для scaleType, і він не буде масштабувати зображення, але для будь-якого великого зображення він підійде до максимального розміру зображення всередині вікна перегляду, зберігаючи пропорцію
— yogesh prajapati

для масштабування невеликих зображень використовуйте натомість scaleType = "centerCrop".
— Eaweb

Ще одна річ для мене з цим рішенням - використовувати "android: src", а не "android: background", щоб переглянути своє зображення.
— Кодування

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

23

Наведений нижче код робить ідеальне зображення з однаковим розміром перегляду зображень. Отримайте висоту та ширину растрового зображення, а потім обчисліть нову висоту та ширину за допомогою параметрів imageview. Це дає вам потрібне зображення з найкращим співвідношенням сторін.

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
Це просто зменшить початкову висоту на той же коефіцієнт, на який зменшилася ширина. Це не гарантує нову висоту <ivHeight. В ідеалі слід перевірити, яке співвідношення більше (currentBitmapHeight / ivHeight, currentBitmapWidth / ivWidth), а потім на основі цього прийняти подальше рішення.
— Суміт Трехан

1
Це насправді працює чудово, хоча вам не потрібен ivHeight або newWidth, просто введіть ivWidth у розрахунок.
— Стюарт

14

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


5
Це змінить співвідношення сторін, якщо вихідне зображення не буде квадратним.
— Липень

1
fitXYмайже завжди змінить співвідношення сторін зображення. OP чітко зазначає, що співвідношення сторін ОБОВ'ЯЗКОВО зберігати.
— IcyFlame

7

Шукаючи день, я думаю, що це найпростіше рішення:

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);

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

як це відповідає на питання ОП. Це не підтримуватиме співвідношення аспетів
— Алекс

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

4

Використовуйте цей код:

<ImageView android:id="@+id/avatar"
           android:layout_width="fill_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY" />

4

Відредагований Jarno Argillanders відповідає:

Як підходити до зображення за вашою шириною та висотою:

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: фон на 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" />

це працює чудово, як шарм

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


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, коли Bitmap знаходиться всередині.

Результат

Важливо, щоб ImageView мав wrap_content і пристосовувавViewBounds до істинного, тоді 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. */

0

Мені потрібно було це виконати у макеті з обмеженням з Пікассо, тому я зібрав разом із цими вищезазначені відповіді і придумав це рішення (я вже знаю співвідношення сторін зображення, яке завантажую, так що це допомагає):

Викликається в моєму коді активності десь після 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" />
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.