Почему мой вектор не масштабируется, как ожидалось?

Я пытаюсь использовать векторные чертежи в своем приложении для Android. От http://developer.android.com/training/material/drawables.html (Акцент мой):

В Android 5.0 (уровень API 21) и выше вы можете определить векторные чертежи,масштаб без потери четкости.

используя этот drawable:

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

и это ImageView:

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

создает это размытое изображение при попытке отобразить значок на 400dp (на большом мобильном устройстве с высоким разрешением около 2015 года под управлением lollipop):

blurryBellIcon

изменение ширины и высоты в определении вектора, выводимого на 200dp, значительно улучшает ситуацию при размере 400dp. Однако, установив это как drawable для элемента TextView (т. е. значок слева от текста), теперь создается огромный значок.

мои вопросы:

1) Почему есть спецификация ширины/высоты в векторном drawable? Я думал, что весь смысл в том, что они масштабируются вверх и вниз без потерь, делая ширину и высоту бессмысленными в своем определении?

2) Можно ли использовать один вектор drawable, который работает как 24dp drawable на TextView, но хорошо масштабируется, чтобы использовать как можно больше изображений? Е. Г. как я могу избежать создания нескольких векторные рисунки разных размеров и вместо того, чтобы использовать один масштаб для моего оказанные требования?

3) Как эффективно использовать атрибуты width/height и в чем разница с viewportWidth/Height?

дополнительная информация:

  • на устройстве работает API 22
  • использование Android Studio v1.5.1 с Gradle версии 1.5.0
  • Манифест компилируется и целевой уровень 23, минимальный уровень 15. Я также попытался переместить минимальный уровень на 21, но это не имело значения.
  • Декомпиляция APK (с Мин level set to 21) показывает один XML-ресурс в папке drawable. Растеризованные изображения не создаются.

7 ответов


появилась новая информация об этой проблеме здесь:

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

похоже на использование android:scaleType="fitXY" сделает его масштаб правильно на леденец.

от инженера Google:

привет, дайте мне знать, если scaleType= 'fitXY' может быть обходным путем для вас, в чтобы изображение выглядело четким.

зефир против леденца из-за специальной обработки масштабирования добавляют в зефир.

кроме того, для ваших комментариев: "правильное поведение: вектор drawable масштабировать без потери качества. Так что, если мы хотим использовать один и тот же актив в 3 разных размерах в нашем приложении нам не нужно дублировать vector_drawable.xml 3 раза с различными жесткими размерами. "

хотя я полностью согласен, что это должно быть так, на самом деле, Android платформа имеет производительность озабоченность таким образом, что мы не достигли идеальный мир еще. Поэтому рекомендуется использовать 3 разных vector_drawable.xml для повышения производительности, если вы уверены, что хотите нарисовать 3 разных размера на экране одновременно.

техническая деталь-в основном мы используем растровые под крючок чтобы кэшировать сложный путь рендеринга, так что мы можем получить лучшее перерисовка производительности, наравне с перерисовкой растрового чертежа.


1) Почему в векторе есть спецификация ширины/высоты? Я думал, что весь смысл в том, что они масштабируются вверх и вниз без потерь, делая ширину и высоту бессмысленными в своем определении?

для SDK версий менее 21, где система сборки должна генерировать растровые изображения и как размер по умолчанию в случаях, когда вы не указываете ширину/высоту.

2) Можно ли использовать один вектор, который работает как 24dp drawable на TextView, а также большое изображение ширины экрана?

Я не верю, что это возможно, если вам также нужно нацелить SDKs менее 21.

3) Как эффективно использовать атрибуты width/height и в чем разница с viewportWidth/Height?

документы: (на самом деле не очень полезно сейчас, когда я перечитываю его...)

android:width

используется для определите внутреннюю ширину drawable. Это поддерживает все единицы измерения, обычно заданные с помощью dp.

android:height

используется для определения внутренней высоты drawable. Это поддерживает все единицы измерения, обычно заданные с помощью dp.

android:viewportWidth

используется для определения ширины области просмотра пространства. Viewport-это в основном виртуальный холст, на котором рисуются пути.

android:viewportHeight

используется для определения высоты области просмотра пространства. Viewport-это в основном виртуальный холст, на котором рисуются пути.

дополнительная документация:

