Если вы посмотрите мой доклад на дне университета Devoxx (доступен на parleys.com ), вы узнаете, как это сделать самостоятельно. Во время выступления я написалFlowLayout реализацию прямо на сцене, чтобы показать, насколько просто писать собственные макеты.
спасибо, Ромен, парень, это действительно помогает. как насчет того, чтобы просто дать решение? или ссылку? ... Я не понимаю, как ваш ответ был принят.
Иоганн Хильбольд
4
@JohannHilbold: Я только что добавил ссылки
Macarse
7
Читатели должны знать, что код по ссылке содержит несколько серьезных проблем и далек от простого решения. У меня уже были две серьезные проблемы с этой небольшой базой кода. Я не буду публиковать исправления, потому что они представляют собой клейкую ленту для моих конкретных потребностей ...
Неманья Ковачевич
6
Я никогда не утверждал, что он идеален :)
Romain Guy
19
@RomainGuy дело в том, может быть, тогда все не так просто.
Джеффри Блаттман 08
72
Вы должны использовать FlexboxLayoutс flexWrap="wrap"атрибутом.
<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>
Это должно быть отмечено как решение! Лучший ответ на эту проблему на данный момент
x10sion 02
1
Чтобы добавить к этому ответу, эта библиотека также имеет LayoutManager, если вы хотите иметь этот эффект в RecyclerView
Ари
1
Бинго, банго, бонго. Замечательная библиотека для использования Flexbox в Android. Хороший.
Джошуа Пинтер,
23
У меня недостаточно репутации, чтобы опубликовать комментарий к ответу Ромена Гая, но именно там должен быть этот ответ (я создал учетную запись, чтобы поделиться своим изменением).
В любом случае, я вижу, что другие люди обнаружили, что у его довольно крутого решения FlowLayout есть некоторые проблемы. Я сам мог найти одного и, как и другие, видел, что некоторых детей подрезали. При детальном рассмотрении алгоритма кажется, что при расчете высоты произошла очень простая ошибка. Когда самый последний дочерний элемент помещается на новую строку, значит, высота не была правильно вычислена. Я немного очистил вычисления (было странное использование "высоты" по сравнению с currentHeight).
Следующее изменение устраняет проблему «последний дочерний элемент обрезается, если находится на новой строке»:
Очень полезно в некоторых случаях. Вот версия, которая поддерживает MarginLayoutParams.
jk7
Хорошее решение! маржа работает только после установки внутри метода инициализации, но не из макета.
Pratik Saluja
6
Вот пользовательский класс, в котором вы можете создать макет, как показано ниже, с добавлением динамического представления (также называемого FlowLayout).
Хороший класс, но потребуется некоторая работа для поддержки направления макета справа налево.
Тед Хопп
Как разместить предметы в центре.
Abhishek c
java.lang.ClassCastException: android.widget.LinearLayout $ LayoutParams не может быть преобразован в com.nuveda.fillintheblank.FlowLayout $ LayoutParams
Naveen Kumar M
Я думаю, вы пытаетесь установить динамические параметры для своего макета, поэтому возникают проблемы, я предлагаю использовать RelativeLayout.LayoutParams.
Дхавал Соланки
3
Версия @MattNotEquals () FlowLayout, которая поддерживает MarginLayoutParams.
Это просто минималистичная реализация MarginLayoutParms для поддержки левого, правого, верхнего и нижнего полей.
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);}}}
Я чесал голову последние 2 часа, и только этот фрагмент кода работал у меня !! Не могли бы вы предоставить схему потока для RadioGroup?
Pratik Saluja
Кроме того, я хочу знать, как использовать маржу? margin = 10dp поступает правильно из макета.
Pratik Saluja 03
1
@Pratik, если у вас небольшая RadioGroup и вы хотите, чтобы рядом с ней отображались другие представления, если есть место, и переход к следующей строке, если места нет, FlowLayout должен работать нормально. Большой горизонтальный RadioGroup, который заставляет его элементы RadioButton переходить к следующей строке, когда первая строка выходит за пределы места, потребует записи настраиваемого класса типа RadioGroup, поскольку RadioGroup расширяет LinearLayout. Вы можете написать собственный класс RadioGroup, используя идеи этого класса FlowLayout. Пока у меня не было необходимости использовать радиокнопки. Обычно мы используем спиннеры или другие элементы управления.
jk7 05
@Pratik, вы можете установить все поля с android:layout_margin="10dp"в файле макета, или задать индивидуальные поля с атрибутами , такими как android:layout_marginLeft="10dp", android:layout_marginTop="4dp", ..etc.
jk7 05
0
Хороший простой автономный код FlowLayout здесь (всего несколько сжатых файлов gist.github) :
Теперь в ConstraintLayout встроена поддержка с использованием виджета Flow. Он имеет множество опций, которые можно использовать для создания различных типов потоков.
Ответы:
Если вы посмотрите мой доклад на дне университета Devoxx (доступен на parleys.com ), вы узнаете, как это сделать самостоятельно. Во время выступления я написал
FlowLayout
реализацию прямо на сцене, чтобы показать, насколько просто писать собственные макеты.Реализация размещена здесь .
источник
Вы должны использовать
FlexboxLayout
сflexWrap="wrap"
атрибутом.Инструкции по сборке см. В репозитории на github.
Подробнее об этом - https://android-developers.googleblog.com/2017/02/build-f flexible-layouts-with.html.
источник
У меня недостаточно репутации, чтобы опубликовать комментарий к ответу Ромена Гая, но именно там должен быть этот ответ (я создал учетную запись, чтобы поделиться своим изменением).
В любом случае, я вижу, что другие люди обнаружили, что у его довольно крутого решения FlowLayout есть некоторые проблемы. Я сам мог найти одного и, как и другие, видел, что некоторых детей подрезали. При детальном рассмотрении алгоритма кажется, что при расчете высоты произошла очень простая ошибка. Когда самый последний дочерний элемент помещается на новую строку, значит, высота не была правильно вычислена. Я немного очистил вычисления (было странное использование "высоты" по сравнению с currentHeight).
Следующее изменение устраняет проблему «последний дочерний элемент обрезается, если находится на новой строке»:
источник
Есть библиотека от Google, которая называется «flexbox-layout» . Вам стоит это увидеть.
Чтобы использовать его в RecyclerView, вы можете использовать что-то вроде этого:
источник
Как и один из предыдущих ответов, я начал с решения здесь: http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Я расширил его, чтобы учесть разный рост детей, как показано ниже.
Я использовал это как решение для упаковки многострочного TextEdits. Надеюсь, поможет!
источник
Вот пользовательский класс, в котором вы можете создать макет, как показано ниже, с добавлением динамического представления (также называемого FlowLayout).
Пример :
text_view.xml
activity_flow_layou_demo.xml
FlowLayouDemo.java
источник
Версия @MattNotEquals () FlowLayout, которая поддерживает MarginLayoutParams.
Это просто минималистичная реализация MarginLayoutParms для поддержки левого, правого, верхнего и нижнего полей.
источник
android:layout_margin="10dp"
в файле макета, или задать индивидуальные поля с атрибутами , такими какandroid:layout_marginLeft="10dp"
,android:layout_marginTop="4dp"
, ..etc.Хороший простой автономный код FlowLayout здесь (всего несколько сжатых файлов gist.github) :
http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Однако действия там из коробки не помогли мне загрузить настраиваемый макет.
Я нашел этот обходной путь [используя вызов 2-param .inflate () из этого примера ] :
источник
Теперь в ConstraintLayout встроена поддержка с использованием виджета Flow. Он имеет множество опций, которые можно использовать для создания различных типов потоков.
Пример:
Взгляните на этот пост: https://medium.com/@tapanrgohil/constraintlayout-flow-bye-bye-to-linerlayout-78fd7fa9b679
И здесь: https://www.bignerdranch.com/blog/constraintlayout-flow-simple-grid-building-without-nested-layouts/
источник