Próbuję użyć rysunków wektorowych w mojej aplikacji na Androida. Z http://developer.android.com/training/material/drawables.html (moje wyróżnienie):
W systemie Android 5.0 (poziom interfejsu API 21) i nowszych można zdefiniować elementy wektorowe, które skalują się bez utraty definicji.
Korzystanie z tego do rysowania:
<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" />
i ten ImageView:
<ImageView
android:layout_width="400dp"
android:layout_height="400dp"
android:src="@drawable/icon_bell"/>
powoduje wyświetlenie tego rozmytego obrazu podczas próby wyświetlenia ikony w rozdzielczości 400 dp (na dużym urządzeniu mobilnym o wysokiej rozdzielczości z około 2015 r., na którym działa Lollipop):
Zmiana szerokości i wysokości w definicji wektora rysowanego do 200dp znacząco poprawia sytuację przy wyrenderowanym rozmiarze 400dp. Jednak ustawienie tego jako możliwego do rysowania dla elementu TextView (tj. Ikony po lewej stronie tekstu) tworzy teraz ogromną ikonę.
Moje pytania:
1) Dlaczego w wektorze do rysowania istnieje specyfikacja szerokości / wysokości? Myślałem, że chodzi o to, że skalują się w górę iw dół bezstratnie, przez co szerokość i wysokość nie mają znaczenia w swojej definicji?
2) Czy możliwe jest użycie pojedynczego wektora do rysowania, który działa jako rysowany w formacie 24dp na TextView, ale dobrze skaluje się, aby używać również znacznie większych obrazów? Np. Jak uniknąć tworzenia wielu rysunków wektorowych o różnych rozmiarach i zamiast tego użyć takiego, który skaluje się do moich renderowanych wymagań?
3) Jak efektywnie wykorzystać atrybuty szerokości / wysokości i jaka jest różnica z viewportWidth / Height?
Dodatkowe Szczegóły:
- Na urządzeniu działa API 22
- Korzystanie z Android Studio w wersji 1.5.1 z Gradle w wersji 1.5.0
- Manifest jest kompilacją i docelowym poziomem 23, minimalnym poziomem 15. Próbowałem również przenieść minimalny poziom na 21, ale to nie miało znaczenia.
- Dekompilacja APK (z minimalnym poziomem ustawionym na 21) pokazuje pojedynczy zasób XML w folderze do rysowania. Nie są tworzone żadne obrazy rasteryzowane.
New -> Vector Asset
, upuszczam XML obrazu wektorowego do mojego folderu do rysowania. Jeśli jednak używam apktool do rozpakowywania kompilowanego pliku APK, widzę, że pliki XML sądrawable-anydpi-v21
zapisane i poprawnie skalują na urządzeniach z interfejsem API 21+. Pliki rastrowe są umieszczone wdrawable-<mdpi/hdpi/etc>-v4
folderach i nie są wykorzystywane w urządzeniach API 21+ (na podstawie faktu, że skala ich poprawnie)drawable
folder. Szerokość / wysokość w wektorowym pliku XML z możliwością rysowania wynosi 24 dp. Określenie ImageView o wysokości / szerokości 400 dp zdecydowanie tworzy słabo skalowany obraz.drawable-anydpi-v21
jest to, że mójminSdkVersion
jest mniejszy niż 21. Jakakolwiek zmiana w zachowaniu, jeśli ustawiszminSdkVersion
mniej niż 21? A co z przeniesieniem XML dodrawable-anydpi
? Nie spodziewałbym się zmiany, ale spodziewałbym się również, że twój obraz wektorowy będzie poprawnie skalowany ...drawable-anydpi-v21
z różnymi rasteryzowanymi obrazami w mdi / hdpi / etc. lornetka składana. Brak zmian w końcowym wyniku renderowania.Odpowiedzi:
Tutaj są nowe informacje na temat tego problemu:
https://code.google.com/p/android/issues/detail?id=202019
Wygląda na to, że użycie
android:scaleType="fitXY"
spowoduje poprawne skalowanie w Lollipopie.Od inżyniera Google:
źródło
W przypadku wersji SDK mniejszych niż 21, w których system kompilacji musi generować obrazy rastrowe i jako domyślny rozmiar w przypadkach, w których nie określono szerokości / wysokości.
Nie wierzę, że jest to możliwe, jeśli chcesz również kierować reklamy na zestawy SDK mniejsze niż 21.
Dokumentacja: (właściwie niezbyt przydatna teraz, gdy ją ponownie przeczytałem ...)
Więcej dokumentacji:
Edycja: dzieje się coś dziwnego. Oto moje wyniki w emulatorze SDK w wersji 23 (urządzenie testowe Lollipop + jest teraz martwe ...):
A w emulatorze SDK w wersji 21:
źródło
width
height
viewport
height
iwidth
odxml
?AppCompat 23.2 wprowadza rysunki wektorowe dla wszystkich urządzeń z systemem Android 2.1 lub nowszym. Obrazy są skalowane prawidłowo, niezależnie od szerokości / wysokości określonej w pliku XML elementu wektorowego do rysowania. Niestety ta implementacja nie jest używana na poziomie API 21 i wyższym (na korzyść implementacji natywnej).
Dobra wiadomość jest taka, że możemy zmusić AppCompat do używania jego implementacji na poziomach API 21 i 22. Zła wiadomość jest taka, że musimy użyć do tego refleksji.
Przede wszystkim upewnij się, że używasz najnowszej wersji AppCompat i że masz włączoną nową implementację wektorów:
android { defaultConfig { vectorDrawables.useSupportLibrary = true } } dependencies { compile 'com.android.support:appcompat-v7:23.2.0' }
Następnie wywołaj
useCompatVectorIfNeeded();
onCreate () swojej aplikacji: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(); } } }
Na koniec upewnij się, że używasz
app:srcCompat
zamiastandroid:src
ustawiania obrazu ImageView:<ImageView android:layout_width="400dp" android:layout_height="400dp" app:srcCompat="@drawable/icon_bell"/>
Twoje rysunki wektorowe powinny teraz poprawnie skalować się!
źródło
1) Dlaczego w wektorze do rysowania istnieje specyfikacja szerokości / wysokości? Myślałem, że chodzi o to, że skalują się w górę iw dół bezstratnie, przez co szerokość i wysokość nie mają znaczenia w swojej definicji?
2) Czy możliwe jest użycie pojedynczego wektora do rysowania, który działa jako rysowany w trybie 24dp na TextView, a także dużego obrazu o szerokości bliskiej ekranu?
3) Jak efektywnie wykorzystać atrybuty szerokości / wysokości i jaka jest różnica z viewportWidth / Height?
źródło
Rozwiązuję swój problem po prostu zmieniam rozmiar obrazu wektorowego. Od początku był to zasób:
<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">
I zmieniłem to na 150dp (rozmiar ImageView w układzie z tym zasobem wektorowym), na przykład:
<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">
Na mnie to działa.
źródło
Muszę próbować tych sposobów, ale niestety żaden z nich nie zadziałał. Staram
fitXY
sięImageView
, staram używającapp:srcCompat
ale nawet nie można go używać. ale znalazłem podstępny sposób:Ale celem tej drogi są wymiary widoków. jeśli masz
ImageView
nieprawidłowe wymiary, element do rysowania zostanie rozciągnięty. musisz kontrolować to w wersjach wcześniejszych niż Lollipop lub Użyj niektórych widokówPercentRelativeLayout
.Mam nadzieję, że to pomocne.
źródło
Po pierwsze : zaimportuj svg do rysowania: (( https://www.learn2crack.com/2016/02/android-studio-svg.html ))
Po drugie : jeśli chcesz uzyskać wsparcie z Android API 7+, musisz użyć nagrania Android Support Library (( https://stackoverflow.com/a/44713221/1140304 ))
1- dodaj
vectorDrawables.useSupportLibrary = true
do pliku build.gradle.
2-Użyj przestrzeni nazw w układzie zawierającym imageView:
xmlns:app="http://schemas.android.com/apk/res-auto"
Po trzecie : ustaw imageView w android: scaleType = "fitXY" i użyj app: srcCompat
<ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" app:srcCompat="@drawable/ic_menu" />
Po czwarte : jeśli chcesz ustawić svg w kodzie java, musisz dodać poniższy wiersz na oncreate methoed
@Override protected void onCreate(Bundle savedInstanceState) { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }
źródło
Dla mnie powodem, dla którego wektory były konwertowane na png, był
android:fillType="evenodd"
atrybut w moim wektorze do rysowania. Kiedy usunąłem wszystkie wystąpienia tego atrybutu z mojego rysunku (w związku z tym domyślnynonzero
typ wypełnienia zastosowany do wektora), następnym razem, gdy aplikacja została zbudowana, wszystko było w porządku.źródło