Jak skalować obraz w ImageView, aby zachować proporcje

526

W Androidzie zdefiniowałem ImageView„s”layout_width ma być fill_parent(co zajmuje całą szerokość telefonu).

Jeśli obraz, który umieściłem, ImageViewjest większy niżlayout_width , Android go skaluje, prawda? Ale co z wysokością? Czy po skalowaniu obrazu system Android zachowa proporcje?

Dowiedziałem się, że u góry iu dołu, ImageViewgdy Android skaluje obraz, który jest większy niż ten, jest biała przestrzeń ImageView. Czy to prawda? Jeśli tak, jak mogę wyeliminować tę białą przestrzeń?

Michał
źródło

Odpowiedzi:

799
  1. Tak, domyślnie Android skaluje obraz w celu dopasowania do ImageView, zachowując proporcje. Pamiętaj jednak, aby ustawić obraz na ImageView za pomocą android:src="..."zamiast android:background="...". src=powoduje skalowanie obrazu z zachowaniem współczynnika kształtu, ale background=powoduje skalowanie i zniekształcanie obrazu w celu dopasowania dokładnie do rozmiaru ImageView. (Możesz jednak używać jednocześnie tła i źródła, co może być przydatne w przypadku wyświetlania ramki wokół głównego obrazu za pomocą tylko jednego ImageView.)

  2. Powinieneś także zobaczyć android:adjustViewBounds sprawić, aby ImageView zmienił rozmiar, aby pasował do przeskalowanego obrazu. Na przykład, jeśli masz prostokątny obraz w normalnie kwadratowym ImageView, AdjustViewBounds = true spowoduje, że zmieni on również rozmiar ImageView, aby był również prostokątny. Wpływa to następnie na układ innych widoków wokół ImageView.

    Następnie, jak napisał Samuh, możesz zmienić sposób domyślnego skalowania obrazów za pomocą android:scaleTypeparametru. Nawiasem mówiąc, najłatwiejszym sposobem, aby dowiedzieć się, jak to działa, byłoby po prostu trochę eksperymentować! Pamiętaj tylko, aby spojrzeć na układy w samym emulatorze (lub rzeczywistym telefonie), ponieważ podgląd w Eclipse jest zwykle nieprawidłowy.

Steve Haley
źródło
18
To to samo, właśnie zrobione w kodzie, a nie XML. setImageBitmapjest taki sam jak android:src="..."i setBackground...jestandroid:background="..."
Steve Haley
4
@SuperUser image.setImageDrawable(...)jest również android:src="..."w formacie xml.
PureSpider
11
„Android: adjustViewBounds” to przydatny tutaj do odnotowania! jeśli tego nie dodasz, najprawdopodobniej wystąpią problemy z nieprawidłowym skalowaniem ramki / granic / obrazu w ImageView.
Zły 84
2
src = vs background = była dla mnie różnicą!
Christopher Rathgeb,
21
android:adjustViewBoundsbył ostatnim elementem mojej układanki, dzięki!
themarketka
281

Zobaczyć android:adjustViewBounds.

Ustaw tę wartość na true, jeśli chcesz, aby ImageView dostosowywał swoje granice, aby zachować proporcje rysowania.

Gratzi
źródło
6
To jest poprawna poprawka dla problemu. Mieliśmy to w naszym widoku obrazu, gdzie wysokość zawierała wszystkie te dodatkowe białe znaki. Nie są to „przezroczyste piksele”, ponieważ mieliśmy parametr fill_parent dla szerokości i wrap_content dla wysokości. Jeśli nie masz opcji adjustViewBounds = true, otrzymasz dodatkową spację. Po ustawieniu tej wartości nasz problem zniknął. Dzięki!
christophercotton
3
dzięki, ustawienie tego na src zamiast tła działało idealnie!
Cameron,
Zobacz także jak skalować
mapę
1
Jest to idealne rozwiązanie problemu. Również dla rozmiarów użyj kontenera nadrzędnego, aby ustawić rozmiar i ustaw match_parent w ImageView. To rozwiązuje wiele problemów.
Nimila Hiranya,
+1 za przejście do rzeczy. Początkowo napisałem to w bardziej „potocznym” zdaniu i sof zabronił mi go przedkładać. Zamiast poszarpanych piór poszedł komputer.
Jacksonkr,
168

