Vektörüm neden beklendiği gibi ölçeklenemiyor?


98

Android uygulamamda vektör çekmecelerini kullanmaya çalışıyorum. Gönderen http://developer.android.com/training/material/drawables.html (vurgu mayın):

Android 5.0 (API Seviye 21) ve üzeri sürümlerde, tanımı kaybetmeden ölçeklenen vektör çekilebilir öğeleri tanımlayabilirsiniz .

Bu çekmeceyi kullanarak:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="@color/colorPrimary" android:pathData="M14,20A2,2 0 0,1 12,22A2,2 0 0,1 10,20H14M12,2A1,1 0 0,1 13,3V4.08C15.84,4.56 18,7.03 18,10V16L21,19H3L6,16V10C6,7.03 8.16,4.56 11,4.08V3A1,1 0 0,1 12,2Z" />

ve bu ImageView:

<ImageView
    android:layout_width="400dp"
    android:layout_height="400dp"
    android:src="@drawable/icon_bell"/>

simgeyi 400 dp'de görüntülemeye çalışırken bu bulanık görüntüyü oluşturur (2015 civarında lolipop çalıştıran büyük bir yüksek çözünürlüklü mobil cihazda):

blurryBellIcon

Çekilebilir vektör tanımındaki genişlik ve yüksekliğin 200 dp'ye değiştirilmesi, 400 dp işlenmiş boyuttaki durumu önemli ölçüde iyileştirir. Ancak, bunu bir TextView öğesi (yani metnin solundaki simge) için bir çekilebilir olarak ayarlamak artık büyük bir simge oluşturur.

Sorularım:

1) Çekilebilir vektörde neden bir genişlik / yükseklik özelliği var? Tüm bunların kayıpsız bir şekilde yukarı ve aşağı ölçeklenmelerinin genişlik ve yüksekliği tanımında anlamsız hale getirmek olduğunu düşündüm.

2) Bir TextView üzerinde 24dp çekilebilir olarak çalışan, ancak aynı zamanda daha büyük görüntüleri kullanmak için iyi ölçeklenen tek bir vektör çekilebilirliği kullanmak mümkün müdür? Örneğin, farklı boyutlarda birden çok vektör çekilebilirliği oluşturmaktan nasıl kaçınabilirim ve bunun yerine işlenmiş gereksinimlerime göre ölçeklenen birini nasıl kullanabilirim?

3) Genişlik / yükseklik özniteliklerini nasıl etkili bir şekilde kullanırım ve görüntü alanı Genişliği / Yükseklik ile arasındaki fark nedir?

Ek detaylar:

  • Cihaz API 22 çalıştırıyor
  • Android Studio v1.5.1'i Gradle sürüm 1.5.0 ile kullanma
  • Manifest derleme ve hedef seviye 23, minimum seviye 15. Ayrıca minimum seviyeyi 21'e çıkarmayı denedim, ancak bu hiçbir fark yaratmadı.
  • APK'nin yeniden derlenmesi (minimum seviye 21'e ayarlı olarak) çekilebilir klasörde tek bir XML kaynağı gösterir. Rasterleştirilmiş görüntüler üretilmez.

Açık olmak gerekirse. Android stüdyo mu kullanıyorsunuz? Android Studio'nun hangi sürümü ve Gradle eklentisinin hangi sürümü? Android Studio'da çekilebilir klasöre sağ tıkladığımda ve New -> Vector Assetonu seçtiğimde vektör görüntü XML'sini çekilebilir klasörüme bırakıyorum. Ancak, oluşturulan APK'yi paketinden çıkarmak için apktool kullanırsam, XML dosyalarının içinde olduğunu drawable-anydpi-v21ve API 21+ cihazlarda doğru şekilde ölçeklendiğini görüyorum . Tarama dosyaları drawable-<mdpi/hdpi/etc>-v4klasörlere yerleştirilir ve API 21+ cihazlarda kullanılmaz (doğru ölçeklendikleri gerçeğine göre)
Cory Charlton

@Cory Charlton. Meraklı. Gradle 1.5.0 ile Studio 1.5.1 kullanıyorum. Minimum seviyeyi 21 olarak değiştirdikten sonra, görüntünün APK'de göründüğü tek yer drawableklasördür. Vektör çizilebilir xml dosyasındaki genişlik / yükseklik 24dp'dir. 400dp yükseklik / genişlikte bir ImageView belirtmek kesinlikle kötü ölçeklendirilmiş bir görüntü oluşturuyor.
Chris Knight

