Bild in ImageView einpassen, Seitenverhältnis beibehalten und ImageView dann auf Bildgröße ändern?

164

Wie passt man ein Bild von zufälliger Größe an ein an ImageView?
Wann:

  • Die anfänglichen ImageViewAbmessungen betragen 250 dp * 250 dp
  • Die größere Dimension des Bildes sollte auf 250 dp vergrößert / verkleinert werden
  • Das Bild sollte sein Seitenverhältnis beibehalten
  • Die ImageViewAbmessungen sollten nach der Skalierung mit den Abmessungen des skalierten Bildes übereinstimmen

Zum Beispiel für ein Bild von 100 * 150, das Bild und das ImageViewsollte 166 * 250 sein.
Zum Beispiel für ein Bild von 150 * 100 sollte das Bild und das ImageView250 * 166 sein.

Wenn ich die Grenzen setze als

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

Bilder passen richtig in die ImageView, aber die ImageViewist immer 250dp * 250dp.

jul
quelle
Äh, wollen Sie die Größe von ImageViewauf die Bildgröße ändern ? Zum Beispiel würde ein Bild von 100 dp x 150 dp ImageViewauf die gleichen Maße skaliert ? Oder meinst du, wie man das Bild auf die ImageViewGrenzen skaliert ? Beispielsweise würde ein Bild von 1000 dp x 875 dp in 250 dp x 250 dp skaliert. Müssen Sie das Seitenverhältnis beibehalten?
Jarno Argillander
Ich möchte, dass das ImageView die Abmessungen des Bildes hat und das Bild seine größte Abmessung von 250 dp hat und sein Seitenverhältnis beibehält. Zum Beispiel möchte ich für ein Bild von 100 * 150, dass das Bild und die ImageView 166 * 250 sind. Ich werde meine Frage aktualisieren.
jul
Möchten Sie die Skalierung / Anpassung nur durchführen, wenn Sie eine Aktivität anzeigen (einmal ausführen) oder wenn Sie etwas für die Aktivität tun, z. B. ein Bild aus der Galerie / dem Web auswählen (mehrmals ausführen, aber nicht laden) oder beides?
Jarno Argillander
Siehe meine modifizierte Antwort, die genau so tun sollte, wie Sie es gewünscht haben :)
Jarno Argillander

Antworten:

136

(Die Antwort wurde nach Klarstellung der ursprünglichen Frage stark geändert)

Nach Klarstellungen:
Dies kann nicht nur in XML erfolgen . Es ist nicht möglich, sowohl das Bild als auch das Bild ImageViewso zu skalieren , dass die eine Dimension des Bildes immer 250 dp beträgt und ImageViewdie gleichen Abmessungen wie das Bild hat.

Dieser Code skaliert Drawable von a ImageView, um in einem Quadrat wie 250 dp x 250 dp mit einer Dimension von genau 250 dp zu bleiben und das Seitenverhältnis beizubehalten. Dann ImageViewwird die Größe geändert, um den Abmessungen des skalierten Bildes zu entsprechen. Der Code wird in einer Aktivität verwendet. Ich habe es über den Button-Click-Handler getestet.

Genießen. :) :)

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

Der XML-Code für 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"/>


Dank dieser Diskussion für den Skalierungscode:
http://www.anddev.org/resize_and_rotate_image_-_example-t621.html


UPDATE 7. November 2012:
Nullzeigerprüfung hinzugefügt, wie in den Kommentaren vorgeschlagen

Jarno Argillander
quelle
1
Die ImageView ist immer 250 * 250.
jul
2
OK. Das kann nicht nur in XML gemacht werden. Java-Code ist erforderlich. Mit XML können Sie entweder das Bild skalieren oder das ImageView, nicht beide.
Jarno Argillander
92
Ich
2
Ion ist ein Framework für asynchrone Vernetzung und Laden von Bildern
Thomas
1
Java ist eine extrem hässliche Sprache, da für so einfache Aufgaben so viel Code geschrieben werden muss.
Dmitry
245

Möglicherweise keine Antwort auf diese spezielle Frage, aber wenn jemand wie ich nach einer Antwort sucht, wie ein Bild mit begrenzter Größe (z. B. maxWidth) in ImageView angepasst werden kann, während das Seitenverhältnis beibehalten wird, und dann den von ImageView belegten übermäßigen Speicherplatz entfernt Die einfachste Lösung besteht darin, die folgenden Eigenschaften in XML zu verwenden:

    android:scaleType="centerInside"
    android:adjustViewBounds="true"
Anzeigename
quelle
13
Dies funktioniert, wenn das Bild nicht vergrößert werden soll, wenn es zu klein ist.
Janusz
Wie skaliere ich es, wenn es zu klein ist und behalte auch das Seitenverhältnis bei?
Kaustubh Bhagwat
Wenn jemand dies benötigt, ist "fitCenter" ein weiteres Attribut für scaleType. Es skaliert das Bild nicht, aber für jedes große Bild passt es die maximale Größe des Bilds in das Ansichtsfeld, wobei das Seitenverhältnis beibehalten wird
yogesh prajapati
Um kleine Bilder zu vergrößern, verwenden Sie stattdessen scaleType = "centerCrop".
Eaweb
Eine weitere Sache für mich, mit dieser Lösung zu arbeiten, ist die Verwendung von "android: src" und nicht von "android: background", um mein Bild zu refinanzieren.
Codingpan
45
<ImageView android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:scaleType="centerCrop"
           android:adjustViewBounds="true"/>
Diesel
quelle
23

Der folgende Code macht die Bitmap perfekt mit der gleichen Größe der Bildansicht. Holen Sie sich die Höhe und Breite des Bitmap-Bilds und berechnen Sie die neue Höhe und Breite mithilfe der Parameter der Bildansicht. Dadurch erhalten Sie das gewünschte Bild mit dem besten Seitenverhältnis.

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)

genießen.

Naresh Sharma
quelle
3
Dadurch wird nur die ursprüngliche Höhe um denselben Faktor verringert, um den die Breite verringert wurde. Dies garantiert nicht, dass newHeight <ivHeight. Idealerweise sollten Sie überprüfen, welches Verhältnis größer ist (currentBitmapHeight / ivHeight, currentBitmapWidth / ivWidth) und dann auf dieser Grundlage eine weitere Entscheidung treffen.
Sumit Trehan
1
Dies funktioniert tatsächlich perfekt, obwohl Sie weder ivHeight noch newWidth benötigen, sondern stattdessen ivWidth in die Berechnung einbeziehen.
Stuart
14

Versuchen Sie, android:scaleType="fitXY"zu Ihrem hinzuzufügen ImageView.

DeeFour
quelle
5
Dadurch wird das Seitenverhältnis geändert, wenn das Originalbild nicht quadratisch ist.
jul
1
fitXYändert fast immer das Seitenverhältnis des Bildes. OP erwähnt deutlich, dass das Seitenverhältnis beibehalten werden muss.
IcyFlame
7

Nach der Suche nach einem Tag denke ich, dass dies die einfachste Lösung ist:

imageView.getLayoutParams().width = 250;
imageView.getLayoutParams().height = 250;
imageView.setAdjustViewBounds(true);
MikeyB
quelle
2
Vielen Dank für Ihre nette Antwort. Aber ich denke, es ist besser adjustViewBounds, XML hinzuzufügen
7

Die beste Lösung, die in den meisten Fällen funktioniert, ist

Hier ist ein Beispiel:

<ImageView android:id="@+id/avatar"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="fitXY"/>
Nikita Vishwakarma
quelle
1
Verlassen Sie sich nicht auf veraltete API (fill_parent)
fdermishin
Wie beantwortet dies die Frage von OP? Dies wird das Aspet-Verhältnis nicht aufrechterhalten
Alex
6

