J'ai une vue personnalisée en tenant une autre. Hiérarchie:
MyOuterView
->MyInnerView
MyInnerView
a un attribut enum tel que:
<attr name="myAttr" format="enum">
<enum name="foo" value="0"/>
<enum name="bar" value="1"/>
</attr>
Je peux donc instancier le composant dans MyOuterView
XML comme:
<com.example.MyInnerView
....
app:myAttr="foo"/>
Ce qui fonctionne bien sûr. La MyOuterView
offre un argument pour la personnalisation elle-même. Sur la base de cet argument, je souhaite définir l’argument de MyInnerView
.
Le comportement souhaité est que je puisse travailler avec Data Binding comme:
<com.example.MyInnerView
....
app:myAttr="@{data.getMyAttr()}"/>
où getMyAttr()
ressemble à:
public int getMyAttr() {
return myAttr; // returns 0 or 1
}
Le résultat est un problème de compilation.
****/data binding error **** msg: impossible de définir le paramètre de configuration pour l'attribut 'app: myAttr' avec le type de paramètre int sur com.example.MyInnerView
Donc, évidemment, je ne peux pas définir l'énumération par valeur mais uniquement par nom. Une idée en dehors de la création de la MyInnerView
par programme? Veuillez noter que je ne peux pas changer MyInnerView
.
Je ne peux pas définir l'énumération par valeur mais uniquement par nom
Ceci n'est pas entièrement vrai. Vous ne seriez pas en mesure de définir la valeur avec DataBinding même par son nom, le fait est que la valeur d'un attribut défini dans un fichier xml est transmise à la variable View
via le constructeur. Un View
pourrait avoir à la fois un attribut et un séparateur, mais ce n'est pas nécessairement le cas. Par exemple, si vous définissez une valeur pour Android:text
sur une TextView
, cette valeur est définie sur com.Android.internal.R.styleable.TextView_text
; elle est ensuite extraite de la AttributeSet
dans le constructeur. Si vous utilisez DataBinding, setText()
est appelé, mais ce sont deux choses complètement différentes, la fonctionnalité est la même mais elles ne sont pas liées dans le code.
Etant donné que vous ne pouvez pas modifier MyInnerView
et qu’il n’existe aucun séparateur que vous pouvez appeler pour myAttr
, votre seule option est de le transmettre par le constructeur. DataBinding n'est tout simplement pas réalisable, même avec un BinderAdapter, vous ne pourriez pas définir la valeur dans AttributeSet
car View
est déjà instancié à ce stade.
Option 1 - thèmes
Définir un nouvel attribut
<attr name="MyInnerViewAttrValue" format="integer" />
Puis résolvez cet attribut avec un style, par exemple, vous pourriez avoir
<style name="AppTheme.Foo">
<item name="MyInnerViewAttrValue">0</item>
</style>
<style name="AppTheme.Bar">
<item name="MyInnerViewAttrValue">1</item>
</style>
Définissez-le dans la mise en page xml
<com.example.MyInnerView
...
app:myAttr="?attr/MyInnerViewAttrValue" />
Ensuite, appelez setTheme(int)
dans la Activity
avant l'instanciation des vues.
Option 2 - BindingAdapter personnalisé
Si vous vouliez définir votre valeur DataBinding (parce que vous aviez un setter ou parce que vous vouliez pirater MyInnerView
avec réflexion), vous devrez créer un BindingAdapter personnalisé, par exemple
@BindingAdapter("myAttrValue")
public static void setMyAttr(MyInnerView myInnerView, int value) {
switch (value) {
case 0:
myInnerView.foo();
break;
default:
myInnerView.bar();
}
}
Puis dans la mise en page xml
<com.example.lelloman.dummy.MyInnerView
...
myAttrValue="@{model.attr}" />
Et donnez la valeur int
de votre ViewModel
public class MyInnerViewModel {
public int getAttr() {
return 1234;
}
}
Malheureusement, vous pouvez utiliser un nom d'attribut tel que app:myAttr="@{...}"
uniquement s'il existe un séparateur pour cela et que ce séparateur est associé à nom d'attribut ou qu'il peut être résolu par son nom. Dans votre cas, si cet attribut est utilisé uniquement dans le constructeur de View et view n’a aucune méthode publique pour changer cela - vous avez encore quelques solutions possibles: - étendre View et implémenter une logique pour personnaliser l’affichage comme cet attribut do (si possible) - make BindingAdapter et utilisez Reflection (si possible). - créez votre propre vue par copier-coller et corriger)