W układzie chcę przeskalować obraz tła (zachowując jego proporcje) do miejsca przydzielonego podczas tworzenia strony. Czy ktoś ma pomysł jak to zrobić?
Używam layout.setBackgroundDrawable()
i a BitmapDrawable()
do ustawiania gravity
przycinania i wypełniania, ale nie widzę żadnej opcji skalowania.
Odpowiedzi:
Aby dostosować skalowanie obrazu tła, utwórz taki zasób:
<?xml version="1.0" encoding="utf-8"?> <bitmap xmlns:android="http://schemas.android.com/apk/res/android" android:gravity="center" android:src="@drawable/list_bkgnd" />
Następnie zostanie wyśrodkowany w widoku, jeśli zostanie użyty jako tło. Istnieją również inne flagi: http://developer.android.com/guide/topics/resources/drawable-resource.html
źródło
Nie próbowałem robić dokładnie tego, co chcesz, ale możesz skalować ImageView za pomocą
android:scaleType="fitXY"
i będzie on dopasowany do dowolnego rozmiaru, który nadasz ImageView.
Możesz więc utworzyć FrameLayout dla swojego układu, umieścić w nim ImageView, a następnie dowolną inną zawartość, której potrzebujesz w FrameLayout, z przezroczystym tłem.
<FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent"> <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:src="@drawable/back" android:scaleType="fitXY" /> <LinearLayout>your views</LinearLayout> </FrameLayout>
źródło
Można to zrobić w łatwy sposób z poziomu rysunku:
your_drawable.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@color/bg_color"/> <item> <bitmap android:gravity="center|bottom|clip_vertical" android:src="@drawable/your_image" /> </item> </layer-list>
Jedynym minusem jest to, że jeśli nie ma wystarczającej ilości miejsca, obraz nie zostanie w pełni pokazany, ale zostanie przycięty, nie mogłem znaleźć sposobu, aby to zrobić bezpośrednio z rysunku. Ale z testów, które zrobiłem, działa całkiem dobrze i nie przycina zbyt dużej części obrazu. Możesz grać więcej z opcjami grawitacji.
Innym sposobem będzie po prostu stworzyć układ, gdzie można użyć
ImageView
i ustawićscaleType
sięfitCenter
.źródło
error: <item> must have a 'name' attribute.
Aby zachować proporcje trzeba użyć
android:scaleType=fitCenter
lubfitStart
itd. UżywaniefitXY
nie będzie zachować oryginalne proporcje obrazu!Zauważ, że działa to tylko dla obrazów z
src
atrybutem, a nie dla obrazu tła.źródło
Użyj obrazu jako tła dopasowanego do układu:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/imgPlaylistItemBg" android:layout_width="match_parent" android:layout_height="match_parent" android:adjustViewBounds="true" android:maxHeight="0dp" android:scaleType="fitXY" android:src="@drawable/img_dsh" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > </LinearLayout> </FrameLayout>
źródło
android:scaleType="centerCrop"
Działa również .Po ustawieniu Drawable z ImageView przy użyciu
setBackgroundDrawable
metody obraz będzie zawsze skalowany. Parametry jakoadjustViewBounds
lub różneScaleTypes
będą po prostu ignorowane. Jedynym rozwiązaniem, aby zachować proporcje, które znalazłem, jest zmiana rozmiaruImageView
po załadowaniu rysunku. Oto fragment kodu, którego użyłem:// bmp is your Bitmap object int imgHeight = bmp.getHeight(); int imgWidth = bmp.getWidth(); int containerHeight = imageView.getHeight(); int containerWidth = imageView.getWidth(); boolean ch2cw = containerHeight > containerWidth; float h2w = (float) imgHeight / (float) imgWidth; float newContainerHeight, newContainerWidth; if (h2w > 1) { // height is greater than width if (ch2cw) { newContainerWidth = (float) containerWidth; newContainerHeight = newContainerWidth * h2w; } else { newContainerHeight = (float) containerHeight; newContainerWidth = newContainerHeight / h2w; } } else { // width is greater than height if (ch2cw) { newContainerWidth = (float) containerWidth; newContainerHeight = newContainerWidth / h2w; } else { newContainerWidth = (float) containerHeight; newContainerHeight = newContainerWidth * h2w; } } Bitmap copy = Bitmap.createScaledBitmap(bmp, (int) newContainerWidth, (int) newContainerHeight, false); imageView.setBackgroundDrawable(new BitmapDrawable(copy)); LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); imageView.setLayoutParams(params); imageView.setMaxHeight((int) newContainerHeight); imageView.setMaxWidth((int) newContainerWidth);
W powyższym fragmencie kodu bmp to obiekt Bitmap, który ma być wyświetlany, a imageView to
ImageView
obiektWażną rzeczą, na którą należy zwrócić uwagę, jest zmiana parametrów układu . Jest to konieczne, ponieważ
setMaxHeight
isetMaxWidth
będzie miało znaczenie tylko wtedy, gdy szerokość i wysokość są zdefiniowane tak, aby zawijać zawartość, a nie wypełniać element nadrzędny. Z drugiej strony Fill parent jest pożądanym ustawieniem na początku, ponieważ w przeciwnym raziecontainerWidth
icontainerHeight
oba będą miały wartości równe 0. Tak więc w pliku układu będziesz miał coś takiego dla swojego ImageView:... <ImageView android:id="@+id/my_image_view" android:layout_width="fill_parent" android:layout_height="fill_parent"/> ...
źródło
Nie jest to najbardziej wydajne rozwiązanie, ale jak ktoś zasugerował zamiast tła, możesz utworzyć FrameLayout lub RelativeLayout i użyć ImageView jako pseudo tła - inne elementy będą umieszczone tuż nad nim:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="match_parent" android:layout_width="match_parent"> <ImageView android:id="@+id/ivBackground" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:scaleType="fitStart" android:src="@drawable/menu_icon_exit" /> <Button android:id="@+id/bSomeButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginLeft="61dp" android:layout_marginTop="122dp" android:text="Button" /> </RelativeLayout>
Problem z ImageView polega na tym, że dostępne są tylko typy skali: CENTER, CENTER_CROP, CENTER_INSIDE, FIT_CENTER, FIT_END, FIT_START, FIT_XY, MATRIX ( http://etcodehome.blogspot.de/2011/05/android-imageview-scaletype-samples.html )
i aby „przeskalować obraz tła (zachowując proporcje)” w niektórych przypadkach, gdy chcesz, aby obraz wypełnił cały ekran (na przykład obraz tła), a współczynnik proporcji ekranu jest inny niż obraz, wymagany typ skali jest miły z TOP_CROP, ponieważ:
CENTER_CROP centruje przeskalowany obraz zamiast wyrównywać górną krawędź do górnej krawędzi widoku obrazu, a FIT_START dopasowuje się do wysokości ekranu i nie wypełnia szerokości. I jak zauważył użytkownik Anke, FIT_XY nie zachowuje proporcji.
Na szczęście ktoś rozszerzył ImageView o obsługę TOP_CROP
public class ImageViewScaleTypeTopCrop extends ImageView { public ImageViewScaleTypeTopCrop(Context context) { super(context); setup(); } public ImageViewScaleTypeTopCrop(Context context, AttributeSet attrs) { super(context, attrs); setup(); } public ImageViewScaleTypeTopCrop(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setup(); } private void setup() { setScaleType(ScaleType.MATRIX); } @Override protected boolean setFrame(int frameLeft, int frameTop, int frameRight, int frameBottom) { float frameWidth = frameRight - frameLeft; float frameHeight = frameBottom - frameTop; if (getDrawable() != null) { Matrix matrix = getImageMatrix(); float scaleFactor, scaleFactorWidth, scaleFactorHeight; scaleFactorWidth = (float) frameWidth / (float) getDrawable().getIntrinsicWidth(); scaleFactorHeight = (float) frameHeight / (float) getDrawable().getIntrinsicHeight(); if (scaleFactorHeight > scaleFactorWidth) { scaleFactor = scaleFactorHeight; } else { scaleFactor = scaleFactorWidth; } matrix.setScale(scaleFactor, scaleFactor, 0, 0); setImageMatrix(matrix); } return super.setFrame(frameLeft, frameTop, frameRight, frameBottom); } }
https://stackoverflow.com/a/14815588/2075875
Teraz IMHO byłoby idealne, gdyby ktoś napisał niestandardowy Drawable, który skaluje obraz w ten sposób. Wtedy może być użyty jako parametr tła.
Reflog sugeruje przeskalowanie rysunku przed jego użyciem. Oto instrukcja, jak to zrobić: Java (Android): jak skalować element do rysowania bez mapy bitowej? Chociaż ma tę wadę, że skalowanie do rysowania / mapy bitowej będzie zużywać więcej pamięci RAM, podczas gdy skalowanie w locie używane przez ImageView nie wymaga więcej pamięci. Zaletą może być mniejsze obciążenie procesora.
źródło
Poniższy kod sprawia, że bitmapa jest idealna z tym samym rozmiarem obrazu. Uzyskaj wysokość i szerokość obrazu bitmapowego, a następnie oblicz nową wysokość i szerokość za pomocą parametrów imageview. To daje wymagany obraz o najlepszym współczynniku proporcji.
int bwidth=bitMap1.getWidth(); int bheight=bitMap1.getHeight(); int swidth=imageView_location.getWidth(); int sheight=imageView_location.getHeight(); new_width=swidth; new_height = (int) Math.floor((double) bheight *( (double) new_width / (double) bwidth)); Bitmap newbitMap = Bitmap.createScaledBitmap(bitMap1,new_width,new_height, true); imageView_location.setImageBitmap(newbitMap)
źródło
To, co zaproponował Dweebo, działa. Ale moim skromnym zdaniem jest to niepotrzebne. Tło do rysowania dobrze się skaluje. Widok powinien mieć stałą szerokość i wysokość, jak w poniższym przykładzie:
< RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/black"> <LinearLayout android:layout_width="500dip" android:layout_height="450dip" android:layout_centerInParent="true" android:background="@drawable/my_drawable" android:orientation="vertical" android:padding="30dip" > ... </LinearLayout> < / RelativeLayout>
źródło
Jedną z opcji do wypróbowania jest umieszczenie obrazu w
drawable-nodpi
folderze i ustawienie tła układu na identyfikator zasobu do rysowania.To zdecydowanie działa ze skalowaniem w dół, chociaż nie testowałem skalowania w górę.
źródło
Kotlin:
Jeśli potrzebujesz narysować bitmapę w Widoku, przeskalowany do FIT.
Możesz wykonać odpowiednie obliczenia, aby ustawić bm wysokość równą kontenerowi i dostosować szerokość, w przypadku gdy stosunek szerokości bm do wysokości jest mniejszy niż stosunek szerokości do wysokości kontenera lub odwrotnie w przeciwnym scenariuszu.
Zdjęcia:
// binding.fragPhotoEditDrawCont is the RelativeLayout where is your view // bm is the Bitmap val ch = binding.fragPhotoEditDrawCont.height val cw = binding.fragPhotoEditDrawCont.width val bh = bm.height val bw = bm.width val rc = cw.toFloat() / ch.toFloat() val rb = bw.toFloat() / bh.toFloat() if (rb < rc) { // Bitmap Width to Height ratio is less than Container ratio // Means, bitmap should pin top and bottom, and have some space on sides. // _____ ___ // container = |_____| bm = |___| val bmHeight = ch - 4 //4 for container border val bmWidth = rb * bmHeight //new width is bm_ratio * bm_height binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth.toInt(), bmHeight) } else { val bmWidth = cw - 4 //4 for container border val bmHeight = 1f/rb * cw binding.fragPhotoEditDraw.layoutParams = RelativeLayout.LayoutParams(bmWidth, bmHeight.toInt()) }
źródło
będziesz musiał wstępnie skalować ten rysunek, zanim użyjesz go jako tła
źródło
Możesz użyć jednego z następujących:
android: gravity = "fill_horizontal | clip_vertical"
Lub
android: gravity = "fill_vertical | clip_horizontal"
źródło