Beklediğim bu. İle sonuçlanmamın tek nedeni drawable-anydpi-v21, benim minSdkVersion21'in altında olmasıdır. 21'den küçük olarak ayarlarsanız davranışta herhangi bir değişiklik olur minSdkVersionmu? XML'i konumuna taşımaya ne dersiniz drawable-anydpi? Bir değişiklik olmasını beklemiyorum ama vektör görüntünüzün doğru şekilde ölçeklenmesini de beklerdim ...
Cory Charlton

Minimum sürümü 15'e geri döndürmek sizinle aynı sonuçları verir. drawable-anydpi-v21Mdi / hdpi / etc içinde çeşitli rasterleştirilmiş görüntülerin bulunduğu tek bir xml dosyası . klasörler. Yine de son oluşturulan sonuçta değişiklik yok.
Chris Knight

Çok tuhaf ... Resminizi kullanarak uygulamalarımdan birini değiştirdim ve iyi çalışıyor (düzenlenmiş
Cory Charlton

Yanıtlar:


102

Burada bu sorunla ilgili yeni bilgiler var:

https://code.google.com/p/android/issues/detail?id=202019

Kullanmanın android:scaleType="fitXY"Lollipop'ta doğru şekilde ölçeklenmesini sağlayacak gibi görünüyor .

Bir Google mühendisinden:

Merhaba, Görüntünün net görünmesini sağlamak için scaleType = 'fitXY' sizin için bir geçici çözüm olup olmadığını bana bildirin.

Hatmi Vs Lollipop, marshmallow'a eklenen özel bir ölçeklendirme işleminden kaynaklanmaktadır.

Ayrıca yorumlarınız için: "Doğru davranış: Çizilebilir vektör, kalite kaybı olmadan ölçeklenmelidir. Dolayısıyla, uygulamamızda aynı varlığı 3 farklı boyutta kullanmak istiyorsak, vector_drawable.xml'yi 3 kez farklı bir şekilde çoğaltmamız gerekmez. kodlanmış boyutlar. "

Bunun böyle olması gerektiğine tamamen katılıyorum, gerçekte, Android platformunun henüz ideal dünyaya ulaşamadığımız bir performans endişesi var. Bu yüzden, aynı anda ekrana 3 farklı boyut çizmek istediğinizden eminseniz, daha iyi performans için 3 farklı vector_drawable.xml kullanmanız önerilir.

Teknik ayrıntı, temelde, karmaşık yol oluşturmayı önbelleğe almak için kancanın altında bir bitmap kullanıyoruz, böylece en iyi yeniden çizim performansını, bir bitmap çizilebilirini yeniden çizmeye benzer şekilde elde edebiliriz.


27
Tamam Google, sadece farklı boyutlara sahip aynı görüntü alanlarına ve yollara sahip aynı çekilebilir öğeleri kopyalayıp yapıştırmamız kesinlikle korkunç .
Miha_x64

Bu, logomun pikselli olduğunu gösteren cihazda düzeltildi, ancak daha önce her şeyin yolunda olduğu diğer birimde, şimdi yanlış en boy oranı. Bunun neden bir sorun olduğunu anlamıyorum, bu bir vektör! Piksel değil! : P
tplive

@Harish Gyanani, android: scaleType = "fitXY" sorunu çözüyor peki ya dinamik ve kare olmayan simgeler?
Manuela

29

1) Çekilebilir vektörde neden bir genişlik / yükseklik özelliği var? Tüm bunların kayıpsız bir şekilde yukarı ve aşağı ölçeklenmelerinin genişlik ve yüksekliği tanımında anlamsız hale getirmek olduğunu düşündüm.

Derleme sisteminin tarama görüntüleri oluşturması gereken 21'den küçük SDK sürümleri için ve genişlik / yükseklik belirtmediğiniz durumlarda varsayılan boyut olarak.

2) Bir TextView üzerinde 24dp çizilebilir olarak çalışan tek bir vektör çizimi ve aynı zamanda büyük bir ekrana yakın genişlikte bir resim kullanmak mümkün müdür?