Wszystkim innym, którzy mają ten konkretny problem. Masz taki ImageView, który chcesz mieć szerokość fill_parenti wysokość proporcjonalnie skalowane:

Dodaj te dwa atrybuty do ImageView:

android:adjustViewBounds="true"
android:scaleType="centerCrop"

I ustaw ImageViewszerokość na fill_parenti wysokość na wrap_content.

Ponadto, jeśli nie chcesz przycinać swojego obrazu, spróbuj tego:

 android:adjustViewBounds="true"
 android:layout_centerInParent="true"
Kevin Parker
źródło
16
Tak, ale twój obraz jest przycięty. Idealne rozwiązanie rozciągałoby się na szerokość, utrzymując proporcje, a nie przycinając. Nie mam pojęcia, dlaczego to musi być takie niepotrzebne ...
Warpzit,
1
Ja też :( Przepraszam, jeśli moje rozwiązanie ci nie pomogło, ale pomogło mi.
Kevin Parker,
2
Kevin, to, co powiedziałeś, było dokładnie tym, czego szukałem, jeśli rozmiar obrazu jest mniejszy niż rozmiar ekranu, zostanie on powiększony i wyśrodkowany, idealny. Dzięki.
Soham,
1
+1, z wyjątkiem „(lub innego View)”. AFAICT żaden inny widok nie ma adjustViewBoundsani scaleTypeatrybutów.
LarsH
co powiesz na używanie Androida: scaleType = "centerInside" zamiast Androida: scaleType = "centerCrop"? Nie spowoduje to również przycięcia obrazu, ale upewni się, że zarówno szerokość, jak i wysokość są mniejsze lub równe szerokości i wysokości widoku obrazu :) Oto dobry wizualny przewodnik po scaletypes: thinkbot.com/blog/android-imageview-scaletype-a-visual- przewodnik
vida
57

Jeśli chcesz, ImageViewaby zarówno skalować w górę, jak i w dół przy zachowaniu odpowiedniego współczynnika proporcji, dodaj to do swojego XML:

android:adjustViewBounds="true"
android:scaleType="fitCenter"

Dodaj to do swojego kodu:

// We need to adjust the height if the width of the bitmap is
// smaller than the view width, otherwise the image will be boxed.
final double viewWidthToBitmapWidthRatio = (double)image.getWidth() / (double)bitmap.getWidth();
image.getLayoutParams().height = (int) (bitmap.getHeight() * viewWidthToBitmapWidthRatio);

Zajęło mi trochę czasu, aby to zadziałało, ale wydaje się, że działa to zarówno w przypadku, gdy obraz jest mniejszy niż szerokość ekranu, jak i większy niż szerokość ekranu, i nie zawiera obrazu.

Kevin
źródło
1
Dlaczego nie po prostu użyć Androida: scaleType = "centerCrop"?
Lukas Batteau,
działa jak urok, dzięki. scaleType zależy od sytuacji, na przykład potrzebowałem właśnie tego.
David
To trochę barbarzyński sposób zmiany rozmiaru widoku. Co się stanie, jeśli granice widoku zmienią się po ustawieniu mapy bitowej na ImageView? Dlatego należy to zrobić w onMeasure (), który można zaimplementować, jeśli utworzysz niestandardową podklasę ImageView.
Aron Lorincz
1
Wszystko, czego potrzebowałem, to fitCenter i adjustViewBounds, reszta kodu przynajmniej dla mnie była niepotrzebna
kingargyle
To działa dla mnie i nie muszę dodawać żadnego kodu. Bez regulacjiViewViewBound, jeśli szerokość obrazu była mniejsza niż szerokość imageView, nie był skalowany, więc wysokość zatrzymywała się na wysokości natywnej, a na szerokości pojawiły się niektóre pasma.
Cristi Băluță
15

To działało dla mnie:

android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="39dip"
android:scaleType="centerCrop"
android:adjustViewBounds ="true"
Mike6679
źródło
10

to rozwiązało mój problem

android:adjustViewBounds="true"
android:scaleType="fitXY"
shafiq-ur-rehman
źródło
Nie zachowuje dla mnie proporcji obrazu.
Dmitry
9

Poniżej kodu Praca ze skalowanym obrazem jako współczynnik kształtu:

Bitmap bitmapImage = BitmapFactory.decodeFile("Your path");
int nh = (int) ( bitmapImage.getHeight() * (512.0 / bitmapImage.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(bitmapImage, 512, nh, true);
your_imageview.setImageBitmap(scaled);
Mukesh Parmar
źródło
8

Spójrz na ImageView.ScaleType, aby kontrolować i zrozumieć sposób zmiany rozmiaru w pliku ImageView. Po zmianie rozmiaru obrazu (przy zachowaniu jego współczynnika proporcji) są szanse, że albo wysokość, albo szerokość obrazu stanie się mniejsza niż ImageViewwymiary.

Samuh
źródło
6

Użyj tych właściwości w ImageView, aby zachować proporcje:

android:adjustViewBounds="true"
android:scaleType="fitXY"

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:adjustViewBounds="true"
    android:scaleType="fitXY"
    />
Atif Mahmood
źródło
Tylko ta odpowiedź pomogła mi. Dzięki!
Dmitry
6

Tak to działało dla mnie w ConstraintLayout:

<ImageView
    android:id="@+id/myImg"
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:scaleType="fitCenter"
    android:adjustViewBounds="true"/>

Następnie w kodzie ustawiam drawable jako:

ImageView imgView = findViewById(R.id.myImg);
imgView.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.image_to_show, null));

To ładnie pasuje do obrazu zgodnie z jego proporcjami i utrzymuje go w środku.

Jeet
źródło
5

Mam obraz mniejszy niż ekran. Aby rozciągnąć go proporcjonalnie do maksimum i wyśrodkować w widoku, musiałem użyć następującego kodu:

<ImageView
    android:id="@+id/my_image"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_centerInParent="true"
    android:adjustViewBounds="true"
    android:layout_weight="1"
    android:scaleType="fitCenter" />

Pamiętaj jednak, że jeśli masz względny układ i niektóre elementy mają być ustawione powyżej lub poniżej ImageView, najprawdopodobniej zostaną one nałożone na obraz.

haloksynat
źródło
4

Jeśli jakość obrazu spada: użyj

android:adjustViewBounds="true"

zamiast

android:adjustViewBounds="true"
android:scaleType="fitXY"
developerSumit
źródło
3

Dla każdego z was, który chce, aby obraz dokładnie pasował do widoku obrazu z odpowiednim skalowaniem i bez przycinania

imageView.setScaleType(ScaleType.FIT_XY);

gdzie imageView jest widokiem reprezentującym twój ImageView

oneConsciousness
źródło
4
Nie, to zmienia proporcje. Dokumenty mówią: „Skaluj niezależnie w X i Y, aby src dokładnie pasował do dst. Może to zmienić współczynnik kształtu src”.
Rose Perrone
Nawiasem mówiąc, tego FIT_XY nie można użyć do zmiany szerokości / wysokości obrazu do wyświetlenia w widoku obrazu.
Zatoka
3

Możesz obliczyć szerokość ekranu. Możesz skalować bitmapę.

 public static float getScreenWidth(Activity activity) {
        Display display = activity.getWindowManager().getDefaultDisplay();
        DisplayMetrics outMetrics = new DisplayMetrics();
        display.getMetrics(outMetrics);
        float pxWidth = outMetrics.widthPixels;
        return pxWidth;
    }

obliczyć szerokość ekranu i skalowaną wysokość obrazu według szerokości ekranu.

float screenWidth=getScreenWidth(act)
  float newHeight = screenWidth;
  if (bitmap.getWidth() != 0 && bitmap.getHeight() != 0) {
     newHeight = (screenWidth * bitmap.getHeight()) / bitmap.getWidth();
  }

