Wenn Sie sich den Vortrag ansehen, den ich am Tag der Devoxx-Universität gehalten habe (verfügbar auf parleys.com ), werden Sie lernen, wie man es selbst macht. Während des Vortrags habe ich eine FlowLayoutImplementierung live auf der Bühne geschrieben, um zu zeigen, wie einfach es ist, benutzerdefinierte Layouts zu schreiben.
danke romain kerl, das hilft wirklich. Wie wäre es nur mit der Lösung? oder Link? ... Ich verstehe nicht, wie Ihre Antwort akzeptiert wurde.
Johann Hilbold
4
@ JohannHilbold: Ich habe gerade die Links hinzugefügt
Macarse
7
Die Leser sind sich bewusst, dass der Code auf dem Link einige schwerwiegende Probleme aufweist und keine Drop-In-Lösung darstellt. Ich hatte bereits zwei Hauptprobleme in dieser kleinen Codebasis. Ich werde die Korrekturen nicht veröffentlichen, da es sich um Klebebandlösungen für meine speziellen Anforderungen handelt ...
Nemanja Kovacevic
6
Ich habe nie behauptet, es sei perfekt :)
Romain Guy
19
@RomainGuy der Punkt ist, vielleicht ist es dann doch nicht so einfach.
Jeffrey Blattman
69
Sie sollten FlexboxLayoutmit flexWrap="wrap"Attribut verwenden.
<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>
Dies sollte als Lösung markiert werden! Beste Antwort für dieses Problem bisher
x10sion
1
Um diese Antwort zu ergänzen, hat diese Bibliothek auch einen LayoutManager, wenn Sie diesen Effekt in einer RecyclerView
Ari
1
Bingo, Bango, Bongo. Wunderbare Bibliothek für die Verwendung von Flexbox in Android. Schön.
Joshua Pinter
23
Ich habe nicht genug Ruf, um einen Kommentar zu Romain Guys Antwort zu schreiben, aber dort sollte diese Antwort sein (ich habe ein Konto erstellt, nur um meine Bearbeitung zu teilen).
Wie auch immer, ich sehe, andere Leute haben herausgefunden, dass seine ziemlich coole FlowLayout-Lösung einige Probleme hat. Ich konnte selbst einen finden und sah wie andere, dass einige Kinder abgeschnitten waren. Wenn man den Algorithmus im Detail betrachtet, scheint es ein sehr einfacher Fehler bei der Berechnung der Höhe zu sein. Wenn das allerletzte Kind dasjenige ist, das in eine neue Zeile gesetzt wird, wurde die Größe nicht richtig berechnet. Ich habe die Berechnung ein wenig aufgeräumt (es gab eine seltsame Verwendung von "height" vs. currentHeight).
Die folgende Änderung behebt das Problem "Das letzte Kind wird in einer neuen Zeile abgeschnitten":
In bestimmten Fällen sehr nützlich. Hier ist eine Revision , die MarginLayoutParams unterstützt.
jk7
Schöne Lösung! margin funktioniert nur, nachdem es innerhalb der init-Methode festgelegt wurde, nicht jedoch aus dem Layout.
Pratik Saluja
6
Hier ist die benutzerdefinierte Klasse, in der Sie das Layout wie folgt erreichen können, indem Sie eine dynamische Ansicht hinzufügen (auch FlowLayout genannt).
Schöne Klasse, aber es würde einige Arbeit erfordern, um die Layoutrichtung von rechts nach links zu unterstützen.
Ted Hopp
Wie man Gegenstände in der Mitte macht.
Abhishek c
java.lang.ClassCastException: android.widget.LinearLayout $ LayoutParams kann nicht in com.nuveda.fillintheblank.FlowLayout $ LayoutParams umgewandelt werden
Naveen Kumar M
Ich denke, Sie versuchen, dynamische Parameter für Ihr Layout festzulegen, damit Probleme auftreten. Ich schlage vor, RelativeLayout.LayoutParams zu verwenden.
Dhaval Solanki
3
Eine Überarbeitung von @MattNotEquals () FlowLayout , die MarginLayoutParams unterstützt.
Dies ist nur eine minimalistische Implementierung von MarginLayoutParms zur Unterstützung des linken, rechten, oberen und unteren Randes.
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);}}}
Ich habe mir in den letzten 2 Stunden am Kopf gekratzt und nur dieser Code hat bei mir funktioniert !! Können Sie bitte ein Ablauflayout für RadioGroup bereitstellen?
Pratik Saluja
Außerdem möchte ich wissen, wie ich die Marge verwenden kann. margin = 10dp kommt richtig aus dem Layout.
Pratik Saluja
1
@Pratik, wenn Sie eine kleine RadioGroup haben und möchten, dass andere Ansichten daneben angezeigt werden, wenn Platz vorhanden ist, und zur nächsten Zeile fließen, wenn kein Platz vorhanden ist, sollte das FlowLayout einwandfrei funktionieren. Für eine große horizontale RadioGroup, bei der die RadioButton-Elemente in die nächste Zeile fließen, wenn in der ersten Zeile kein Platz mehr vorhanden ist, muss eine benutzerdefinierte Klasse vom Typ RadioGroup geschrieben werden, da RadioGroup LinearLayout erweitert. Mit den Ideen dieser FlowLayout-Klasse können Sie eine benutzerdefinierte RadioGroup-Klasse schreiben. Bisher musste ich keine Optionsfelder verwenden. Wir verwenden normalerweise Spinner oder andere Steuerelemente.
jk7
@Pratik, können Sie alle Ränder mit Set android:layout_margin="10dp"in der Layout - Datei oder stellen einzelne Ränder mit Attributen wie android:layout_marginLeft="10dp", android:layout_marginTop="4dp", .etc.
jk7
0
Schöner einfacher, in sich geschlossener FlowLayout-Code hier (nur ein paar prägnante gist.github-Dateien) :
In ConstraintLayout ist jetzt Unterstützung mithilfe eines Flow-Widgets integriert. Es gibt viele Optionen, mit denen viele Arten von Flüssen erzielt werden können.
Antworten:
Wenn Sie sich den Vortrag ansehen, den ich am Tag der Devoxx-Universität gehalten habe (verfügbar auf parleys.com ), werden Sie lernen, wie man es selbst macht. Während des Vortrags habe ich eine
FlowLayout
Implementierung live auf der Bühne geschrieben, um zu zeigen, wie einfach es ist, benutzerdefinierte Layouts zu schreiben.Die Implementierung wird hier gehostet .
quelle
Sie sollten
FlexboxLayout
mitflexWrap="wrap"
Attribut verwenden.Anweisungen zum Erstellen finden Sie im Github-Repo.
Mehr dazu - https://android-developers.googleblog.com/2017/02/build-flexible-layouts-with.html
quelle
Ich habe nicht genug Ruf, um einen Kommentar zu Romain Guys Antwort zu schreiben, aber dort sollte diese Antwort sein (ich habe ein Konto erstellt, nur um meine Bearbeitung zu teilen).
Wie auch immer, ich sehe, andere Leute haben herausgefunden, dass seine ziemlich coole FlowLayout-Lösung einige Probleme hat. Ich konnte selbst einen finden und sah wie andere, dass einige Kinder abgeschnitten waren. Wenn man den Algorithmus im Detail betrachtet, scheint es ein sehr einfacher Fehler bei der Berechnung der Höhe zu sein. Wenn das allerletzte Kind dasjenige ist, das in eine neue Zeile gesetzt wird, wurde die Größe nicht richtig berechnet. Ich habe die Berechnung ein wenig aufgeräumt (es gab eine seltsame Verwendung von "height" vs. currentHeight).
Die folgende Änderung behebt das Problem "Das letzte Kind wird in einer neuen Zeile abgeschnitten":
quelle
Es gibt eine Bibliothek von Google namens "Flexbox-Layout" . Sie sollten es überprüfen.
Um es in RecyclerView zu verwenden, können Sie Folgendes verwenden:
quelle
Wie bei einer der vorherigen Antworten habe ich hier mit der Lösung begonnen: http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Ich habe es erweitert, um die unterschiedlichen Kindergrößen wie unten zu berücksichtigen.
Ich habe dies als Lösung für das Umschließen mehrzeiliger TextEdits verwendet. Ich hoffe es hilft!
quelle
Hier ist die benutzerdefinierte Klasse, in der Sie das Layout wie folgt erreichen können, indem Sie eine dynamische Ansicht hinzufügen (auch FlowLayout genannt).
Beispiel:
text_view.xml
activity_flow_layou_demo.xml
FlowLayouDemo.java
quelle
Eine Überarbeitung von @MattNotEquals () FlowLayout , die MarginLayoutParams unterstützt.
Dies ist nur eine minimalistische Implementierung von MarginLayoutParms zur Unterstützung des linken, rechten, oberen und unteren Randes.
quelle
android:layout_margin="10dp"
in der Layout - Datei oder stellen einzelne Ränder mit Attributen wieandroid:layout_marginLeft="10dp"
,android:layout_marginTop="4dp"
, .etc.Schöner einfacher, in sich geschlossener FlowLayout-Code hier (nur ein paar prägnante gist.github-Dateien) :
http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Die sofort einsatzbereite Aktivität zum Laden des benutzerdefinierten Layouts funktionierte jedoch nicht.
Ich habe diese Problemumgehung gefunden [mit dem Aufruf von 2-param .inflate () aus diesem Beispiel ] :
quelle
In ConstraintLayout ist jetzt Unterstützung mithilfe eines Flow-Widgets integriert. Es gibt viele Optionen, mit denen viele Arten von Flüssen erzielt werden können.
Beispiel:
Schauen Sie sich diesen Beitrag an: https://medium.com/@tapanrgohil/constraintlayout-flow-bye-bye-to-linerlayout-78fd7fa9b679
Und hier: https://www.bignerdranch.com/blog/constraintlayout-flow-simple-grid-building-without-nested-layouts/
quelle