21'den küçük SDK'ları hedeflemeniz gerekiyorsa bunun mümkün olduğuna inanmıyorum.

3) Genişlik / yükseklik özniteliklerini nasıl etkili bir şekilde kullanırım ve görüntü alanı Genişliği / Yükseklik ile arasındaki fark nedir?

Belgeler: (aslında şimdi tekrar okuduğum için pek kullanışlı değil ...)

android:width

Çekilebilir ürünün iç genişliğini tanımlamak için kullanılır. Bu, normalde dp ile belirtilen tüm boyut birimlerini destekler.

android:height

Çekilebilir ürünün iç yüksekliğini tanımlamak için kullanılır. Bu, normalde dp ile belirtilen tüm boyut birimlerini destekler.

android:viewportWidth

Görüntü alanı alanının genişliğini tanımlamak için kullanılır. Görüntü alanı temelde yolların üzerine çizildiği sanal tuvaldir.

android:viewportHeight

Görüntü alanı alanının yüksekliğini tanımlamak için kullanılır. Görüntü alanı temelde yolların üzerine çizildiği sanal tuvaldir.

Daha fazla belge:

Android 4.4 (API seviyesi 20) ve önceki sürümler, vektör çizimlerini desteklemez. Minimum API seviyeniz bu API seviyelerinden birine ayarlanmışsa, Vector Asset Studio ayrıca Gradle'ı geriye dönük uyumluluk için çekilebilir vektörün raster görüntülerini oluşturması için yönlendirir. Vektör varlıklarına DrawableJava kodunda veya @drawableXML kodunda olduğu gibi başvurabilirsiniz ; Uygulamanız çalıştığında, API seviyesine bağlı olarak ilgili vektör veya tarama görüntüsü otomatik olarak görüntülenir.


Düzenleme: Tuhaf bir şeyler oluyor. İşte emülatör SDK sürüm 23'teki sonuçlarım (Lollipop + test cihazı şu anda öldü ...):

6.x'te güzel çanlar

Ve öykünücü SDK sürüm 21'de:

5.x üzerinde berbat çanlar


1
Teşekkürler Cory, bu dokümantasyonu görmüştüm ve ayrıca pek de kullanışlı bulmadım. Cihazım Lollipop (v22) ve yine de boy / ağırlık ImageView'da tam olarak belirtilmiş olsa da olmasa da, grafiğin vektör çizilebilirinde belirtilen 24 dp'nin üzerinde ölçeklenmesini sağlayamıyorum. Hedef ve derleme seviyesi 23 ve minimum seviye 21 olan bir manifest'i test ettim, ancak çekilebilir dosyanın kendi içindeki genişliği / yüksekliği değiştirmeden vektör çekilebilirliğimi sorunsuz bir şekilde yükseltmeyecek. Tek farkı yükseklik / genişlik olan birden fazla çekmeceyi gerçekten oluşturmak istemiyorum!
Chris Knight

1
Onay için teşekkürler ve yardımın için gerçekten minnettarım. Gösterdiğiniz gibi, açıkça beklediğim gibi çalışmalı. Tam kodunuzu kullanmak, başlangıçta sahip olduğumla aynı sonucu verir. Sinir bozucu!
Chris Knight

1
GÜNCELLEME: Kodumu API 22 ile öykünücüye karşı çalıştırdım ve hala aynı sonucu alıyorum. Kodumu API 23 ile öykünücüye karşı çalıştırdı ve tada !, çalışıyor. Görünüşe göre yükseltme yalnızca API 23+ cihazlarda çalışıyor. Hedef SDK sürümünü değiştirmeyi denedim ama bu hiçbir fark yaratmadı.
Chris Knight

Bu sorun için bir çözüm buldunuz mu?
dazza5000

@corycharlton o kaldırmak için iyidir width height viewport heightve widthgelen xml?
VINNUSAURUS

10

AppCompat 23.2, Android 2.1 ve üstünü çalıştıran tüm cihazlar için vektör çekmecelerini sunar. Görüntüler, vektör çizilebilir XML dosyasında belirtilen genişlik / yükseklikten bağımsız olarak doğru şekilde ölçeklenir. Ne yazık ki, bu uygulama API seviyesi 21 ve üzerinde kullanılmaz (yerel uygulama lehine).

