IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

Ajout dynamique de formulaire (FragmentActivity, Fragment, custom_cursor ArrayAdapter)


Sujet :

Android

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    107
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 107
    Points : 56
    Points
    56
    Par défaut Ajout dynamique de formulaire (FragmentActivity, Fragment, custom_cursor ArrayAdapter)
    Bonjour à tous =)

    Je cherche à créer une activité (qui étend Fragment) dans laquelle on peut ajouter (grâce à un boutton) dynamiquement N formulaires (contenant un EditText et deux boutons radio pour le moment).

    Alors après quelques recherches et essais j'arrive à peu près à mon résultat, lorsque j'appuis 36 fois sur mon boutton "ajouter forumaire", les formulaires se créent un par un (les uns en desosus des autres) et je peux naviguer d'un forumaire à l'autre en scrollant simplement de haut en bas avec mon doigt.

    Et je me suis dis "raaAAAA ça marche c'est nickel !", mais j'ai constaté deux bug hier assez génant que je n'arrive pas à comprendre/résoudre ^^

    - si je créé par exemple 10 formulaires et qu'ensuite je modifie la valeur d'un radio boutton du premier formulaire, alors les forumaire 4-7-10 'subissent' la même modification. Si je fais la même opération au deuxième forumaire, ce sont les forumaires 5 et 8 qui 'subissent' les mêmes modifs que le forumaire 2. Je ne comprend absoulment pas d'où peut sortir cet espèce de bug/cycle xD
    - lorsque je test l'application sur mon Android (HTC Desire HD), je créé un formulaire. Ensuite je 'click' dans le champs à éditer du formulaire 1 et je perd desuite le 'focus' dès que mon clavier virtuel apparait (donc je dois re'clicker' dans le champs texte après que le clavier virtuel est apparu, ce qui est un peu chiant..). Une fois le premier caractère entré , je reperd le focus ! Je reclick dans la zone champs texte...et la je peux entrer autant de caractères que je veux sans perdre le focus (vraiment byzarre..).
    Si je créé ensuite un deuxième formulaire (et ayant quitté le clavier virtuel entre temps parce qu'il prend pas mal de place sur l'écran) et que je click sur son champs texte, non seulement je perd le focus dès que je veux entrer le premier caractère comme pour le premier formulaire. Mais pire encore, la valeur du champs texte du premier formulaire s'inscrit automatiquement dans le champs texte du deuxième formulaire comme si les deux formulaires s'étaient intervertit ! Et ce comportement-là (perte de focus, interversion de valeur de champ...) je ne le rencontre pas sur l'émulateur Android d'éclipse..
    Donc pareil que le premier bug, je ne sais pas du tout d'où ça pourrait provenir, donc difficile de faire des recherches efficaces sur le net :/

    Voici par quelles structures je suis passé pour créér mon bazard :

    Ma Main activité qui étend "FragmentActivity":
    - contient en static une ArrayList 'donnees_des_formulaires' de données 'donnees_dun_formulaire'
    - affiche le 'fragment' courant

    Mon activité 'secondaire' qui étend "Fragment" :
    - Contient la listView de mon xml, l'adapteur (adapteur personnalisé) et le boutton pour ajouter un novueau formulaire
    Voici le code principal de cette classe (rien de sorcier)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
    	ViewGroup root = (ViewGroup) inflater.inflate(R.layout.secondaire,null);
    	listview = (ListView) root.findViewById(R.id.listview);
    	adaptor = new custom_adaptor(root.getContext(),R.layout.formulaire, Main.donnees_des_formulaires);
    	listview.setAdapter(adaptor);
    	ajouter_formulaire = (Button) root.findViewById(R.id.ajouter_formulaire);
    	ajouter_formulaire.setOnClickListener(new OnClickListener() {
    		public void onClick(View v) {
    			Main.donnees_des_formulaires.add(new donnees_dun_formulaire()); //initilise toutes les variables de l'objet à null
    			adaptor.notifyDataSetChanged();
    		}
    	});
    	return root;
    }
    Mon curseur personnalisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    public class custom_adaptor extends ArrayAdapter<donnees_dun_formulaire> implements TextWatcher{
     
    	Context context;
    	int layoutResourceId;  
    	Holder holder;
    	ArrayList<donnees_dun_formulaire> liste;
     
    	public Adaptor_cavite_item(Context context, int layoutResourceId, ArrayList<donnees_dun_formulaire> data)
    	{
    		super(context,layoutResourceId,data);
    		this.layoutResourceId = layoutResourceId;
    		this.context=context;
    		this.liste = data;
    		this.holder = new Holder();
    	}
     
    	public View getView(int position, View convertView, ViewGroup parent){
     
    		View row = convertView;
     
    		if(row==null){
    		    LayoutInflater inflater = ((Activity)context).getLayoutInflater();
    		    row = inflater.inflate(layoutResourceId, parent,false);
    		    this.holder.champs_texte = (EditText)row.findViewById(R.id.champs_texte);
    		    this.holder.champs_texte.addTextChangedListener(this);
    		    row.setTag(this.holder);
    		}
    		else{this.holder=(Holder)row.getTag();}
    		return row;
    	}
     
    	static class Holder
    	{ 
    		EditText champs_texte;
    	}
    	public void afterTextChanged(Editable arg0) {}
    	public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) {}
    	public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
    		Log.i("onTextChanged", "event reçu");
    		//il faudrait modifier la structure 'Main.donnees_des_forumaires' ici
    	}
    }
    L'objet "donnees_dun_formulaire" est très simple. Mes deux layout aussi (l'un qui contient une "listview" et l'autre qui contient l'ensemble des vues qui composent un formulaire).

    Désolé pour ce post un peut long... mais je vois difficilement comment j'aurai pu éviter de pondre un pavé
    Et un grand Merci d'avance pour un coup d'main

  2. #2
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    107
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 107
    Points : 56
    Points
    56
    Par défaut
    Les problèmes viennent du fait que la listview et ces éléments sont recyclés lorsque je scroll de haut en bas (mécanisme automatique pour optimiser la mémoire) ...donc je me retrouve avec des mêmes vues en haut et en bas, ce qui explique le phénomène étrange que j'ai décris lors de mon premier post...



    J'aurai une petite question pour prendre en compte ce système de recyclage : (edit: ne me dites pas, je pense avoir trouvé x) )

    A quel moment dans mon code dois je sauvegarder les données de mon élément formulaire affiché dans l'élément dans une structure pour pouvoir le recharger ensuite lorsque je raffiche cet élément ? (je ne sais pas si c'est clair..)

    Concrètement, j'ai donc une liste de formulaire que l'on peut ajouter dynamiquement. Lorsque j'entre des données dans un des formulaires, à quel moment je dois sauvegarder les donénes de mon formulaire avant de les perdre à cause du recyclage ? (il y a peut etre une méthode à implémenté qui est appelée avant la destruction d'un élément maybe...je vais chercher par la..).
    Et une fois sauvegardé, il me rete plus qu'à détecter dans mon getview si la view existe, et si oui je recharge toute mes données sauvegardées dans la vue générée grâce au paramètre position c'est bien ça ?

    En vous remerciant =)

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    107
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 107
    Points : 56
    Points
    56
    Par défaut
    Je pensais avoir deviné mais après quelques tests et recherches, forcé de constater que je bloque de nouveau. Quelque chose doit m'échapper encore dans les mécanismes de la listView, je me retrouve avec des vues qui se répètent malgrès ce bout de code et je ne comprend pas pourquoi ça ne fonctionne pas :/
    Lorsque je modifie le spinner de mon premier formulaire, si je scroll vers les autres formulaire je constate que certains se retrouvent avec la même modification (donc des vues qui se recyclent et se répètent..)

    J'ai tout simplement rajouté quelques lignes dans le getView pour sauvegarder/charger les données et capté un event (listener) d'un spinner :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    static ArrayList<donnees_dun_formulaire> liste; //liste créé dans la classe MAIN
     
    public class custom_adaptor extends ArrayAdapter<donnees_dun_formulaire> implements TextWatcher{
     
    	Context context;
    	int layoutResourceId;  
    	Holder holder;
     
     
    	public Adaptor_cavite_item(Context context, int layoutResourceId, ArrayList<donnees_dun_formulaire> data)
    	{
    		super(context,layoutResourceId,data);
    		this.layoutResourceId = layoutResourceId;
    		this.context=context;
    		this.holder = new Holder();
    	}
     
    	public View getView(int position, View convertView, ViewGroup parent){
     
    		View row = convertView;
     
    		if(row==null){
    		    LayoutInflater inflater = ((Activity)context).getLayoutInflater();
    		    row = inflater.inflate(layoutResourceId, parent,false);
    		    //this.holder.champs_texte = (EditText)row.findViewById(R.id.champs_texte);
    		    //this.holder.champs_texte.addTextChangedListener(this);
     
    		    this.holder.type = (Spinner) row.findViewById(R.id.spinner);
    		    ArrayAdapter<CharSequence> adapter_type=ArrayAdapter.createFromResource(context, R.array.spinner_data, android.R.layout.simple_spinner_item);
    		    adapter_type.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    		    this.holder.type.setAdapter(adapter_type);
     
    		    row.setTag(this.holder);
    		}
    		else{this.holder=(Holder)row.getTag();}
     
    		// Je test si l'élément courant de mon ArrayList est initialisé à null 
    		if(MAIN.liste.get(position).type==null && MAIN.liste.get(position).champs_texte==null){
    			MAIN.liste.get(position).type = this.holder.type;
    			//MAIN.liste.get(position).champs_texte = this.holder.champs_texte;
    		}
     
    		// Opération inutile si l'élément courant de l'ArrauList était vide. Dans tous les cas, j'affecte au Holder les objets de l'élément courant de l'ArrayList. Donc dans mon esprit c'est ici que la vue courante via le holder récupère la bonne information du bon élément de l'ArrayList   
    		this.holder.type = MAIN.liste.get(position).type;		
    		this.holder.champs_texte = MAIN.liste.get(position).champs_texte;
     
    		//Ici je colle au spinner du formulaire de la vue courante un listener, ce listener va directement modifier les données de l'élément de l'ArrayList 'globale'
    		this.holder.type.setOnItemSelectedListener(new OnItemSelectedListener() {
    			public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
    				MAIN.liste_cavite.get(position).type.setSelection(arg2);
    			}
    			public void onNothingSelected(AdapterView<?> arg0) {}
    		});
     
     
    		return row;
    	}
     
    	static class Holder
    	{ 
    		//EditText champs_texte;
    		Spinner type;
    	}
    /*
    	public void afterTextChanged(Editable arg0) {}
    	public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) {}
    	public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
    		Log.i("onTextChanged", "event reçu");
    		//il faudrait modifier la structure 'Main.donnees_des_forumaires' ici
    	}
    }
    */
    Qu'estce qui cloche..?

  4. #4
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Bonjour,

    C'est normal cela.

    Ici la création :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    adaptor = new custom_adaptor(root.getContext(),R.layout.formulaire, Main.donnees_des_formulaires);
    Ici la modification
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Main.donnees_des_formulaires.add(new donnees_dun_formulaire()); //initilise toutes les variables de l'objet à null
    			adaptor.notifyDataSetChanged();
    Ici la mise à jour :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    // Opération inutile si l'élément courant de l'ArrauList était vide. Dans tous les cas, j'affecte au Holder les objets de l'élément courant de l'ArrayList. Donc dans mon esprit c'est ici que la vue courante via le holder récupère la bonne information du bon élément de l'ArrayList   
    		this.holder.type = MAIN.liste.get(position).type;		
    		this.holder.champs_texte = MAIN.liste.get(position).champs_texte;
    Pour les deux premier je comprends.

    Par contre pour la mise à jour, c'est quoi cette liste . Tu n'utilises ni les données de ton adapter qui normalement servent à cela en passant, ni la liste qui t'a servie à intialiser les données ( je préconise d'utiliser les données de l'adapter c'est plus évident à suivre).

    ta liste est une statique .
    Arg j'ai compris en fait, alors les données de ton adapter son lié avec la liste que tu lui as passé lors de son initialisation du coup si une a une modification l'autre aussi. Donc tu notifies ton adapter du changement et tu met à jour la liste avec la variable data.

    Si tu ne veux pas avoir la liste de l'actviity en tant que membre tu peux utiliser le getter/setter de l'adapter pour le mettre à jour.
    De plus tu as des fonction add, remove , etc. disponible.
    http://developer.android.com/referen...ayAdapter.html
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    107
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 107
    Points : 56
    Points
    56
    Par défaut
    Hey ! merci pour cette remarque qui a permis d'me débloquer !

    Donc effectivement au final...je ne touchais qu'à l'ArrayList qui provient d'une autre classe et non pas l'adapteur lui meme..donc voici le code plus haut corrigé si ça peut dépanner des gens

    et merci encore =)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    static ArrayList<donnees_dun_formulaire> liste; //liste créé dans la classe MAIN
     
    public class custom_adaptor extends ArrayAdapter<donnees_dun_formulaire> implements TextWatcher{
     
    	Context context;
    	int layoutResourceId;  
    	Holder holder;
     
     
    	public Adaptor_cavite_item(Context context, int layoutResourceId, ArrayList<donnees_dun_formulaire> data)
    	{
    		super(context,layoutResourceId,data);
    		this.layoutResourceId = layoutResourceId;
    		this.context=context;
    		this.holder = new Holder();
    	}
     
    	public View getView(int position, View convertView, ViewGroup parent){
     
    		View row = convertView;
     
    		if(row==null){
    		    LayoutInflater inflater = ((Activity)context).getLayoutInflater();
    		    row = inflater.inflate(layoutResourceId, parent,false);
    		    //this.holder.champs_texte = (EditText)row.findViewById(R.id.champs_texte);
    		    //this.holder.champs_texte.addTextChangedListener(this);
     
    		    this.holder.type = (Spinner) row.findViewById(R.id.spinner);
    		    ArrayAdapter<CharSequence> adapter_type=ArrayAdapter.createFromResource(context, R.array.spinner_data, android.R.layout.simple_spinner_item);
    		    adapter_type.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    		    this.holder.type.setAdapter(adapter_type);
     
    		    row.setTag(this.holder);
    		}
    		else{this.holder=(Holder)row.getTag();}
     
    		// Je test si l'élément courant de mon ArrayList est initialisé à null 
    		if(getItem(position).type==null && getItem(position).champs_texte==null){
    			getItem(position).type = this.holder.type;
    			//getItem(position).champs_texte = this.holder.champs_texte;
    		}
     
    		// Opération inutile si l'élément courant de l'ArrauList était vide. Dans tous les cas, j'affecte au Holder les objets de l'élément courant de l'ArrayList. Donc dans mon esprit c'est ici que la vue courante via le holder récupère la bonne information du bon élément de l'ArrayList   
    		this.holder.type = getItem(position).type;		
    		this.holder.champs_texte = getItem(position).champs_texte;
     
    		//Ici je colle au spinner du formulaire de la vue courante un listener, ce listener va directement modifier les données de l'élément de l'ArrayList 'globale'
    		this.holder.type.setOnItemSelectedListener(new OnItemSelectedListener() {
    			public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
    				MAIN.liste_cavite.get(position).type.setSelection(arg2);
    			}
    			public void onNothingSelected(AdapterView<?> arg0) {}
    		});
     
     
    		return row;
    	}
     
    	static class Holder
    	{ 
    		//EditText champs_texte;
    		Spinner type;
    	}
    /*
    	public void afterTextChanged(Editable arg0) {}
    	public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) {}
    	public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
    		Log.i("onTextChanged", "event reçu");
    		//il faudrait modifier la structure 'Main.donnees_des_forumaires' ici
    	}
    }
    */

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Ajout dynamique dans un formulaire
    Par artatnas dans le forum IHM
    Réponses: 2
    Dernier message: 24/04/2008, 12h37
  2. [JavaScript] [SRC] Name d'un élément de formulaire ajouté dynamiquement
    Par SpaceFrog dans le forum Contribuez
    Réponses: 4
    Dernier message: 26/01/2008, 20h34
  3. Ajout dynamique de champ dans un formulaire
    Par gendalf37400 dans le forum Ruby on Rails
    Réponses: 5
    Dernier message: 06/06/2007, 15h11
  4. ajout dynamique de contrôle dans un formulaire
    Par celiaaa dans le forum IHM
    Réponses: 2
    Dernier message: 26/02/2007, 19h23
  5. Ajout dynamique de champs de type file dans un formulaire !
    Par stitch dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 27/11/2005, 11h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo