Si vous regardez le discours que j'ai donné lors de la journée de l'Université Devoxx (disponible sur parleys.com ), vous apprendrez à le faire vous-même. Pendant la conférence, j'ai écrit une FlowLayoutimplémentation en direct sur scène pour montrer à quel point il est simple d'écrire des mises en page personnalisées.
merci mec romain, ça aide vraiment. que diriez-vous simplement de donner la solution? ou lien? ... Je ne comprends pas comment votre réponse a été acceptée.
Johann Hilbold
4
@JohannHilbold: Je viens d'ajouter les liens
Macarse
7
Les lecteurs sont conscients que le code sur le lien présente de graves problèmes et est loin d'être une solution instantanée. J'ai déjà eu deux problèmes majeurs dans cette petite base de code. Je ne publierai pas les correctifs car ce sont des solutions de ruban adhésif pour mes besoins particuliers ...
Nemanja Kovacevic
6
Je n'ai jamais prétendu que c'était parfait :)
Romain Guy
19
@RomainGuy le fait est que ce n'est peut-être pas si simple après tout.
<com.google.android.flexbox.FlexboxLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"app:flexWrap="wrap"><!-- contents go here --></com.google.android.flexbox.FlexboxLayout>
Pour obtenir des instructions de compilation, consultez le dépôt github.
C'est la dernière et jusqu'à présent la meilleure solution.
Touhid
3
Cela devrait être marqué comme la solution! Meilleure réponse à ce problème jusqu'à présent
x10sion
1
Pour ajouter à cette réponse, cette bibliothèque a également un LayoutManager si vous voulez avoir cet effet dans un RecyclerView
Ari
1
Bingo, bango, bongo. Magnifique bibliothèque pour utiliser Flexbox sous Android. Joli.
Joshua Pinter
23
Je n'ai pas assez de réputation pour publier un commentaire sur la réponse de Romain Guy mais c'est là que devrait se trouver cette réponse (j'ai créé un compte juste pour partager ma modification).
Quoi qu'il en soit, je vois que d'autres personnes ont découvert que sa solution FlowLayout plutôt cool avait quelques problèmes. J'ai pu en trouver un moi-même et j'ai vu, comme d'autres, que certains enfants étaient coupés. En regardant en détail l'algorithme, cela semble être une erreur très simple dans le calcul de la hauteur. Lorsque le tout dernier enfant est celui qui est placé sur une nouvelle ligne, alors la hauteur n'a pas été correctement calculée. J'ai nettoyé un peu le calcul (il y avait une utilisation étrange de "height" par rapport à currentHeight).
La modification suivante résout le problème du «dernier enfant est coupé s'il est sur une nouvelle ligne»:
Belle classe, mais il faudrait un peu de travail pour prendre en charge la direction de la mise en page de droite à gauche.
Ted Hopp
Comment faire des objets au centre.
Abhishek c
java.lang.ClassCastException: android.widget.LinearLayout $ LayoutParams ne peut pas être converti en com.nuveda.fillintheblank.FlowLayout $ LayoutParams
Naveen Kumar M
Je pense que vous essayez de définir des paramètres dynamiques pour votre mise en page afin de créer des problèmes, je suggère d'utiliser RelativeLayout.LayoutParams.
Dhaval Solanki
3
Une révision de @MattNotEquals () FlowLayout qui prend en charge MarginLayoutParams.
Il s'agit simplement d'une implémentation minimaliste de MarginLayoutParms pour prendre en charge les marges gauche, droite, supérieure et inférieure.
import android.content.Context;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;/**
* Original version courtesy of MattNotEquals() at http://stackoverflow.com/a/34169798/4515489 - 4/13/17.
* 7/15/17 Revised to support MarginLayoutParams.
*/publicclassFlowLayoutextendsViewGroup{// Custom layout that wraps child views to a new line.publicFlowLayout(Context context){super(context);}publicFlowLayout(Context context,AttributeSet attrs){this(context, attrs,0);}publicFlowLayout(Context context,AttributeSet attrs,int defStyle){super(context, attrs, defStyle);}@Overrideprotectedvoid onMeasure(int widthMeasureSpec,int heightMeasureSpec){int childLeft = getPaddingLeft();int childTop = getPaddingTop();int lowestBottom =0;int lineHeight =0;int myWidth = resolveSize(100, widthMeasureSpec);int wantedHeight =0;for(int i =0; i < getChildCount(); i++){finalView child = getChildAt(i);if(child.getVisibility()==View.GONE){continue;}
child.measure(getChildMeasureSpec(widthMeasureSpec,0, child.getLayoutParams().width),
getChildMeasureSpec(heightMeasureSpec,0, child.getLayoutParams().height));int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();
lineHeight =Math.max(childHeight, lineHeight);finalLayoutParams lp =(LayoutParams) child.getLayoutParams();
childLeft += lp.leftMargin;
childTop += lp.topMargin;if(childLeft + childWidth + lp.rightMargin + getPaddingRight()> myWidth){// Wrap this line
childLeft = getPaddingLeft()+ lp.leftMargin;
childTop = lowestBottom + lp.topMargin;// Spaced below the previous lowest point
lineHeight = childHeight;}
childLeft += childWidth + lp.rightMargin;if(childTop + childHeight + lp.bottomMargin > lowestBottom){// New lowest point
lowestBottom = childTop + childHeight + lp.bottomMargin;}}
wantedHeight += lowestBottom + getPaddingBottom();// childTop + lineHeight + getPaddingBottom();
setMeasuredDimension(myWidth, resolveSize(wantedHeight, heightMeasureSpec));}@Overrideprotectedvoid onLayout(boolean changed,int left,int top,int right,int bottom){int childLeft = getPaddingLeft();int childTop = getPaddingTop();int lowestBottom =0;int myWidth = right - left;for(int i =0; i < getChildCount(); i++){finalView child = getChildAt(i);if(child.getVisibility()==View.GONE){continue;}int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();finalLayoutParams lp =(LayoutParams) child.getLayoutParams();
childLeft += lp.leftMargin;
childTop += lp.topMargin;if(childLeft + childWidth + lp.rightMargin + getPaddingRight()> myWidth){// Wrap this line
childLeft = getPaddingLeft()+ lp.leftMargin;
childTop = lowestBottom + lp.topMargin;// Spaced below the previous lowest point}
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
childLeft += childWidth + lp.rightMargin;if(childTop + childHeight + lp.bottomMargin > lowestBottom){// New lowest point
lowestBottom = childTop + childHeight + lp.bottomMargin;}}}@Overridepublicboolean shouldDelayChildPressedState(){returnfalse;}@Overrideprotectedboolean checkLayoutParams(ViewGroup.LayoutParams p){return p instanceofLayoutParams;}@OverrideprotectedLayoutParams generateDefaultLayoutParams(){returnnewLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);}@OverridepublicLayoutParams generateLayoutParams(AttributeSet attrs){returnnewFlowLayout.LayoutParams(getContext(), attrs);}@OverrideprotectedViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp){if(lp instanceofLayoutParams){returnnewLayoutParams((LayoutParams) lp);}elseif(lp instanceofMarginLayoutParams){returnnewLayoutParams((MarginLayoutParams) lp);}elsereturnsuper.generateLayoutParams(lp);}/**
* Per-child layout information for layouts that support margins.
*/publicstaticclassLayoutParamsextendsMarginLayoutParams{publicLayoutParams(@NonNullContext c,@NullableAttributeSet attrs){super(c, attrs);}publicLayoutParams(int width,int height){super(width, height);}publicLayoutParams(@NonNullViewGroup.LayoutParams source){super(source);}publicLayoutParams(@NonNullViewGroup.MarginLayoutParams source){super(source);}publicLayoutParams(@NonNullLayoutParams source){super(source);}}}
Je me grattais la tête depuis 2 heures et seul ce morceau de code a fonctionné pour moi !! Pouvez-vous s'il vous plaît fournir une disposition de flux pour RadioGroup?
Pratik Saluja
Aussi, je veux savoir comment utiliser la marge? margin = 10dp provient correctement de la mise en page.
Pratik Saluja
1
@Pratik, si vous avez un petit RadioGroup et que vous voulez que d'autres vues s'affichent à côté de lui s'il y a de la place et passez à la ligne suivante s'il n'y a pas de place, le FlowLayout devrait fonctionner correctement. Un grand RadioGroup horizontal qui fait passer ses éléments RadioButton à la ligne suivante lorsque la première ligne est hors de la pièce nécessiterait l'écriture d'une classe de type RadioGroup personnalisée car RadioGroup étend LinearLayout. Vous pouvez écrire une classe RadioGroup personnalisée en utilisant les idées de cette classe FlowLayout. Jusqu'à présent, je n'ai pas eu besoin d'utiliser les boutons radio. Nous utilisons généralement des Spinners ou d'autres contrôles.
jk7
@Pratik, vous pouvez définir toutes les marges avec android:layout_margin="10dp"dans le fichier de mise en page, ou définir des marges individuelles avec des attributs tels que android:layout_marginLeft="10dp", android:layout_marginTop="4dp", ..etc.
Il existe maintenant une prise en charge intégrée dans ConstraintLayout à l'aide d'un widget Flow. Il dispose de nombreuses options qui peuvent être utilisées pour réaliser de nombreux types de flux.
Réponses:
Si vous regardez le discours que j'ai donné lors de la journée de l'Université Devoxx (disponible sur parleys.com ), vous apprendrez à le faire vous-même. Pendant la conférence, j'ai écrit une
FlowLayout
implémentation en direct sur scène pour montrer à quel point il est simple d'écrire des mises en page personnalisées.L'implémentation est hébergée ici .
la source
Vous devez utiliser
FlexboxLayout
avecflexWrap="wrap"
attribut.Pour obtenir des instructions de compilation, consultez le dépôt github.
En savoir plus à ce sujet - https://android-developers.googleblog.com/2017/02/build-flexible-layouts-with.html
la source
Je n'ai pas assez de réputation pour publier un commentaire sur la réponse de Romain Guy mais c'est là que devrait se trouver cette réponse (j'ai créé un compte juste pour partager ma modification).
Quoi qu'il en soit, je vois que d'autres personnes ont découvert que sa solution FlowLayout plutôt cool avait quelques problèmes. J'ai pu en trouver un moi-même et j'ai vu, comme d'autres, que certains enfants étaient coupés. En regardant en détail l'algorithme, cela semble être une erreur très simple dans le calcul de la hauteur. Lorsque le tout dernier enfant est celui qui est placé sur une nouvelle ligne, alors la hauteur n'a pas été correctement calculée. J'ai nettoyé un peu le calcul (il y avait une utilisation étrange de "height" par rapport à currentHeight).
La modification suivante résout le problème du «dernier enfant est coupé s'il est sur une nouvelle ligne»:
la source
Il existe une bibliothèque de Google, appelée "flexbox-layout" . Tu devrais y jeter un coup d'oeil.
Pour l'utiliser dans RecyclerView, vous pouvez utiliser quelque chose comme ça:
la source
Comme l'une des réponses précédentes, j'ai commencé avec la solution ici: http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Je l'ai étendu pour tenir compte des différentes hauteurs d'enfants comme ci-dessous.
J'ai utilisé cela comme une solution pour envelopper TextEdits multilignes. J'espère que ça aide!
la source
Voici la classe personnalisée où vous pouvez obtenir une mise en page comme suit avec l'ajout d'une vue dynamique (également appelée FlowLayout).
Exemple :
text_view.xml
activity_flow_layou_demo.xml
FlowLayouDemo.java
la source
Une révision de @MattNotEquals () FlowLayout qui prend en charge MarginLayoutParams.
Il s'agit simplement d'une implémentation minimaliste de MarginLayoutParms pour prendre en charge les marges gauche, droite, supérieure et inférieure.
la source
android:layout_margin="10dp"
dans le fichier de mise en page, ou définir des marges individuelles avec des attributs tels queandroid:layout_marginLeft="10dp"
,android:layout_marginTop="4dp"
, ..etc.Beau code FlowLayout autonome simple ici (juste quelques fichiers concis gist.github) :
http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Cependant, l'activité prête à l'emploi ne m'a pas permis de charger la mise en page personnalisée.
J'ai trouvé cette solution de contournement [en utilisant l'appel 2-param .inflate () de cet exemple ] :
la source
Il existe maintenant une prise en charge intégrée dans ConstraintLayout à l'aide d'un widget Flow. Il dispose de nombreuses options qui peuvent être utilisées pour réaliser de nombreux types de flux.
Exemple:
Jetez un œil à cet article: https://medium.com/@tapanrgohil/constraintlayout-flow-bye-bye-to-linerlayout-78fd7fa9b679
Et ici: https://www.bignerdranch.com/blog/constraintlayout-flow-simple-grid-building-without-nested-layouts/
la source