2011-09-20 17 views
18

Mam obraz, który jest mniejszy niż kontener, w którym chciałbym go zmieścić. Chciałbym rozciągnąć obraz, zachowując jego proporcje, do jego największej możliwej wielkości.Jak zrobić obraz tak duży, jak to możliwe, zachowując proporcje obrazu

Aby zilustrować problem:

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

ImageView powyżej byłby rozciągnięty do wypełnienia szerokości pojemnika. Zawarte w nim @drawable będzie również rozciągać się wzdłuż osi x, aby pasować do szerokości ImageView, która jest idealna. Problem polega jednak na tym, że wymiar oznaczony jako wrap_content, w tym przypadku wysokość, pozostaje tej samej wielkości co początkowa wysokość @drawable.

Czytałem dokumentację dotyczącą ScaleType here i nie może znaleźć tam odpowiedź.

Poniższy rysunek opisano powyżej kod:

enter image description hereenter image description here

Current behaviour    Desired Behaviour 

Edycja

ImageView podane scaleType="fitCenter" będzie dokładnie rozwinąć/zmniejszyć @drawable wewnątrz niego rośnie tak duże, jak to możliwe, gdy zachowujesz jego współczynnik proporcji.

Wymiary są zdefiniowane przed skalowaniem w jakikolwiek sposób @drawable. Wymiary ImageView nie są zmieniane przez skalowanie zawierającym @drawable.

+2

Dla mnie to jest powszechny problem, któremu nigdy nie udało się znaleźć czystego rozwiązania. Dodaj w tle 9-plaster dla ramki, a jeszcze gorzej, aby spróbować naprawić. Jestem pewien, że to jest coś, co trzeba zrobić programowo, ale będzie miło, jeśli ktoś ma na to rozwiązanie. – kcoppock

+2

+1 dla w pełni opisanego pytania – Merlin

Odpowiedz

7

XML

Jedynym rozwiązaniem tego XML jest użycie "match_parent" lub dyskretną wartość maksymalną, zamiast "wrap_content" gdzie to możliwe. To zapewni poprawny rozmiar ImageView, co oznacza, że ​​dodanie scaleType="fitCenter" zapewni, że @drawable będzie wówczas poprawnie skalowany.

Programowo

Jest brzydki, ale można zmienić rozmiar ImageView po jego wymiary zostały podane wartości dyskretnych:

final ImageView thumbnailView = (ImageView) toReturn.findViewById(R.id.thumbnail); 

    ViewTreeObserver thumbnailViewVto = thumbnailView.getViewTreeObserver(); 
    thumbnailViewVto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
     private boolean changed = false; 
     @Override 
     public void onGlobalLayout() { 
      if(!changed) { 
       Drawable image = getResources().getDrawable(R.drawable.thumbnail); 
       float heighToWidthRatio = image.getIntrinsicWidth()/image.getIntrinsicHeight(); 
       int height = thumbnailView.getHeight(); 

       thumbnailView.setLayoutParams(
         new LayoutParams(
           (int) (height * heighToWidthRatio), height)); 
       changed = true; 
      } 
     } 
    }); 

EDIT

final ImageView thumbnailView = (ImageView) toReturn.findViewById(R.id.thumbnail); 

    thumbnailView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 

     @Override 
     public void onGlobalLayout() { 
      // Remove the GlobalOnLayout Listener so it only fires once. 
      thumbnailView.getViewTreeObserver().removeGlobalOnLayoutListener(this) 

      // Find the images Height to Width ratio 
      Drawable image = getResources().getDrawable(R.drawable.thumbnail); 
      float heighToWidthRatio = image.getIntrinsicWidth()/image.getIntrinsicHeight(); 

      // Use this ratio to discover the ratio of the ImageView to allow it to perfectly contain the image. 
      int height = thumbnailView.getHeight(); 
      thumbnailView.setLayoutParams(new LayoutParams(
           (int) (height * heighToWidthRatio), height)); 
     } 
    }); 
+1

+1 za rozwiązanie typowego problemu – Merlin

+0

Do czego służy zmienna boolowska 'zmieniona'? – BornToCode

+0

Jest tak, że słuchacz onGlobalLayout nie uruchamia się wielokrotnie. Starsze i mądrzejsze, teraz po prostu usunę "OnGlobalLayoutListener" z 'ViewTreeObserver' jako pierwszą akcję w metodzie' onGlobalLayout() '. (Zobacz moją edycję po szczegóły) – Graeme

1

Wygląda na to, że chcesz dopasować centrum, które używa Matrix.ScaleToFit CENTER.

+0

To zachowanie ma proporcje, ale obraz nie jest już wypełniony.To działałoby, gdyby wysokość ImageView była prawidłowa, co można zrobić programowo, ale chciałbym, aby stało się to przez XML. – Graeme

+0

@Graeme - Z linku: "Oblicz skalę, która zachowa oryginalny współczynnik proporcji src, ale zapewni również, że src zmieści się całkowicie w dst. * Dokładnie dopasuje co najmniej jedną oś (X lub Y). * Wynik jest równy. wyśrodkowany wewnątrz dst. " - Ich opis zdaje się sugerować, że obraz zostanie rozciągnięty w celu wypełnienia szerokości lub wysokości. Może tylko kurczy się dopasować, ale nie rozciąga się, aby dopasować? – mbeckish

+0

Ten opis jest dokładnie poprawny - ponieważ jeden z wymiarów jest ustawiony na "wrap_content", jednak inicjalizacja rozmiaru obrazu wydaje się zdarzyć przed skalowaniem, dlatego wysokość widoku jest już ustawiona i używa najmniejszej osi do dopasowania do bez powiększania. – Graeme

Powiązane problemy