Suppose I am making some new views with styleable attributes. I declare them thusly (this is how the documentation says to do it:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TriangleView">
<attr name="direction">
<enum name="NE" value="0" />
<enum name="NW" value="1" />
<enum name="SW" value="2" />
<enum name="SE" value="3" />
</attr>
</declare-styleable>
<declare-styleable name="BannerView">
<attr name="direction">
<enum name="NE" value="0" />
<enum name="NW" value="1" />
<enum name="SW" value="2" />
<enum name="SE" value="3" />
</attr>
<attr name="thickness" format="dimension" />
</declare-styleable>
</resources>
However, this won't work because all attributes are apparently in the same namespace, and I get the error Error: Attribute "direction" has already been defined
.
So apparently I have to move the apparently duplicated attributes outside the <declare-styleable>
like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="direction">
<enum name="NE" value="0" />
<enum name="NW" value="1" />
<enum name="SW" value="2" />
<enum name="SE" value="3" />
</attr>
<declare-styleable name="BannerView">
<attr name="thickness" format="dimension" />
</declare-styleable>
</resources>
But this poses two questions:
<declare-styleable>
?BannerView
's direction can only be up
or down
.What exactly is the point of
<declare-styleable>
?
<declare-stylable>
tags let you declare attributes for your custom views that you can then set for those views in xml. There are really 3 parts to using the attribute:
<attr>
inside of a <declare-stylable>
tag.app
). Use the custom attribute in your layout (ex. app:direction="NW"
).AttributeSet
parameter, get a TypedArray
and read the custom attributes, if any, from it and then within the constructor tell the view how to use those attributes appropriately.What if I want the attribute to behave differently in different views? For example if BannerView's direction can only be up or down.
Try something like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="direction">
<enum name="NE" value="0" />
<enum name="NW" value="1" />
<enum name="SW" value="2" />
<enum name="SE" value="3" />
</attr>
<declare-styleable name="TriangleView">
<attr name="direction" />
</declare-styleable>
<declare-styleable name="BannerView">
<attr name="direction" />
<attr name="thickness" format="dimension" />
</declare-styleable>
</resources>
When you build your xml layout for TriangleView
or BannerView
, you can use the app:direction="NW"
example for both. In the constructors with AttributeSet
in TriangleView
or BannerView
, the attributes will have the same format as the original, but what you do with that value is dependent on your implementation of the constructors in each respective view (can be the same or different for both).
If you want attributes to be defined differenly (ie. different "format" or "enum") for different views, then you have to create different attributes with different names.