131 votes

Android - Écriture d'un composant personnalisé (composé)

L'application Android que je suis en train de développer a une activité principale qui est devenue assez importante. C'est principalement parce qu'elle contient un TabWidget avec 3 onglets. Chaque onglet comporte un certain nombre de composants. L'activité doit contrôler tous ces composants à la fois. Donc je pense que vous pouvez imaginer que cette activité a comme 20 champs (un champ pour presque chaque composant). Elle contient également beaucoup de logique (écouteurs de clics, logique pour remplir les listes, etc).

Ce que je fais normalement dans les cadres basés sur les composants est de tout diviser en composants personnalisés. Chaque composant personnalisé a alors une responsabilité claire. Il contient son propre ensemble de composants et toute autre logique liée à ce composant.

J'ai essayé de comprendre comment cela peut être fait, et j'ai trouvé quelque chose dans la documentation d'Android qu'ils aiment appeler un "contrôle composé". (Voir http://developer.Android.com/guide/topics/ui/custom-components.html#compound et faites défiler jusqu'à la section "Compound Controls") Je voudrais créer un tel composant sur la base d'un fichier XML définissant la structure de la vue.

Dans la documentation, il est dit :

Notez que, tout comme pour une activité, vous pouvez utiliser l'approche déclarative (basée sur XML) pour créer les composants contenus, ou vous pouvez les imbriquer ou les imbriquer de manière programmatique dans votre code.

Eh bien, c'est une bonne nouvelle ! L'approche basée sur XML est exactement ce que je veux ! Mais elle ne dit pas comment le faire, si ce n'est que c'est "comme avec une activité"... Mais ce que je fais dans une Activity, c'est appeler setContentView(...) pour gonfler les vues à partir de XML. Cette méthode n'est pas disponible si vous sous-classez par exemple LinearLayout .

J'ai donc essayé de gonfler le XML manuellement comme ceci :

public class MyCompoundComponent extends LinearLayout {

    public MyCompoundComponent(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.my_layout, this);
    }
}

Cela fonctionne, à l'exception du fait que le XML que je charge a LinearLayout déclaré comme l'élément Root. Il en résulte que l'élément LinearLayout étant un enfant de MyCompoundComponent qui lui-même est déjà un LinearLayout ! ! Donc maintenant nous avons un LinearLayout redondant entre MyCompoundComponent et les vues dont il a réellement besoin.

Quelqu'un peut-il me fournir une meilleure façon d'aborder cette question, en évitant d'avoir une redondance LinearLayout instancié ?

100voto

bhatt4982 Points 4648

Utilisez fusionner comme racine XML

<merge xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Your Layout -->
</merge>

Consultez cet article.

0voto

Timmmm Points 9909

Je pense que la façon dont vous êtes censé le faire, est d'utiliser le nom de votre classe comme élément racine XML :

<com.example.views.MyView xmlns:....
       android:orientation="vertical" etc.>
    <TextView android:id="@+id/text" ... />
</com.example.views.MyView>

Ensuite, votre classe doit être dérivée de la mise en page que vous souhaitez utiliser. Notez que si vous utilisez cette méthode, vous Ne le fais pas. utiliser le gonfleur de mise en page ici.

public class MyView extends LinearLayout
{
    public ConversationListItem(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }
    public ConversationListItem(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public void setData(String text)
    {
        mTextView.setText(text);
    }

    private TextView mTextView;

    @Override
    protected void onFinishInflate()
    {
        super.onFinishInflate();

        mTextView = (TextView)findViewById(R.id.text);
    }
}

Ensuite, vous pouvez utiliser votre vue dans les mises en page XML comme d'habitude. Si vous voulez créer la vue de manière programmatique, vous devez la gonfler vous-même :

MyView v = (MyView)inflater.inflate(R.layout.my_view, parent, false);

Malheureusement, cela ne vous permet pas de faire v = new MyView(context) parce qu'il ne semble pas y avoir de moyen de contourner le problème des mises en page imbriquées, ce n'est donc pas vraiment une solution complète. Vous pourriez ajouter une méthode comme celle-ci à MyView pour le rendre un peu plus agréable :

public static MyView create(Context context)
{
    return (MyView)LayoutInflater.fromContext(context).inflate(R.layout.my_view, null, false);
}

Avertissement : il se peut que je dise des conneries.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X