Ajuster l'image dans ImageView, conserver les proportions, puis redimensionner ImageView aux dimensions de l'image?


165

Comment adapter une image de taille aléatoire à un ImageView?
Quand:

  • Les ImageViewdimensions initiales sont 250dp * 250dp
  • La plus grande dimension de l'image doit être augmentée / réduite à 250dp
  • L'image doit conserver ses proportions
  • Les ImageViewdimensions doivent correspondre aux dimensions de l'image mise à l'échelle après la mise à l'échelle

Par exemple, pour une image de 100 * 150, l'image et le ImageViewdoivent être 166 * 250.
Par exemple, pour une image de 150 * 100, l'image et le ImageViewdoivent être 250 * 166.

Si je fixe les limites comme

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

les images s'intègrent correctement dans le ImageView, mais le ImageViewest toujours 250dp * 250dp.


Euh, voulez-vous changer la taille de la taille de ImageViewl'image? Par exemple, une image de 100dp x 150dp serait mise à l'échelle ImageViewaux mêmes mesures? Ou voulez-vous dire comment redimensionner l'image aux ImageViewlimites. Par exemple, une image de 1000dp x 875dp serait mise à l'échelle en 250dp x 250dp. Avez-vous besoin de conserver les proportions?
Jarno Argillander

Je veux que ImageView ait les dimensions de l'image et que l'image ait sa plus grande dimension égale à 250dp et conserve son rapport hauteur / largeur. Par exemple, pour une image de 100 * 150, je veux que l'image et ImageView soient 166 * 250. Je vais mettre à jour ma question.
jul

Voulez-vous effectuer une mise à l'échelle / un ajustement uniquement lors de l'affichage d'une activité (à faire une fois) ou lorsque vous faites quelque chose sur l'activité, comme sélectionner une image dans la galerie / le Web (à faire plusieurs fois mais pas au chargement) ou les deux?
Jarno Argillander

Voir ma réponse modifiée, qui devrait faire exactement ce que vous vouliez :)
Jarno Argillander

Réponses:


138

(La réponse a été fortement modifiée après des clarifications à la question initiale)

Après clarifications:
cela ne peut pas être fait uniquement en XML . Il n'est pas possible de mettre à l'échelle à la fois l'image et le ImageViewpour que la dimension unique de l'image soit toujours 250dp et que le ImageViewait les mêmes dimensions que l'image.

Ce code met à l'échelle Drawable un ImageViewpour rester dans un carré comme 250dp x 250dp avec une dimension exactement 250dp et en conservant le rapport hauteur / largeur. Ensuite, le ImageViewest redimensionné pour correspondre aux dimensions de l'image mise à l'échelle. Le code est utilisé dans une activité. Je l'ai testé via le gestionnaire de clic de bouton.

Prendre plaisir. :)

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

Le code xml pour 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"/>


Merci à cette discussion pour le code de mise à l'échelle:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html


MISE À JOUR 7 novembre 2012:
Ajout de la vérification du pointeur nul comme suggéré dans les commentaires


1
ImageView sera toujours 250 * 250.
jul

2
D'accord. Cela ne peut pas être fait uniquement en XML. Le code Java est requis. Avec xml, vous pouvez redimensionner l'image ou le ImageView, pas les deux.
Jarno Argillander

94
Je ne savais pas que vous pouviez remplacer Android: par un:
StackOverflowed

2
Ion est un framework pour la mise en réseau asynchrone et le chargement d'images: github.com/koush/ion
Thomas

1
Java est un langage extrêmement laid car il nécessite d'écrire beaucoup de code pour des tâches aussi simples.
Dmitry

246

Peut ne pas être une réponse à cette question spécifique, mais si quelqu'un, comme moi, cherche une réponse sur la façon d'ajuster l'image dans ImageView avec une taille limitée (par exemple, maxWidth) tout en préservant le rapport hauteur / largeur, puis en se débarrassant de l'espace excessif occupé par ImageView, alors la solution la plus simple consiste à utiliser les propriétés suivantes en XML:

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

14
Cela fonctionne si vous ne voulez pas que l'image soit mise à l'échelle si elle est trop petite.
Janusz

Comment puis-je le mettre à l'échelle s'il est trop petit et maintenir le rapport hauteur / largeur?
Kaustubh Bhagwat

si quelqu'un a besoin, "fitCenter" est un autre attribut pour scaleType, et il n'agrandira pas l'image, mais pour toute grande image, il s'adaptera à la taille maximale de l'image à l'intérieur de la zone de vue en conservant le rapport
hauteur

pour agrandir les petites images, utilisez à la place scaleType = "centerCrop".
Eaweb

une autre chose pour moi de travailler avec cette solution est d'utiliser "android: src" et non le "android: background" pour refaire mon image.
Codingpan

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

23

Le code ci-dessous rend le bitmap parfaitement avec la même taille de l'image vue. Obtenez la hauteur et la largeur de l'image bitmap, puis calculez la nouvelle hauteur et la largeur à l'aide des paramètres d'imageview. Cela vous donne l'image requise avec le meilleur rapport hauteur / largeur.

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)

