web-dev-qa-db-fra.com

DataBinding: Comment obtenir des ressources par identifiant dynamique?

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?

30
Dmitry Zaytsev

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.

11
Dmitry Zaytsev

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.

23
Amagi82

Depuis juin 2016, cela est possible en XML:

Android:text= "@{String.format(@string/my_format_string, myPojo.resourceId)}"
18
Kaskasi

Vous pouvez utiliser:

Android:text='@{(id > 0) ? context.getString(id) : ""}'
4
Dalvinder Singh

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);
4
Khemraj

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}"/>
0
Yazazzello