Атрибуты с тем же именем в attrs.xml для пользовательского просмотра

180

Я пишу несколько пользовательских представлений, которые имеют некоторые одноименные атрибуты. В соответствующем <declare-styleable>разделе attrs.xmlя хотел бы использовать те же имена для атрибутов:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView1">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" format="string" />
        <attr name="myattr2" format="dimension" />
        ...
    </declare-styleable>
</resources>

Я получаю сообщение об ошибке, myattr1и myattr2это уже определено. Я обнаружил, что должен опустить formatатрибут для myattr1и myattr2в MyView2, но если я это сделаю, я получу следующую ошибку в консоли:

[2010-12-13 23:53:11 - MyProject] ERROR: In <declare-styleable> MyView2, unable to find attribute 

Есть ли способ, которым я мог бы сделать это, может быть, какое-то пространство имен (просто угадать)?

Venator85
источник

Ответы:

401

Решение. Просто извлеките общие атрибуты из обоих представлений и добавьте их непосредственно как дочерние <resources>элементы узла:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="myattr1" format="string" />
    <attr name="myattr2" format="dimension" />

    <declare-styleable name="MyView1">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>

    <declare-styleable name="MyView2">
        <attr name="myattr1" />
        <attr name="myattr2" />
        ...
    </declare-styleable>
</resources>
Venator85
источник
11
что происходит, когда myattr1в строке MyView1и целое число MyView2?
foxx1337
4
Я так не думаю, например, у нас может быть атрибут «ориентации», и для некоторых видов это «горизонтальный» / «вертикальный», а для других «ландшафт» / «портрет» / «квадрат». С моей точки зрения, это ошибка (или, по крайней мере, противоречивое поведение) в Android (имейте в виду, что: 1. Стилируемые атрибуты всегда начинаются с prefix = view name и 2. Если вы создаете отдельные проекты библиотеки для таких представлений, все будет работать нормально )
se.solovyev
4
Когда я следую этому ответу, я получаю ERROR: In <declare-styleable> com_app_view_widget, unable to find attribute customAttr За все мнение, за которое я пытаюсь заявить. Любые идеи?
Dapp
45
@Google: Дрянной дизайн
Гленн Бек,
6
@ foxx1337 Просто используйте <attr name="myattr1" format="string|integer" />. Работает для меня.
Mygod
58

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

  <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <!-- parent styleable -->
     <declare-styleable name="MyView">
         <attr name="myattr1" format="string" />
         <attr name="myattr2" format="dimension" />
     </declare-styleable>

     <!-- inheriting parent styleable -->
     <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
    <declare-styleable name="MyView1" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myBackgroundColor" format="color"/>
    </declare-styleable>


    <!-- inheriting parent styleable -->
    <!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
    <declare-styleable name="MyView2" parent="MyView">
        <attr name="myattr1" />
        <attr name="myattr2" />
        <attr name="myfont" format="string"/>
        ...
    </declare-styleable>
</resources>

Это работает для меня полностью. Нам нужно сделать родительский стиль стилевым, а затем нам нужно наследовать этот родительский стиль. Например, как я уже делал выше: родительское стилевое имя MyView и унаследовало его от другого моего стиля, такого как MyView1 и MyView2 соответственно.

Прия Сингхал
источник
1
Это сработало для меня. Я не мог найти способ ссылаться на извлеченные атрибуты в коде из принятого ответа.
Неманья Ковачевич,
Хм ... странно ... принятое решение, кажется, работает хорошо для меня (targetSdkVersion 27). Может быть, потому что такие атрибуты, как «текст», являются общими и могут существовать в некоторых других файлах attrs.xml ..?
Аба
Я попытался с именем, которое, скорее всего, необычно, и принятое решение все еще работало для меня.
Аба
Я согласен с первым комментарием! Нет никакого способа сослаться на извлеченный атрибут из typedArray. Поэтому вам нужно определить стилизованного родителя
reavcn
для этого работу не забудьте рассмотреть этот атрибут в родителю , а не в ребенке (для класса MyView2права: R.styleable.MyView2_myattr1, неправильно: R.styleable.MyView_myattr1)
vigilancer
28

Как ответила Прия Сингхал, Android Studio требует, чтобы имена общих атрибутов были определены в их собственном имени стиля. Они больше не могут быть в корне.

Однако есть еще несколько моментов, на которые следует обратить внимание (поэтому я также добавляю ответ):

  • Общие стили не обязательно должны называться так же, как представления. (Благодаря этому ответу за указание на это.)
  • Вам не нужно использовать наследование с родителем.

пример

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

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- common attributes to all custom text based views -->

    <declare-styleable name="TextAttributes">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <!-- custom text views -->

    <declare-styleable name="View1">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

Упорядоченный пример

На самом деле, мне даже не нужно помещать атрибуты под произвольным именем. Пока я определяю их (даю им format) хотя бы для одного пользовательского представления, я могу использовать их где угодно (без format). Так что это также работает (и выглядит чище):

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="View1">
        <attr name="text" format="string"/>
        <attr name="textSize" format="dimension"/>
        <attr name="textColor" format="color"/>
        <attr name="gravity">
            <flag name="top" value="48" />
            <flag name="center" value="17" />
            <flag name="bottom" value="80" />
        </attr>
    </declare-styleable>

    <declare-styleable name="View2">
        <attr name="text"/>
        <attr name="textSize"/>
        <attr name="textColor"/>
        <attr name="gravity"/>
    </declare-styleable>

</resources>

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

Suragch
источник
Что не так с наследованием? У меня есть пользовательские иерархии представлений, связанные стилевые элементы которых не отражают эту взаимосвязь, которая может быть выведена только в соответствующих определениях стилей путем именования соглашений и определенных в них определенных элементов (с учетом того, что некоторые принадлежат одному стилю, а другие - другому). Я бы предпочел сделать это явно с parentатрибутом, но не видел много сообщений, предлагающих его использование.
Самис
@ Самис, я не работал над этим некоторое время, но я не знаю ничего плохого в использовании parent. Я думаю, я просто сказал, что это не требуется.
Сурагч
Это не обязательно, я просто создал другой подкласс, обернутый вокруг дополнительного атрибута, который я не хотел помещать в базовый класс. Я просто использую комментарии и соглашения об именах, чтобы обозначить разделение.
Самис
8

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- common attributes -->
     <attr name="myattr1" format="string" />
     <attr name="myattr2" format="dimension" />

 <!-- also note "myBackgroundColor" belongs to child styleable"MyView1"-->
<declare-styleable name="MyView1" >
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myBackgroundColor" format="color"/>
</declare-styleable>

<!-- same way here "myfonnt" belongs to child styelable "MyView2" -->
<declare-styleable name="MyView2" parent="MyView">
    <attr name="myattr1" />
    <attr name="myattr2" />
    <attr name="myfont" format="string"/>
    ...
</declare-styleable>

Хания Вариани
источник
1

На всякий случай, кто-то все еще застрял с этой проблемой после того, как попробовал доступное решение. Я застрял с добавлением subtitleатрибута сstring форматом.

Мое решение - удалить формат.

перед:

<attr name="subtitle" format="string"/>

после:

<attr name="subtitle"/>

Ахмад Музакки
источник