Как центрировать вектор, который можно рисовать в списке слоев без масштабирования

104

Я пытаюсь использовать VectorDrawablea LayerListбез масштабирования вектора. Например:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
    <item android:gravity="center" android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

Выдвижной ic_check_white_48dpидентификатор, определенный как:

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

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

Я могу добиться желаемого эффекта, если заменю вектор, который можно рисовать, на PNG для каждой плотности и изменю список слоев как таковой:

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
    <item>
        <bitmap android:gravity="center" android:src="@drawable/ic_check_white_48dp"/>
    </item>
</layer-list>

Есть ли способ сделать это с помощью VectorDrawable?

ашуги
источник
11
Похоже, что это может быть просто ошибка API 21/22. Я только что протестировал на устройстве API 23, и вектор для рисования был правильно центрирован.
ashughes
1
Вы должны ответить на свой вопрос и принять его. Так это будет более заметно, и вопрос не останется без ответа.
Марцин Козиньски
1
Я не ответил на свой вопрос, потому что у меня еще нет ответа, что делать с API 21/22. Мое временное решение заключалось в использовании PNG вместо векторов. Тем не менее, в надежде найти способ заставить векторы работать.
ashughes
1
Я открыл здесь вопрос: code.google.com/p/android/issues/detail?id=219600
toobsco42,
Это уже исправлено в API 23, поэтому я предполагаю, что ваш отчет об ошибке будет отмечен как исправленный.
ashughes

Ответы:

30

Я столкнулся с той же проблемой, пытаясь центрировать векторные чертежи в многоуровневом списке.

У меня есть обходной путь, это не совсем то же самое, но он работает, вам нужно установить размер для всего рисования и добавить отступ к векторному элементу:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <size android:height="120dp" android:width="120dp"/>
            <solid android:color="@color/grid_item_activated"/>
        </shape>
    </item>
    <item android:top="24dp"
          android:bottom="24dp"
          android:left="24dp"
          android:right="24dp"
          android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

Размер приведенной выше фигуры устанавливает размер всего объекта для рисования, 120dp в этом примере, отступ второго элемента, 24dp в этом примере, центрирует векторное изображение.

Это не то же самое, что использовать, gravity="center"но рабочий способ использования векторов в API 21 и 22.

Николас Тайлер
источник
2
Похоже, вам потребуется знать точный размер объекта для рисования (чтобы установить размер формы), вместо того, чтобы позволять ему заполнять все пространство, на которое он установлен, с помощью флажка, который можно рисовать по центру внутри него.
ashughes
1
можно не знать размер, но вы не можете изменить отступ с помощью этого метода, вы можете наложить чертежи друг на друга в просмотрах изображений. Как я уже говорил выше, идеального решения для gravity="center"API 21 и 22 не существует.
Николас Тайлер,
Не работает при использовании с windowBackground. Явные размеры в этом случае ничего не делают. И это тоже не сработает, если я помещу список слоев в другой список слоев.
Всеволод Ганин,
20

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

<layer-list>
    <item android:drawable="@color/grid_item_activated"/>
     <item
        android:gravity="center"
        android:width="48dp"
        android:height="48dp"
        android:drawable="@drawable/ic_check_white_48dp"/>
</layer-list>

Надеюсь, поможет!

Фелипе Дуарте
источник
34
Это не помогает в API 21-22, потому что widthатрибут недоступен на этих уровнях API. В API 23 они не нужны, потому что ошибка исправлена, а возможность рисования больше не растягивается.
WonderCsabo 03
3
Это не работает правильно для API 27, изображение растянуто на весь экран
Константин Конопко
8

Отредактированное решение, благодаря которому ваш SplashScreen будет отлично выглядеть на всех API, включая API21 - API23.

Прежде всего, прочтите эту статью и следуйте ХОРОШЕМУ способу создания заставки.

Если ваш логотип искажен или не подходит, и вы ориентируетесь только на API 24 +, вы можете просто уменьшить масштаб вектора, который можно рисовать прямо в его XML-файле, например:

