web-dev-qa-db-fra.com

Adapter l'image à ImageView, conserver les proportions, puis redimensionner ImageView aux dimensions de l'image?

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

  • Les dimensions initiales ImageView sont 250dp * 250dp
  • La plus grande dimension de l'image doit être augmentée/réduite à 250dp
  • L'image doit conserver son format
  • Les dimensions ImageView 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 la ImageView doivent être 166 * 250.
Par exemple. pour une image de 150 * 100, l'image et la ImageView doivent ê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 tiennent correctement dans la ImageView, mais la ImageView est toujours de 250dp * 250dp.

143
jul

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

Après clarifications:
Ce ne peut pas être fait en XML seulement. Il n'est pas possible de redimensionner à la fois l'image et la ImageView de sorte que la seule dimension de l'image soit toujours 250dp et que la ImageView ait les mêmes dimensions que l'image.

Ce code met à l'échelleDrawable d'une ImageView pour rester dans un carré tel que 250dp x 250dp avec une dimension de 250dp exactement et en conservant les proportions. La ImageView est ensuite redimensionnée pour correspondre aux dimensions de l'image redimensionnée. Le code est utilisé dans une activité. Je l'ai testé via un gestionnaire de clic sur le 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 la 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


UPDATE 7 novembre 2012:
Ajout d'une vérification du pointeur null comme suggéré dans les commentaires

131
Jarno Argillander

Peut-être pas une réponse pour cette question spécifique, mais si quelqu'un, comme moi, cherche une réponse, comment ajuster une image dans ImageView avec une taille limitée (par exemple, maxWidth) tout en préservant le rapport d'aspect, puis en éliminant l'espace excessif occupé par ImageView, la solution la plus simple consiste alors à utiliser les propriétés suivantes en XML:

    Android:scaleType="centerInside"
    Android:adjustViewBounds="true"
201
Sarge Borsch
<ImageView Android:layout_width="match_parent"
           Android:layout_height="wrap_content"
           Android:scaleType="centerCrop"
           Android:adjustViewBounds="true"/>
35
diesel

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

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.

21
Naresh Sharma

essayez d’ajouter Android:scaleType="fitXY" à votre ImageView.

11
DeeFour

Après avoir cherché pendant une journée, je pense que c'est la solution la plus simple:

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

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"/>
5
Nikita Vishwakarma

Utilisez ce code:

<ImageView Android:id="@+id/avatar"
           Android:layout_width="fill_parent"
           Android:layout_height="match_parent"
           Android:scaleType="fitXY" />
4
Abhay Anand

tout cela peut être fait en utilisant XML ... les autres méthodes semblent assez compliquées ... De toute façon, il vous suffit de définir la hauteur de votre choix dans dp, puis de définir 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
Thunderstick

Édité Jarno Argillanders answer:

Comment adapter l’image à votre largeur et votre hauteur:

1) Initialiser ImageView et définir l'image:

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

2) maintenant redimensionner:

scaleImage(iv);

Méthode scaleImage modifiée: (vous pouvez remplacer les valeurs englobantes 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" />
4
Volodymyr Kulyk

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"
                />
3
Ronny Kibet

J'avais besoin d'un ImageView et d'un bitmap, de sorte que le bitmap soit redimensionné à la taille d'ImageView et que sa taille soit identique à celle du bitmap redimensionné :).

Je cherchais dans ce billet comment faire et, finalement, j'ai fait ce que je voulais, mais pas de 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, tout en conservant le rapport de format, .__, et ne laisse pas de pixels supplémentaires laissés par ImageView lorsque le bitmap est à l'intérieur.

Résultat

Il est important que ImageView ait Wrap_content et adjustViewBounds égal à true, Alors setMaxWidth et setMaxHeight fonctionneront, cela 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. */
1
alekshandru

Utilisez Simple math pour redimensionner l'image. soit vous pouvez redimensionner ImageView ou vous pouvez redimensionner une image dessinable par rapport à ImageView. Recherchez la largeur et la hauteur de votre bitmap que vous souhaitez définir sur ImageView et appelez la méthode souhaitée. supposons que votre largeur 500 soit supérieure à la hauteur de la méthode call

//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
Ritesh Namdev

J'avais besoin de faire cela dans une mise en page de contraintes avec Picasso, alors j'ai rassemblé certaines des réponses ci-dessus et j'ai trouvé cette solution (je connais déjà le format 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 d'utilisation de chargement d'image.

0
the_dude_abides

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 un gridview. Lorsque vous définissez ces paramètres dans la visualisation d'image, l'image peut être automatiquement affichée au format 1: 1.

0
Bilal Demir