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.

juil
la source
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

Jarno Argillander
la source
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"
Afficher un nom
la source
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"/>
diesel
la source
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.

Naresh Sharma
la source
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.

DeeFour
la source
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);
MikeyB
la source
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"/>
Nikita Vishwakarma
la source
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">
Thunderstick
la source
4

Utilisez ce code:

<ImageView android:id="@+id/avatar"
           android:layout_width="fill_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY" />
Abhay Anand
la source
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" />
Volodymyr Kulyk
la source
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"
                />
Ronny Kibet
la source
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

Harvinder Singh
la source
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. */
Alekshandru
la source
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.

the_dude_abides
la source
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.

Bilal Demir
la source
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" />
Ritesh Namdev
la source
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" />
myworldbox
la source