Po skalowaniu bitmapy.

Bitmap scaledBitmap=Bitmap.createScaledBitmap(bitmap, (int) screenWidth, (int) newHeight, true);
android_developer
źródło
3

Robiąc to programowo, pamiętaj, aby wywoływać setery we właściwej kolejności:

imageView.setAdjustViewBounds(true)
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP)
lukas
źródło
2

Jeśli chcesz, aby Twój obraz zajmował maksymalną możliwą przestrzeń, najlepszą opcją byłoby

android:layout_weight="1"
android:scaleType="fitCenter"
Mohsen Afshin
źródło
2

Nie potrzebujesz kodu Java. Ty po prostu musisz :

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

Klucz znajduje się w rodzicu dopasowania dla szerokości i wysokości

Romu Dizzy
źródło
1

Spróbuj użyć android:layout_gravityImageView:

android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_vertical|center_horizontal"
android:layout_weight="1"

Powyższy przykład działał dla mnie.

ITisha
źródło
1
android: layout_weight = „1” jest kluczem.
nima
1

Mam algorytm do skalowania mapy bitowej, aby najlepiej dopasować wymiary pojemnika, zachowując jego proporcje. Proszę znaleźć moje rozwiązanie tutaj

Mam nadzieję, że to pomoże komuś zejść z linii!

Parth Kapoor
źródło
0

Używam tego:

<ImageView
android:id="@+id/logo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true"
android:scaleType="centerInside"
android:src="@drawable/logo" />
Flavio Capaccio
źródło
0

w przypadku użycia cardviewdo zaokrąglania imageviewi naprawionego android:layout_heightdla nagłówka działało to dla mnie, aby załadować obrazGlide

    <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:tools="http://schemas.android.com/tools"
             android:layout_width="match_parent"
             android:layout_height="220dp"
             xmlns:card_view="http://schemas.android.com/apk/res-auto"
             >

    <android.support.v7.widget.CardView
            android:id="@+id/card_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center|top"
            card_view:cardBackgroundColor="@color/colorPrimary"
            card_view:cardCornerRadius="10dp"
            card_view:cardElevation="10dp"
            card_view:cardPreventCornerOverlap="false"
            card_view:cardUseCompatPadding="true">

        <ImageView
                android:adjustViewBounds="true"
                android:maxHeight="220dp"
                android:id="@+id/iv_full"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:scaleType="fitCenter"/>

    </android.support.v7.widget.CardView>
</FrameLayout>
lvl4fi4
źródło
0

Możesz skalować obraz, co również zmniejszy jego rozmiar. Istnieje biblioteka, którą można pobrać i używać. https://github.com/niraj124124/Images-Files-scale-and-compress.git

Jak korzystać 1) Zaimportuj kompresor-v1.0. słoik do twojego projektu. 2) Dodaj poniższy przykładowy kod do przetestowania. ResizeLimiter resize = ImageResizer.build (); resize.scale („inputImagePath”, „outputImagePath”, imageWidth, imageHeight); Istnieje wiele innych metod, zgodnie z Twoimi wymaganiami

Niraj
źródło
0

Przekaż ImageView i na podstawie wysokości i szerokości ekranu możesz to zrobić

    public void setScaleImage(EventAssetValueListenerView view){
        // Get the ImageView and its bitmap
        Drawable drawing = view.getDrawable();
        Bitmap bitmap = ((BitmapDrawable)drawing).getBitmap();
        // Get current dimensions
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        float xScale = ((float) 4) / width;
        float yScale = ((float) 4) / height;
        float scale = (xScale <= yScale) ? xScale : yScale;

        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);

        Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
        BitmapDrawable result = new BitmapDrawable(scaledBitmap);
        width = scaledBitmap.getWidth();
        height = scaledBitmap.getHeight();

        view.setImageDrawable(result);

        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
        params.width = width;
        params.height = height;
        view.setLayoutParams(params);
    }

ppreetikaa
źródło
0

Szybka odpowiedź:

<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
źródło
-5
imageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 130, 110, false));
użytkownik2099162
źródło