Android 4.4 (уровень API 20) и ниже не поддерживает векторные чертежи. Если ваш минимальный уровень API установлен на одном из этих уровней API, Vector Asset Studio также направляет Gradle для создания растровых изображений вектора для обратной совместимости. Вы можете обратиться к вектор активы как Drawable в коде Java или @drawable в XML-коде; при запуске приложения соответствующий вектор или растровое изображение отображается автоматически в зависимости от уровня API.


Edit: что-то странное происходит. Вот мои результаты в эмуляторе SDK версии 23 (тестовое устройство Lollipop+ сейчас мертво...):

Good bells on 6.x

и в версии SDK эмулятора 21:

Crappy bells on 5.x


AppCompat 23.2 представляет векторные чертежи для всех устройств под управлением Android 2.1 и выше. Изображения масштабируются правильно, независимо от ширины / высоты, указанной в XML-файле векторного чертежа. К сожалению, эта реализация не используется в API уровня 21 и выше (в пользу собственной реализации).

хорошей новостью является то, что мы можем заставить AppCompat использовать его реализацию на уровнях API 21 и 22. Плохая новость в том, что мы должны использовать рефлексию, чтобы сделать этот.

прежде всего, убедитесь, что вы используете последнюю версию AppCompat и что вы включили новую векторную реализацию:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

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

затем вызов useCompatVectorIfNeeded(); в onCreate () вашего приложения:

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

наконец, убедитесь, что вы используете app:srcCompat вместо android:src чтобы установить изображение вашего ImageView:

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

ваши векторные чертежи теперь должны масштабироваться правильно!


1) Почему в векторе есть спецификация ширины/высоты? Я думал, что весь смысл в том, что они масштабируются вверх и вниз без потерь, делая ширину и высоту бессмысленными в своем определении?

Это только размер вектора по умолчанию, если вы не определяете его в виде макета. (т. е. вы используете содержимое wrap для высоты и ширина вашего imageview)

2) Можно ли использовать один вектор, который работает как 24dp drawable на TextView, а также большом изображении ширины экрана?

Да, это возможно, и у меня не было никаких проблем с изменением размера как пока работающее устройство использует lollipop или выше. В предыдущих APIs, вектор преобразуется в pngs для разных размеров экрана, когда вы создаете приложение.

3) Как эффективно использовать атрибуты width/height и в чем разница с viewportWidth/Height?

этот влияет на то, как используется пространство вокруг вектора. т. е. вы можете используйте его, чтобы изменить "гравитацию" вектора внутри окна просмотра, сделайте у вектора есть поле по умолчанию, оставьте определенные части вектора из иллюминатора и т. д... Обычно, вы просто устанавливаете их на то же самое размер.


Я пытаюсь должен из этих способов, но, к сожалению, ни один из них не работал. Я стараюсь fitXY на ImageView Я стараюсь использовать app:srcCompat но даже не может использовать его. но я нашел хитрый способ:--8-->

установите Drawable в background вашего ImageView.

но точка этого пути-представления измерений. если ImageView имеет неправильные размеры, drawable получает растяжку. вы должны контролировать его в версиях pre-lollipop или использовать некоторые представления PercentRelativeLayout.

надеюсь, что это полезный.


первый : импорт svg в drawble : ((https://www.learn2crack.com/2016/02/android-studio-svg.html))

1-Щелкните правой кнопкой мыши на папке drawable выберите New - > Vector Asset

enter image description here

2-вектор Asset Studio предоставляет вам возможность выбрать встроенный Значки материалов или ваш собственный локальный файл svg. Вы можете переопределить размер по умолчанию если необходимый.

enter image description here

второй :если вы хотите получить поддержку от Android API 7+ , Вы должны использовать библиотеку поддержки Android ((https://stackoverflow.com/a/44713221/1140304))

1 - добавить

vectorDrawables.useSupportLibrary = true

в сборку.файл gradle.

2-Используйте пространство имен в макете с imageView:

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

третий: установите imageView с android: scaleType= "fitXY" и использовать приложение: srcCompat

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

в-четвертых :если вы хотите установить svg в java-коде, вы должны добавить ниже строку oncreate methoed

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

Я решаю свою проблему, просто меняю размер векторного изображения. С самого начала это был ресурс вроде:

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

и я изменил его на 150dp (размер ImageView в макете с этим векторным ресурсом), как:

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

это работает для меня.