Se você assistir à palestra que dei no dia da Devoxx University (disponível em parleys.com ), você aprenderá a fazer isso sozinho. Durante a palestra eu escrevi umFlowLayout implementação ao vivo no palco para mostrar como é simples escrever layouts personalizados.
Obrigado, cara, isso realmente ajuda. que tal apenas dar a solução? ou link? ... Não entendi como sua resposta foi aceita.
Johann Hilbold
4
@JohannHilbold: Acabei de adicionar os links
Macarse
7
Os leitores devem estar cientes de que o código no link tem alguns problemas sérios e está longe de ser uma solução drop-in. Já tive dois problemas principais nesta pequena base de código. Não vou postar as correções porque são soluções de fita adesiva para minhas necessidades específicas ...
Nemanja Kovacevic
6
Eu nunca disse que era perfeito :)
Romain Guy
19
@RomainGuy, a questão é que talvez não seja tão simples assim, afinal.
Jeffrey Blattman
70
Você deve usar FlexboxLayoutcom flexWrap="wrap"atributo.
<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>
Isso deve ser marcado como a solução! Melhor resposta para este problema até agora
x10sion
1
Para adicionar a essa resposta, essa lib também tem um LayoutManager se você quiser ter esse efeito em um RecyclerView
Ari
1
Bingo, bango, bongô. Biblioteca maravilhosa para usar Flexbox no Android. Agradável.
Joshua Pinter
23
Não tenho reputação suficiente para postar um comentário sobre a resposta de Romain Guy, mas é onde esta resposta deve estar (criei uma conta apenas para compartilhar minha edição).
De qualquer forma, vejo que outras pessoas descobriram que sua solução FlowLayout muito legal tem alguns problemas. Eu próprio consegui encontrar um e vi, como outros, que algumas crianças foram cortadas. Olhando em detalhes no algoritmo, parece ser um erro muito simples no cálculo da altura. Quando o último filho é aquele que está sendo colocado em uma nova linha, a altura não foi computada corretamente. Limpei um pouco o cálculo (havia um uso estranho de "altura" vs. altura atual).
A seguinte alteração corrige o problema de "o último filho é cortado se estiver em uma nova linha":
Boa aula, mas precisaria de algum trabalho para suportar a direção do layout da direita para a esquerda.
Ted Hopp
Como fazer itens no centro.
Abhishek c
java.lang.ClassCastException: android.widget.LinearLayout $ LayoutParams não pode ser convertido para com.nuveda.fillintheblank.FlowLayout $ LayoutParams
Naveen Kumar M
Eu acho que você está tentando definir parâmetros dinâmicos para seu layout, então está criando problemas, eu sugiro usar RelativeLayout.LayoutParams.
Dhaval Solanki
3
Uma revisão para @MattNotEquals () FlowLayout que oferece suporte a MarginLayoutParams.
Esta é apenas uma implementação minimalista de MarginLayoutParms para oferecer suporte às margens esquerda, direita, superior e inferior.
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);}}}
Eu estava coçando minha cabeça nas últimas 2 horas e apenas este pedaço de código funcionou para mim !! Você pode fornecer um layout de fluxo para o RadioGroup?
Pratik Saluja
Além disso, quero saber como posso usar a margem? margin = 10dp está vindo corretamente do layout.
Pratik Saluja
1
@Pratik, se você tem um RadioGroup pequeno e deseja que outras visualizações sejam exibidas ao lado dele se houver espaço e flua para a próxima linha se não houver espaço, o FlowLayout deve funcionar bem. Um grande RadioGroup horizontal que faz com que seus itens RadioButton fluam para a próxima linha quando a primeira linha está fora do espaço exigiria uma classe personalizada do tipo RadioGroup a ser escrita, uma vez que RadioGroup estende LinearLayout. Você pode escrever uma classe RadioGroup personalizada usando as idéias desta classe FlowLayout. Até agora, não precisei usar botões de rádio. Normalmente usamos Spinners ou outros controles.
jk7
@Pratik, você pode definir todas as margens com android:layout_margin="10dp"no arquivo de layout, ou definir as margens individuais com atributos tais como android:layout_marginLeft="10dp", android:layout_marginTop="4dp", .etc.
Agora há suporte integrado no ConstraintLayout usando um widget de fluxo. Ele tem muitas opções que podem ser usadas para atingir vários tipos de fluxos.
Respostas:
Se você assistir à palestra que dei no dia da Devoxx University (disponível em parleys.com ), você aprenderá a fazer isso sozinho. Durante a palestra eu escrevi um
FlowLayout
implementação ao vivo no palco para mostrar como é simples escrever layouts personalizados.A implementação está hospedada aqui .
fonte
Você deve usar
FlexboxLayout
comflexWrap="wrap"
atributo.Para obter instruções de compilação, consulte o repositório github.
Mais sobre isso - https://android-developers.googleblog.com/2017/02/build-flexible-layouts-with.html
fonte
Não tenho reputação suficiente para postar um comentário sobre a resposta de Romain Guy, mas é onde esta resposta deve estar (criei uma conta apenas para compartilhar minha edição).
De qualquer forma, vejo que outras pessoas descobriram que sua solução FlowLayout muito legal tem alguns problemas. Eu próprio consegui encontrar um e vi, como outros, que algumas crianças foram cortadas. Olhando em detalhes no algoritmo, parece ser um erro muito simples no cálculo da altura. Quando o último filho é aquele que está sendo colocado em uma nova linha, a altura não foi computada corretamente. Limpei um pouco o cálculo (havia um uso estranho de "altura" vs. altura atual).
A seguinte alteração corrige o problema de "o último filho é cortado se estiver em uma nova linha":
fonte
Existe uma biblioteca do Google, chamada "flexbox-layout" . Você deveria dar uma olhada.
Para usá-lo no RecyclerView, você pode usar algo assim:
fonte
Como uma das respostas anteriores, comecei com a solução aqui: http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Eu o estendi para explicar as diferentes alturas das crianças, conforme abaixo.
Usei isso como uma solução para agrupar TextEdits de várias linhas. Espero que ajude!
fonte
Aqui está a classe personalizada onde você pode obter um layout como seguir com a adição de visualização dinâmica (também chamado de FlowLayout).
Exemplo:
text_view.xml
activity_flow_layou_demo.xml
FlowLayouDemo.java
fonte
Uma revisão para @MattNotEquals () FlowLayout que oferece suporte a MarginLayoutParams.
Esta é apenas uma implementação minimalista de MarginLayoutParms para oferecer suporte às margens esquerda, direita, superior e inferior.
fonte
android:layout_margin="10dp"
no arquivo de layout, ou definir as margens individuais com atributos tais comoandroid:layout_marginLeft="10dp"
,android:layout_marginTop="4dp"
, .etc.Bom código FlowLayout autocontido simples aqui (apenas alguns arquivos gist.github concisos) :
http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
No entanto, a atividade pronta para uso não funcionou para eu carregar o layout personalizado.
Eu encontrei esta solução [usando a chamada .inflate () de 2 parâmetros deste exemplo ] :
fonte
Agora há suporte integrado no ConstraintLayout usando um widget de fluxo. Ele tem muitas opções que podem ser usadas para atingir vários tipos de fluxos.
Exemplo:
Dê uma olhada nesta postagem: https://medium.com/@tapanrgohil/constraintlayout-flow-bye-bye-to-linerlayout-78fd7fa9b679
E aqui: https://www.bignerdranch.com/blog/constraintlayout-flow-simple-grid-building-without-nested-layouts/
fonte