İyi haber şu ki, AppCompat uygulamasını 21 ve 22 API seviyelerinde kullanmaya zorlayabiliriz. Kötü haber, bunu yapmak için yansıma kullanmamız gerektiğidir.

Her şeyden önce, AppCompat'ın en son sürümünü kullandığınızdan ve yeni vektör uygulamasını etkinleştirdiğinizden emin olun:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
    compile 'com.android.support:appcompat-v7:23.2.0'
}

Ardından, useCompatVectorIfNeeded();Uygulamanızın onCreate () öğesini arayın :

private void useCompatVectorIfNeeded() {
    int sdkInt = Build.VERSION.SDK_INT;
    if (sdkInt == 21 || sdkInt == 22) { //vector drawables scale correctly in API level 23
        try {
            AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
            Class<?> inflateDelegateClass = Class.forName("android.support.v7.widget.AppCompatDrawableManager$InflateDelegate");
            Class<?> vdcInflateDelegateClass = Class.forName("android.support.v7.widget.AppCompatDrawableManager$VdcInflateDelegate");

            Constructor<?> constructor = vdcInflateDelegateClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            Object vdcInflateDelegate = constructor.newInstance();

            Class<?> args[] = {String.class, inflateDelegateClass};
            Method addDelegate = AppCompatDrawableManager.class.getDeclaredMethod("addDelegate", args);
            addDelegate.setAccessible(true);
            addDelegate.invoke(drawableManager, "vector", vdcInflateDelegate);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

Son olarak, ImageView'unuzun resmini ayarlamak app:srcCompatyerine kullandığınızdan emin olun android:src:

<ImageView
    android:layout_width="400dp"
    android:layout_height="400dp"
    app:srcCompat="@drawable/icon_bell"/>

Vektör çekilebilir öğeleriniz artık doğru şekilde ölçeklenmelidir!


İyi bir yaklaşım, ancak, AppCompat 25.4 (ve belki daha önce) bir tüy bırakma hatası veriyor "sadece aynı kütüphane grubundan çağrılabilir". Kullandığım derleme araçları hala oluşturulmasına izin veriyor, ancak çalışma zamanı sonuçları olup olmadığından emin değilim. Test etmek üzere.
androidguy

yalnızca aynı kitaplık grubundan çağrılabilir, bunu ekleyerek bu hatayı kaldırın: lintOptions {disable 'RestrictedApi'}
Usama Saeed US

6

1) Çekilebilir vektörde neden bir genişlik / yükseklik özelliği var? Tüm bunların kayıpsız bir şekilde yukarı ve aşağı ölçeklenmelerinin genişlik ve yüksekliği tanımında anlamsız hale getirmek olduğunu düşündüm.

Bu, mizanpaj görünümünde tanımlamamanız durumunda vektörün yalnızca varsayılan boyutudur. (yani, görüntü görünümünüzün yüksekliği ve genişliği için sarma içeriği kullanırsınız)

2) Bir TextView üzerinde 24dp çizilebilir olarak çalışan tek bir vektör çizimi ve aynı zamanda büyük bir ekrana yakın genişlikte bir resim kullanmak mümkün müdür?

Evet, mümkün ve çalışan cihaz lolipop veya üstü kullandığı sürece yeniden boyutlandırma konusunda herhangi bir sorun yaşamadım. Önceki API'lerde, uygulamayı oluşturduğunuzda vektör farklı ekran boyutları için pngs'ye dönüştürülür.

3) Genişlik / yükseklik özniteliklerini nasıl etkili bir şekilde kullanırım ve görüntü alanı Genişliği / Yükseklik ile arasındaki fark nedir?

Bu, vektörünüzün etrafındaki boşluğun nasıl kullanıldığını etkiler. Yani bunu, görüntü alanı içindeki vektörün "yerçekimini" değiştirmek, vektörün varsayılan bir marjı olmasını sağlamak, vektörün belirli kısımlarını görüntü alanının dışında bırakmak, vb. için kullanabilirsiniz. Normalde, onları aynı şekilde ayarlarsınız. boyut.