<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="640"
android:viewportHeight="640"
android:width="240dp"
android:height="240dp">
<path
    android:pathData="M320.96 55.9L477.14 345L161.67 345L320.96 55.9Z"
    android:strokeColor="#292929"
    android:strokeWidth="24" />
</vector>

в приведенном выше коде я изменяю масштаб рисунка, который я нарисовал на холсте 640x640, до 240x240. Затем я просто помещаю его в свой экран-заставку, и он отлично работает:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"
android:paddingBottom="20dp" android:paddingRight="20dp" android:paddingLeft="20dp" android:paddingTop="20dp">

<!-- The background color, preferably the same as your normal theme -->
<item>
    <shape>
        <size android:height="120dp" android:width="120dp"/>
        <solid android:color="@android:color/white"/>
    </shape>
</item>

<!-- Your product logo - 144dp color version of your app icon -->
<item
    android:drawable="@drawable/logo_vect"
    android:gravity="center">

</item>
</layer-list>

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

ИЗМЕНИТЬ, чтобы он работал также и с API21-22-23

Хотя приведенное выше решение работает для устройств с API24 +, я был очень разочарован, установив свое приложение на устройство с API22. Я заметил, что заставка снова пытается заполнить весь вид и выглядит дерьмом. Вырвав брови полдня, я наконец силой воли применил решение грубой силы.

вам нужно создать второй файл, названный точно так же, как splashscreen xml (скажем, splash_screen.xml), и поместить его в 2 папки с именем drawable-v22 и drawable-v21, которые вы создадите в папке res / (чтобы увидеть их, вы необходимо изменить вид вашего проекта с Android на Project). Это служит для указания вашему телефону перенаправления к файлам, размещенным в этих папках, всякий раз, когда соответствующее устройство запускает API, соответствующий суффиксу -vXX в папке с возможностью переноса, см. Эту ссылку . поместите следующий код в список слоев файла splash_screen.xml, который вы создаете в этих папках:

<item>
<shape>
    <size android:height="120dp" android:width="120dp"/>
    <solid android:color="@android:color/white"/>
</shape>
</item>

<!-- Your product logo - 144dp color version of your app icon -->
<item android:gravity="center">
    <bitmap android:gravity="center"
        android:src="logo_vect"/>

</item>

так выглядят папки

По какой-то причине для этих API вам нужно обернуть свой чертеж в растровое изображение, чтобы он работал, и окончательный результат выглядел бы так же. Проблема в том, что вам нужно использовать aproach с дополнительными папками с возможностью рисования, поскольку вторая версия файла splash_screen.xml приведет к тому, что ваш экран-заставка вообще не будет отображаться на устройствах с API выше 23. Возможно, вам также придется разместить Первую версию splash_screen.xml в drawable-v24, так как по умолчанию для Android используется ближайшая папка drawable-vXX, которую он может найти для ресурсов.

мой экран-заставка

Quealegriamasalegre
источник
4

В настоящее время я работаю над заставкой с векторным рисунком, центрированным как по горизонтали, так и по вертикали. Вот что у меня получилось на уровне API 25:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">

<!-- background color, same as theme -->
<item android:drawable="@android:color/white"/>

<!-- app logo -->

<item
    android:drawable="@drawable/my_app_logo"
    android:gravity="center_horizontal|center_vertical"
    android:width="200dp"
    android:height="200dp"
    />
</layer-list>

Если вы хотите настроить размер векторного рисованного объекта, изменить android:widthи android:heightатрибуты выше, не обязательно изменять исходный рисованный объект.

Кроме того, по моему опыту, НЕ помещайте вектор, который можно рисовать, в тег растрового изображения, который у меня никогда не работает. Растровое изображение предназначено для файлов формата .png, .jpg и .gif, а не для векторных изображений.

Ссылка

https://developer.android.com/guide/topics/resources/drawable-resource#LayerList

https://developer.android.com/guide/topics/resources/more-resources.html#Dimension

Венхэ Ци
источник
1
Хорошая уловка о векторных чертежах, которые должны быть внутри тега <item> вместо тега <bitmap>.
FrostRocket