Android: Çekilebilir bir resmi mi yoksa arka plan resmini mi ölçeklendirin?


134

Bir düzende, arka plan görüntüsünü (en boy oranını koruyarak) sayfa oluşturulduğunda ayrılan alana ölçeklemek istiyorum. Bunun nasıl yapılacağına dair bir fikri olan var mı?

Kırpma ve doldurma için ayarlamak için layout.setBackgroundDrawable()ve a kullanıyorum , ancak ölçekleme için herhangi bir seçenek görmüyorum.BitmapDrawable()gravity


Bu sorunu yaşadım ve Dweebo'nun önerisini Anke'nin önerdiği değişiklikle takip ettim: fitXY'yi fitCenter olarak değiştirdim. İyi çalıştı.

Yanıtlar:


90

Arka plan görüntüsü ölçeklendirmeyi özelleştirmek için aşağıdaki gibi bir kaynak oluşturun:

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

Ardından, arka plan olarak kullanılırsa görünümde ortalanacaktır. Başka işaretler de var: http://developer.android.com/guide/topics/resources/drawable-resource.html


6
Bit eşlem kullanmayı denedim, ancak görüntü Sam'in istediği gibi ölçeklenmedi, basitçe ortalandı. ImageView'ı kullandığımda, güzel çalışıyor, karışıklık / karışıklık yok. (nb: Benim durumumda da kaydırma yapmıyorum.) Görüntüyü ölçeklendirmek için bitmap'i neyle büyütebilirim?
Joe D'Andrea

7
Olası değerler şunlardır: "top" | "alt" | "sol" | "doğru" | "center_vertical" | "fill_vertical" | "center_horizontal" | "fill_horizontal" | "merkez" | "doldur" | "clip_vertical" | "clip_horizontal"
Aleks N.

30
Bu parametrelerin hiçbiri en boy oranını koruyarak bitmap'i ölçeklendirmez, bu nedenle yanıt yanlıştır.
Malachiasz

7
Sevgili Malachiasz, 'merkez' en-boy oranına saygı duyar. Ancak görüntüyü küçültmez. Bu, kullanımı biraz tehlikeli bir özellik olduğu anlamına gelir. Hedefin çözünürlüğüne bağlı olarak, bir şeyin tam olarak nasıl çıkacağını asla bilemezsiniz. Google'dan bir başka yarım yamalak çözüm.

2
scaleType özelliğini eklemenin bir yolu var mı?
ademar111190

57

Tam olarak istediğiniz şeyi yapmaya çalışmadım, ancak bir ImageView'ı kullanarak ölçekleyebilirsiniz ve ImageView'e android:scaleType="fitXY"
verdiğiniz boyuta uyacak şekilde boyutlandırılacaktır.

Böylece mizanpajınız için bir FrameLayout oluşturabilir, ImageView'ü içine yerleştirebilir ve ardından FrameLayout'ta ihtiyacınız olan diğer içeriği ve şeffaf bir arka planla birlikte kullanabilirsiniz.

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

1
Bunu bir Yüzeyde yapmak mümkün mü? Değilse, FrameLayout kullanarak önizlemeyi (bir kayıt cihazı uygulaması için) gösterebilir miyim?
Namratha

1
@dweebo: Bunu denedin mi? Benim için işe yaramıyor gibi görünüyor.
speedplane

3
Bir yerine iki UI bileşeni kullanmak, özellikle ListView gibi yoğun bileşenler için kötü bir fikir olduğu için olumsuz oy verildi. Büyük olasılıkla kaydırırken sorun yaşarsınız. Doğru çözüm: stackoverflow.com/a/9362168/145046
Aleks N.

ScaleType fitCenter ve centerCrop'u denedim (farklı yoğunluklar için birkaç çizim / resim varyasyonuyla birlikte) ve işe yaradı! Her iki ölçek türü de benim için anlamlıydı - sanırım daha çok görüntüye dayalı kişisel bir tercih. FrameLayout yerine birleştirme kullandığımı ve benim özel durumumda kaydırma olmadığını unutmayın.
Joe D'Andrea

