Je sais qu'il est possible de référencer des ressources dans la mise en page par leur identifiant de ressource:
Android:text="@{@string/resourceName}"
Cependant, je voudrais référencer la ressource par son identifiant qui n'est connu qu'au moment de l'exécution. À titre d'exemple simple, imaginez que nous avons un tel modèle:
public class MyPOJO {
public final int resourceId = R.string.helloWorld;
}
Et maintenant, je dois utiliser cette valeur comme valeur dans une chaîne de format. Appelons ça
<string name="myFormatString">Value is: %s</string>
L'approche la plus simple ne fonctionne pas:
Android:text="@{@string/myFormatString(myPojo.resourceId)}"
Cela mettra simplement une valeur entière dans un espace réservé (cela prouve également que j'ai initialisé correctement mon POJO, donc je ne fournis pas la disposition entière ici).
J'ai également essayé d'utiliser @BindingConversion
, mais cela n'a pas fonctionné (ce qui est en fait prévu, mais j'ai quand même essayé) - int
était toujours affecté à l'espace réservé et la méthode de liaison n'était pas appelée.
Comment puis-je obtenir explicitement une ressource par son identifiant dans la bibliothèque DataBinding?
J'ai fini par créer ma propre méthode:
public class BindingUtils {
public static String string(int resourceId) {
return MyApplication
.getApplication()
.getResources()
.getString(resourceId);
}
}
Déclarer une importation pour cela:
<data>
<import type="com.example.BindingUtils" />
...
</data>
Et juste l'appeler pendant la liaison:
Android:text="@{@string/myFormatString(BindingUtils.string(myPojo.resourceId))}"
Ce serait bien d'avoir une méthode prête à l'emploi pour cela. DataBinding est sitll en version bêta - alors peut-être qu'il viendra à l'avenir.
Une autre solution consiste à créer un @BindingAdapter
Personnalisé pour cela.
@BindingAdapter({"format", "argId"})
public static void setFormattedText(TextView textView, String format, int argId){
if(argId == 0) return;
textView.setText(String.format(format, textView.getResources().getString(argId)));
}
Et puis il suffit de fournir les variables séparément.
<TextView
app:format="@{@string/myFormatString}"
app:argId="@{myPojo.resourceId}"
Vous pouvez utiliser un tableau si vous avez besoin de plusieurs arguments, mais dans mon cas, un seul suffit.
Depuis juin 2016, cela est possible en XML:
Android:text= "@{String.format(@string/my_format_string, myPojo.resourceId)}"
Vous pouvez utiliser:
Android:text='@{(id > 0) ? context.getString(id) : ""}'
Une autre solution si vous avez déjà Context
défini dans votre xml alors vous aurez pas besoin d'importer la classe String
.
Android:text="@{@string/myFormatString(context.getString(pojo.res))}"
travaillera pour
<string name="myFormatString">Value is: %s</string>
Si vous n'avez pas de contexte dans votre xml, alors suivez ceci
<data>
<variable
name="context"
type="abc.UserActivity"/>
<variable
name="pojo"
type="abc.MyPOJO"/>
</data>
et dans votre Activity
ActivityUserBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
binding.setPojo(new MyPOJO());
binding.setContext(this);
Version Kotlin:
@BindingAdapter("template", "resId")
fun TextView.setFormattedText(template: String, resId: Int) {
if (template.isEmpty() || resId == 0) return
text = template.format(resources.getString(resId))
}
en xml
<TextView
app:template="@{@string/myFormatString}"
app:resId="@{viewModel.resourceId}"/>