Вмістити зображення у 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.