Teşekkürler Emiura. Aynı çekmeceyi kullanarak birden çok işlenmiş boyutu nasıl elde ettiğinizle ilgilenirim. 24dp'lik bir çizilebilir kullanarak (test amaçlı) ImageView'umu belirli bir genişlik ve yüksekliğe sahip olacak şekilde değiştirdim ve Lollipop cihazımda (v22) çalıştırdım, ancak yine de vektör görüntüsü yerine taranmış, büyütülmüş bir görüntü gibi zayıf bir şekilde işliyor. Ayrıca bildirimimi v23 ve min sürüm 21'e karşı hedef ve derleme olacak şekilde değiştirdim. Fark yok.
Chris Knight

Bu durumda, vektör çekilebilir dosyanızda yalnızca en büyük boyutu kullanmanız ve ardından metin görünümünüzde 24 dp boyutunu belirtmeniz gerekir.
emirua

Şimdi görüyorum ki, vektör çizimindeki boyut ile Lollipop'taki mizanpajın boyutu arasında çok büyük farklarla büyüttüğünüzde bulanık görüntüler elde ediyorsunuz. Bununla birlikte, farklı ekran boyutları için bir sürü dosyaya sahip olmaktan ziyade en büyük boyutu ayarlamak hala çok daha düzgün;).
emirua

4

Sorunumu çözüyorum sadece vektör görüntüsünün boyutunu değiştiriyorum. İlk andan itibaren şöyle bir kaynaktı:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:width="24dp"
    android:height="24dp"
    android:viewportHeight="300"
    android:viewportWidth="300">

Ve bunu 150dp olarak değiştirdim (bu vektör kaynağı ile düzende ImageView boyutu):

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:width="150dp"
    android:height="150dp"
    android:viewportHeight="300"
    android:viewportWidth="300">

Benim için çalışıyor.


teşekkürler, bu pikselli göründüğü tabletimdeki sorunu çözmek için yeterli.
user2342558

3

Bunları denemeliyim ama ne yazık ki hiçbiri işe yaramadı. Ben denemek fitXYiçinde ImageViewben kullanmayı deneyin, app:srcCompatancak bu bile onu kullanamaz. ama hileli bir yol buldum:

Çekilebilir'i backgroundsizin ImageView.

Ancak bu yolun amacı, Görüş boyutlarıdır. eğer senin ImageViewboyutları hatalı, çekilebilir Stretch alır. lolipop öncesi sürümlerde kontrol etmeli veya Bazı Görünümleri Kullanmalısınız PercentRelativeLayout.

Umarım yardımcı olur.


2

İlk : svg'yi drawble'a içe aktarın: (( https://www.learn2crack.com/2016/02/android-studio-svg.html ))

1-Çekilebilir klasöre sağ tıklayın Yeni -> Vektör Varlığı'nı seçin

görüntü açıklamasını buraya girin

2- Vector Asset Studio, dahili Malzeme simgelerini veya kendi yerel svg dosyanızı seçme seçeneği sunar. Gerekirse varsayılan boyutu geçersiz kılabilirsiniz.

görüntü açıklamasını buraya girin

İkincisi : Android API 7 + 'dan destek istiyorsanız, Android Destek Kitaplığı kaydını kullanmanız gerekir (( https://stackoverflow.com/a/44713221/1140304 ))

1- ekle

vectorDrawables.useSupportLibrary = true

build.gradle dosyanıza.

2-Düzeninizde imageView olan ad alanını kullanın:

xmlns:app="http://schemas.android.com/apk/res-auto"

Üçüncüsü : android: scaleType = "fitXY" ile imageView'i ayarlayın ve app: srcCompat'ı kullanın

 <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"
        app:srcCompat="@drawable/ic_menu" />

Dördüncüsü : java kodunda svg ayarlamak istiyorsanız, oncreate methoed üzerine aşağıdaki satırı eklemelisiniz

 @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

Çözümünüz API 21 ve üzeri üzerinde çalışıyor mu? Yukarıdaki user3210008, uygulamanın API 21 ve üzerinde kullanılmadığını belirtir.
AJW

2

Benim için vektörlerin png'ye dönüştürülmesinin nedeni, android:fillType="evenodd"vektör çizimimdeki öznitelikti. Ben ne zaman benim çekilebilir Bu özelliğin tüm oluşumlarını kaldırıldı (varsayılan bunun nonzero, bir dahaki sefere vektörü uygulanan dolgu tipi) uygulaması her şey iyiydi inşa edilmiştir.

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.