2
fitXY görüntünün en boy oranını korumadığından centerInside uygun, fitXY değil
Malachiasz

35

Bunu çekmeceden yapmanın kolay bir yolu var:

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>

Tek dezavantajı, yeterli alan yoksa, görüntünüz tam olarak gösterilmeyecek, ancak kırpılacak, bunu doğrudan bir çekmeceden yapmanın bir yolunu bulamadım. Ancak yaptığım testlerden oldukça iyi çalışıyor ve görüntünün çoğunu kırpmıyor. Yerçekimi seçenekleriyle daha fazla oynayabilirsiniz.

Başka bir yöntem de, bir kullanacak bir düzen oluşturmak için olacak ImageViewve set scaleTypeiçin fitCenter.


2
Bu çözüm kesinlikle temamın arka plan özelliğini değiştirmek ve görünümde Sekmeler olduğunda veya olmadığında farklı görüntü ölçeğinden kaçınmak için uzun zamandır aradığım şeydi. Bunu paylaştığın için teşekkürler
Bibu

1
Şu hatayı gösteriyor:error: <item> must have a 'name' attribute.
Dmitry

thx @lonutNegru, +1 günümü kurtardığın için :)
Ravi Vaniya

18

Boy kullanmak zorunda oranını tutmak için android:scaleType=fitCenterya da fitStartkullanma vbfitXY resmin orijinal en boy oranı tutmak olmaz!

Bunun srcarka plan resmi için değil, yalnızca özniteliğe sahip resimlerde işe yaradığını unutmayın .


18

Görüntüyü mizanpaja göre boyutlandırılmış arka plan olarak kullanın:

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

Teşekkürler! Ayrıca android:scaleType="centerCrop"çalışır.
CoolMind

5

setBackgroundDrawableYöntemi kullanarak bir ImageView'ın Çizilebilirliğini ayarladığınızda, görüntü her zaman ölçeklenecektir. adjustViewBoundsFarklı veya farklı parametreler ScaleTypesgöz ardı edilecektir. Bulduğum en boy oranını korumak için tek çözüm ImageView, çekilebilir dosyanızı yükledikten sonra yeniden boyutlandırmaktır . İşte kullandığım kod pasajı:

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

Yukarıdaki kod parçacığında bmp gösterilecek olan bit eşlem nesnesi ve imageview olduğuImageView nesne

Dikkat edilmesi gereken önemli bir nokta, yerleşim parametrelerinin değişmesidir . Bu gereklidir, çünkü setMaxHeightve setMaxWidthgenişlik ve yükseklik üst doldurmak için değil, içerik sarmak için tanımlanırsa sadece fark yaratacak. Öte yandan üst üste doldur, başlangıçta istenen ayardır, çünkü aksi takdirde containerWidthvecontainerHeight her iki değer size ImageView için böyle bir şey olacak senin düzen dosyasında, 0. So için eşit olacaktır:

...
<ImageView android:id="@+id/my_image_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>
...

4

Bu en performanslı çözüm değildir, ancak arka plan yerine birisinin önerdiği gibi, FrameLayout veya RelativeLayout oluşturabilir ve ImageView'u sözde arka plan olarak kullanabilirsiniz - diğer öğeler basitçe onun üzerinde konumlandırılacaktır:

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

ImageView ile ilgili sorun, yalnızca mevcut scaleType'ların şunlardır: 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 )

ve bazı durumlarda, bir görüntünün tüm ekranı doldurmasını istediğinizde (örneğin, arka plan görüntüsü) ve ekranın en boy oranının görüntününkinden farklı olması durumunda, "arka plan görüntüsünü ölçeklemek (en boy oranını koruyarak)" için gerekli scaleType türdür TOP_CROP içinde, çünkü:

CENTER_CROP, üst kenarı görüntü görünümünün üst kenarına hizalamak yerine ölçeklenen görüntüyü ortalar ve FIT_START ekran yüksekliğine sığar ve genişliği doldurmaz. Ve Anke kullanıcısının farkına göre FIT_XY en boy oranını korumuyor.

Memnuniyetle birisi ImageView'u TOP_CROP'u destekleyecek şekilde genişletti

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

Şimdi, birisi görüntüyü bu şekilde ölçeklendiren özel Drawable yazarsa IMHO mükemmel olurdu. Daha sonra arka plan parametresi olarak kullanılabilir.


Reflog, kullanmadan önce çekilebilirliği önceden ölçeklendirmenizi önerir. İşte bunun nasıl yapılacağına dair talimat: Java (Android): Bitmap olmadan bir çizim nasıl ölçeklenir? Dezavantajı olmasına rağmen, yükseltilmiş çekilebilir / bitmap daha fazla RAM kullanır, ImageView tarafından kullanılan anında ölçeklendirme daha fazla bellek gerektirmez. Avantaj, daha az işlemci yükü olabilir.


Güzel bir! Tam olarak peşinde olduğum şeyi yapıyor: genişliği orantılı olarak artırarak ve görüntünün altından kırparak tüm ekranı dolduracak arka plan görüntüsü.
CMash

4

Aşağıdaki kod, bitmap'i görüntü görünümüyle aynı boyutta mükemmel hale getirir. Bitmap görüntü yüksekliğini ve genişliğini alın ve ardından yeni yükseklik ve genişliği, görüntü izleme parametrelerinin yardımıyla hesaplayın. Bu, size en iyi en boy oranına sahip gerekli görüntüyü verir.

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)

2

Dweebo'nun önerdiği işe yarıyor. Ama alçakgönüllü görüşüme göre gereksiz. Arka plan çekilebilirliği kendi kendine iyi ölçeklenir. Görünüm, aşağıdaki örnekte olduğu gibi sabit genişliğe ve yüksekliğe sahip olmalıdır:

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

2
Anladığım kadarıyla, bir arka plan bir görünümü doldurmak için genişler, ancak küçülmez.
Edward Falk

1

Denemek için bir seçenek, resmi drawable-nodpi klasöre bir düzenin arka planını çekilebilir kaynak kimliğine ayarlamaktır.

Bu kesinlikle ölçek küçültme ile çalışıyor, yine de ölçek büyütmeyi test etmedim.


0

Kotlin:

Bir Görünümde bir bit eşlem çizmeniz gerekirse, FIT olarak ölçeklendirilir.

Bm genişlik / yükseklik oranının konteyner genişliği / yükseklik oranından daha az olması veya ters senaryoda tersi durumda bm'yi konteynere eşit olarak ayarlamak ve genişliği ayarlamak için uygun hesaplamaları yapabilirsiniz.

Görüntüler:

Örnek Resim 1

Örnek Resim 2

// 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())
}

-4

arka plan olarak kullanmadan önce bu çekilebilirliği önceden ölçeklendirmeniz gerekecek


Bu gerçekten tek seçenek mi? ImageView'u yerleştirmek için ekran boyutunu belirleyebilecek bir konteyner türü yok mu?
GrkEngineer

SurfaceView ile de sorun yaşıyorum
AZ_

3
İOS'ta olduğu gibi en boy uydurma, görünüm dolgusu, sol üst, üst vb. Gibi bir şey yok mu? That sucks ..
Maciej Swic

@ Aleksej'in dediği gibi, gerçek olmayan bir cevap.
öğrenci

-5

Aşağıdakilerden birini kullanabilirsiniz:

android: yerçekimi = "fill_horizontal | clip_vertical"

Veya

android: yerçekimi = "fill_vertical | clip_horizontal"

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.