prendre plaisir.


3
Cela réduira simplement la hauteur d'origine du même facteur que celui par lequel la largeur a été réduite. Cela ne garantit pas que newHeight <ivHeight. Idéalement, vous devriez vérifier quel rapport est le plus grand (currentBitmapHeight / ivHeight, currentBitmapWidth / ivWidth) et ensuite, sur la base de cette décision, prendre une autre décision.
Sumit Trehan

1
Cela fonctionne parfaitement, bien que vous n'ayez pas besoin de ivHeight ou newWidth, mettez simplement ivWidth dans le calcul à la place.
Stuart

14

essayez d'ajouter android:scaleType="fitXY"à votre ImageView.


5
Cela modifiera le rapport hauteur / largeur si l'image d'origine n'est pas au carré.
juillet

1
fitXYchangera presque toujours le rapport hauteur / largeur de l'image. OP mentionne clairement que le rapport hauteur / largeur DOIT être conservé.
IcyFlame

7

Après avoir cherché un jour, je pense que c'est la solution la plus simple:

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

2
Merci pour votre gentille réponse, mais je pense qu'il vaut mieux ajouter adjustViewBoundsà XML

7

La meilleure solution qui fonctionne dans la plupart des cas est

Voici un exemple:

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

1
Ne comptez pas sur l'API obsolète (fill_parent)
fdermishin

comment cela répond-il à la question d'OP. Cela ne maintiendra pas le ratio d'aspet
Alex

6

tout cela peut être fait en utilisant XML ... les autres méthodes semblent assez compliquées. Quoi qu'il en soit, vous réglez simplement la hauteur à ce que vous voulez dans dp, puis définissez la largeur pour envelopper le contenu ou vice versa. Utilisez scaleType fitCenter pour ajuster la taille de l'image.

<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

Utilisez ce code:

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

4

Modifié Jarno Argillanders réponse:

Comment adapter l' image avec votre Largeur et Hauteur:

1) Initialiser ImageView et ensemble Image:

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

2) Redimensionnez maintenant:

scaleImage(iv);

scaleImageMéthode modifiée : ( vous pouvez remplacer les valeurs de délimitation EXPECTED )

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

Et .xml:

<ImageView
    android:id="@+id/iv_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal" />

Je pense que cette distribution: LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams (); devrait aller dans l'autre sens, puisque MarginLayoutParams hérite de ViewGroup.LayoutParams.
Jay Jacobs

3

Cela l'a fait pour mon cas.

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

2

si cela ne fonctionne pas pour vous, remplacez android: background par android: src

android: src jouera le truc majeur

    <ImageView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitCenter"
    android:src="@drawable/bg_hc" />

ça marche bien comme un charme

entrez la description de l'image ici


1

J'avais besoin d'un ImageView et d'un Bitmap, donc le Bitmap est mis à l'échelle à la taille ImageView, et la taille de ImageView est la même que celle du Bitmap mis à l'échelle :).

Je cherchais à travers cet article pour savoir comment le faire, et j'ai finalement fait ce que je voulais, pas la manière décrite ici.

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

puis dans la méthode 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;
}

puis code 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);

}

Et le résultat est que l'image s'intègre parfaitement à l'intérieur, en conservant le rapport hauteur / largeur, et n'a pas de pixels restants supplémentaires d'ImageView lorsque le Bitmap est à l'intérieur.

Résultat

Il est important que ImageView ait wrap_content et AdjustViewBounds sur true, puis setMaxWidth et setMaxHeight fonctionneront, ceci est écrit dans le code source de 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

J'avais besoin de faire cela dans une mise en page de contraintes avec Picasso, alors j'ai mélangé certaines des réponses ci-dessus et j'ai trouvé cette solution (je connais déjà le rapport hauteur / largeur de l'image que je charge, ce qui aide):

Appelé dans mon code d'activité quelque part après 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...
    }
}

Dans mon 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>

Notez l'absence d'attribut constraintBottom_toBottomOf. ImageLoader est ma propre classe statique pour les méthodes et les constantes utilitaires de chargement d'images.


0

J'utilise une solution très simple. Voici mon code:

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

Mes images sont ajoutées dynamiquement dans une grille. Lorsque vous effectuez ces réglages pour la vue d'image, l'image peut être automatiquement affichée dans un rapport 1: 1.


0

Utilisez des mathématiques simples pour redimensionner l'image. soit vous pouvez redimensionner, ImageViewsoit redimensionner l'image dessinable que définie sur ImageView. recherchez la largeur et la hauteur de votre bitmap que vous souhaitez définir ImageViewet appelez la méthode souhaitée. supposons que votre largeur 500 soit supérieure à la hauteur de la méthode d'appel

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

Vous utilisez cette classe pour redimensionner le bitmap.

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

le code xml est

<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

Réponse rapide:

<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" />
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.