The core documentation for Views Metadata and properties usage can be found here. For most instances, this is sufficient to add metadata to any given view descendant class.
There are, however, some cases where extra care is needed to properly add metadata to a class.
[TOC]
In some cases a View sub-class is declared as a nested class of varying visibility. In order to properly attach metadata to such a class the following should be used. Consider the following example class:
In the header it is declared thusly:
class ASH_EXPORT MyViewClass : public views::View {
public:
METADATA_HEADER(MyViewClass, views::View);
// ... Public API goes here ...
private:
// ... A private nested view ...
class MyNestedView;
};
Then in the .cc file:
class MyViewClass::MyNestedView : public views::View {
public:
METADATA_HEADER(MyNestedView, views::View);
// ... Public API goes here …
};
Then, to properly declare the metadata for MyViewClass::MyNestedView
along
with any necessary properties, the BEGIN_METADATA
macro takes an extra
parameter to define the outer class or scope:
BEGIN_METADATA(MyViewClass, MyNestedView)
END_METADATA
This ensures the internal metadata classes are defined with the properly nested scope. The rest of the definition remains the same as the above linked document comment.
While this may seem strange that a property would be read-only, it’s a good debugging tool by allowing the ui-devtools to peer into the object instance for more insight about it’s internal state. In those cases, you may want to define such a property in the metadata. A read-only property only has a “getter” (see the core documentation about how to define a “getter”). It is as simple as using a different macro when defining the class’ metadata.
ADD_READONLY_PROPERTY_METADATA(bool, IsDrawn);
In this case, the IsDrawn
property is calculated and not something that can
be directly set. However, it is likely useful during debugging to see whether
the view considers itself to be drawn. Sometimes you will need to refactor the
“getter” to properly match the naming requirements.
While this may be rare, there are cases where a type has been declared as a mere alias to a POD type such as int, unsigned, float, etc. In most circumstances the default type converter which will convert to/from a string using the natural string format is sufficient. However in some cases this type alias is meant to convey that this POD type is to be treated differently and thus needs to convert to/from strings using a different syntax. Unfortunately, C++ doesn’t have the concept of making a truly uniquely identifiable type from a POD type. In those cases some extra care is needed when defining a custom type converter for such a type.
Consider the following type:
using datetime_t = double;
If a property were using that type, the compiler would select the following type converter:
template <>
struct TypeConverter<double> {
//...
};
This is most likely not what was desired since the likely intent is to allow
the use of a date/time string to display or set the value. There is no way to
force the compiler to select a TypeConverter<datetime_t>
specialization. We
need to do a little extra work.
First of all, make the type unique with the following macro:
MAKE_TYPE_UNIQUE(SkColor);
Then use the UNIQUE_TYPE_NAME
macro to wrap the name you want to be unique.
template <>
struct VIEWS_EXPORT TypeConverter<UNIQUE_TYPE_NAME(datetime_t)>
: BaseTypeConverter<true, false> {
// Define implementations for ToString and FromString here. See type_conversion.h
};
It’s also helpful to define your own type-alias to later reference.
using DateTimeConverter = TypeConverter<UNIQUE_TYPE_NAME(datetime_t)>;
Finally, you need to be explicit about when to select that type converter when defining the property in the metadata. Add the reference to the type converter specialization to the macro.
BEGIN_METADATA(MyDateTimeView, views::View)
ADD_PROPERTY_METADATA(datetime_t, CurrentDateTime, DateTimeConverter)
END_METADATA
NOTE: SkColor is such a case where the above technique has been used. For properties of that type, use the SkColorConverter type alias when defining the metadata for a property of that type.
ADD_PROPERTY_METADATA(SkColor, BackgroundColor, SkColorConverter)
Due to their very nature, some property types may not be readily convertible to
or from strings. Common instances of this are pointers or a unique_ptr<T>
.
However, knowing that something has been set for such a property can be
helpful. Unlike the read-only properties described above, a property of a
non-serializable type may still have a “getter” and a “setter”. Within the code
at run-time, getting or setting the value directly via the getter and setter is
perfectly valid.
The type converter for a non-serializable type may return something from the ToString() method, but it will typically return absl::nullopt from the FromString() method. For a non-serializable type, the ui-devtools front-end won’t call the setter since whatever “value” it has is presumed to be unconvertable to a valid value.
For pointers and unique_ptr<T>
a partial specialization is already available
in which the compiler should already select. Most non-serializable types are
already unique, so creating a type converter specialization is relatively
straightforward. Otherwise see the above section to resolve this.
For other instances that may need this you will need to define your own type
converter specialization. This is done the same as other type converter
specializations, except for the ancestor specialization. The ancestor
BaseTypeConverter
template takes a few bool
parameters. The first of which
indicates whether a property type is serializable.