Dies kann alles mit XML erfolgen ... die anderen Methoden scheinen ziemlich kompliziert zu sein. Wie auch immer, Sie stellen einfach die Höhe in dp auf das ein, was Sie wollen, und stellen dann die Breite ein, um Inhalte zu verpacken oder umgekehrt. Verwenden Sie scaleType fitCenter, um die Größe des Bildes anzupassen.

<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
quelle
4

Verwenden Sie diesen Code:

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

Edited Jarno Argillanders Antwort:

Wie Bild mit Ihrer Breite passen und Höhe:

1) Initialisieren Image und Set Bild:

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

2) Ändern Sie jetzt die Größe:

scaleImage(iv);

Bearbeitete scaleImageMethode: ( Sie können ERWARTETE Begrenzungswerte ersetzen )

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

Und .xml:

<ImageView
    android:id="@+id/iv_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal" />
Volodymyr Kulyk
quelle
Ich denke, diese Besetzung: LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams (); sollte in die andere Richtung gehen, da MarginLayoutParams von ViewGroup.LayoutParams erben.
Jay Jacobs
3

Das hat es für meinen Fall getan.

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

Wenn es bei Ihnen nicht funktioniert, ersetzen Sie android: background durch android: src

android: src wird den großen Streich spielen

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

Es funktioniert gut wie ein Zauber

Geben Sie hier die Bildbeschreibung ein

Harvinder Singh
quelle
1

Ich brauchte eine ImageView und eine Bitmap, damit die Bitmap auf die ImageView-Größe skaliert wird und die Größe der ImageView der skalierten Bitmap entspricht :).

Ich habe in diesem Beitrag nachgesehen, wie es geht, und schließlich getan, was ich will, aber nicht wie hier beschrieben.

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

und dann in der onCreateView-Methode

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

und dann layoutImageView () Code

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

}

Das Ergebnis ist, dass das Bild perfekt hineinpasst, das Seitenverhältnis beibehält und keine zusätzlichen Pixelreste aus ImageView enthält, wenn sich die Bitmap darin befindet.

Ergebnis

Es ist wichtig, dass ImageView wrap_content und adjustViewBounds auf true setzt. Dann funktionieren setMaxWidth und setMaxHeight. Dies ist im Quellcode von ImageView geschrieben.

/*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
quelle
0

Ich musste dies in einem Einschränkungslayout mit Picasso erledigen, also habe ich einige der oben genannten Antworten zusammengestellt und diese Lösung gefunden (ich kenne bereits das Seitenverhältnis des Bildes, das ich lade, das hilft):

Wird irgendwo nach setContentView (...) in meinem Aktivitätscode aufgerufen.

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...
    }
}

In meinem 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>

Beachten Sie das Fehlen eines ConstraintBottom_toBottomOf-Attributs. ImageLoader ist meine eigene statische Klasse zum Laden von Bildern mithilfe von Methoden und Konstanten.

the_dude_abides
quelle
0

Ich benutze eine sehr einfache Lösung. Hier mein 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);

Meine Bilder werden dynamisch in einer Rasteransicht hinzugefügt. Wenn Sie diese Einstellungen in der Bildansicht vornehmen, kann das Bild automatisch im Verhältnis 1: 1 angezeigt werden.

Bilal Demir
quelle
0

Verwenden Sie einfache Mathematik, um die Bildgröße zu ändern. Sie können entweder die Größe ändern ImageViewoder die Größe des zeichnbaren Bilds ändern, als es aktiviert ist ImageView. Suchen Sie die Breite und Höhe Ihrer Bitmap, die Sie festlegen möchten, ImageViewund rufen Sie die gewünschte Methode auf. Angenommen, Ihre Breite 500 ist größer als die Höhe als die Aufrufmethode

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

Sie verwenden diese Klasse zum Ändern der Bitmapgröße.

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-Code ist

<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
quelle
0

Schnelle Antwort:

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