Jika Anda menonton ceramah yang saya berikan pada hari Universitas Devoxx (tersedia di parleys.com ), Anda akan belajar bagaimana melakukannya sendiri. Selama pembicaraan saya menulis FlowLayoutimplementasi langsung di atas panggung untuk menunjukkan betapa sederhananya menulis tata letak khusus.
terima kasih romain guy, itu sangat membantu. bagaimana dengan solusinya saja? atau link? ... Saya tidak mengerti bagaimana jawaban Anda diterima.
Johann Hilbold
4
@JohannHilbold: Saya baru saja menambahkan tautan
Macarse
7
Pembaca mengetahui bahwa kode pada tautan memiliki beberapa masalah serius dan jauh dari solusi drop-in. Saya sudah memiliki dua masalah utama dalam basis kode kecil ini. Saya tidak akan memposting perbaikan karena itu adalah solusi lakban untuk kebutuhan khusus saya ...
Nemanja Kovacevic
6
Saya tidak pernah mengklaim itu sempurna :)
Romain Guy
19
@RomainGuy intinya adalah, mungkin tidak sesederhana itu.
Jeffrey Blattman
71
Anda harus menggunakan FlexboxLayoutdengan flexWrap="wrap"atribut.
<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>
Ini harus ditandai sebagai solusinya! Jawaban terbaik untuk masalah ini sejauh ini
x10sion
1
Untuk menambah jawaban ini, lib itu juga memiliki LayoutManager jika Anda ingin memiliki efek ini di RecyclerView
Ari
1
Bingo, bango, bongo. Perpustakaan luar biasa untuk menggunakan Flexbox di Android. Bagus.
Joshua Pinter
23
Saya tidak memiliki reputasi yang cukup untuk mengirim komentar ke jawaban Romain Guy tetapi di situlah seharusnya jawaban ini (saya membuat akun hanya untuk membagikan hasil edit saya).
Bagaimanapun, saya melihat orang lain telah menemukan solusi FlowLayout yang cukup keren memiliki beberapa masalah. Saya dapat menemukannya sendiri dan saya melihat, seperti yang lainnya, bahwa beberapa anak dipotong. Melihat secara detail pada algoritme, tampaknya itu adalah kesalahan yang sangat sederhana dalam penghitungan ketinggian. Ketika anak terakhir yang diletakkan di baris baru, maka tingginya tidak dihitung dengan benar. Saya membersihkan sedikit komputasi (ada penggunaan aneh "height" vs currentHeight).
Perubahan berikut memperbaiki masalah "anak terakhir dipotong jika di baris baru":
Kelas yang bagus, tetapi perlu beberapa pekerjaan untuk mendukung arah tata letak kanan-ke-kiri.
Ted Hopp
Cara membuat barang di tengah.
Abhishek c
java.lang.ClassCastException: android.widget.LinearLayout $ LayoutParams tidak dapat dilemparkan ke com.nuveda.fillintheblank.FlowLayout $ LayoutParams
Naveen Kumar M
Saya pikir Anda mencoba untuk mengatur parameter Dinamis untuk tata letak Anda sehingga membuat masalah, saya sarankan menggunakan RelativeLayout.LayoutParams.
Dhaval Solanki
3
Revisi untuk @MattNotEquals () FlowLayout yang mendukung MarginLayoutParams.
Ini hanyalah implementasi minimalis MarginLayoutParms untuk mendukung margin kiri, kanan, atas, dan bawah.
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);}}}
Saya menggaruk-garuk kepala saya dari 2 jam terakhir dan hanya potongan kode ini yang berhasil untuk saya !! Bisakah Anda memberikan tata letak aliran untuk RadioGroup?
Pratik Saluja
Juga, saya ingin tahu bagaimana cara menggunakan margin? margin = 10dp datang dengan benar dari tata letak.
Pratik Saluja
1
@Pratik, jika Anda memiliki RadioGroup kecil dan Anda ingin tampilan lain ditampilkan di sampingnya jika ada ruang dan mengalir ke baris berikutnya jika tidak ada ruang, FlowLayout akan berfungsi dengan baik. Sebuah RadioGroup horizontal besar yang menyebabkan item RadioButton mengalir ke baris berikutnya ketika baris pertama keluar dari ruangan akan membutuhkan kelas tipe RadioGroup khusus untuk ditulis karena RadioGroup memperluas LinearLayout. Anda dapat menulis kelas RadioGroup kustom menggunakan ide dari kelas FlowLayout ini. Sejauh ini saya tidak perlu menggunakan tombol Radio. Kami biasanya menggunakan Pemintal atau kontrol lainnya.
jk7
@Pratik, Anda dapat mengatur semua margin dengan android:layout_margin="10dp"di tata letak file, atau mengatur margin individu dengan atribut seperti android:layout_marginLeft="10dp", android:layout_marginTop="4dp", ..etc.
jk7
0
Kode FlowLayout mandiri sederhana yang bagus di sini (hanya beberapa file gist.github ringkas) :
Sekarang ada dukungan bawaan di ConstraintLayout menggunakan widget Flow. Ini memiliki banyak opsi yang dapat digunakan untuk mencapai banyak jenis aliran.
Jawaban:
Jika Anda menonton ceramah yang saya berikan pada hari Universitas Devoxx (tersedia di parleys.com ), Anda akan belajar bagaimana melakukannya sendiri. Selama pembicaraan saya menulis
FlowLayout
implementasi langsung di atas panggung untuk menunjukkan betapa sederhananya menulis tata letak khusus.Penerapannya dihosting di sini .
sumber
Anda harus menggunakan
FlexboxLayout
denganflexWrap="wrap"
atribut.Untuk instruksi pembuatan, lihat repo github.
Selengkapnya tentang ini - https://android-developers.googleblog.com/2017/02/build-flexible-layouts-with.html
sumber
Saya tidak memiliki reputasi yang cukup untuk mengirim komentar ke jawaban Romain Guy tetapi di situlah seharusnya jawaban ini (saya membuat akun hanya untuk membagikan hasil edit saya).
Bagaimanapun, saya melihat orang lain telah menemukan solusi FlowLayout yang cukup keren memiliki beberapa masalah. Saya dapat menemukannya sendiri dan saya melihat, seperti yang lainnya, bahwa beberapa anak dipotong. Melihat secara detail pada algoritme, tampaknya itu adalah kesalahan yang sangat sederhana dalam penghitungan ketinggian. Ketika anak terakhir yang diletakkan di baris baru, maka tingginya tidak dihitung dengan benar. Saya membersihkan sedikit komputasi (ada penggunaan aneh "height" vs currentHeight).
Perubahan berikut memperbaiki masalah "anak terakhir dipotong jika di baris baru":
sumber
Ada pustaka dari Google, yang disebut "flexbox-layout" . Anda harus memeriksanya.
Untuk menggunakannya di RecyclerView, Anda bisa menggunakan sesuatu seperti itu:
sumber
Seperti salah satu jawaban sebelumnya, saya mulai dengan solusi di sini: http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Saya memperluasnya untuk menjelaskan berbagai ketinggian anak-anak seperti di bawah ini.
Saya menggunakan ini sebagai solusi untuk membungkus TextEdits multi-baris. Semoga membantu!
sumber
Berikut adalah kelas khusus tempat Anda bisa mencapai tata letak seperti berikut dengan menambahkan tampilan dinamis (Juga disebut FlowLayout).
Contoh:
text_view.xml
activity_flow_layou_demo.xml
FlowLayouDemo.java
sumber
Revisi untuk @MattNotEquals () FlowLayout yang mendukung MarginLayoutParams.
Ini hanyalah implementasi minimalis MarginLayoutParms untuk mendukung margin kiri, kanan, atas, dan bawah.
sumber
android:layout_margin="10dp"
di tata letak file, atau mengatur margin individu dengan atribut sepertiandroid:layout_marginLeft="10dp"
,android:layout_marginTop="4dp"
, ..etc.Kode FlowLayout mandiri sederhana yang bagus di sini (hanya beberapa file gist.github ringkas) :
http://hzqtc.github.io/2013/12/android-custom-layout-flowlayout.html
Namun, aktivitas di luar kotak tidak berhasil bagi saya untuk memuat tata letak khusus.
Saya menemukan solusi ini [menggunakan panggilan 2-param .inflate () dari contoh ini ] :
sumber
Sekarang ada dukungan bawaan di ConstraintLayout menggunakan widget Flow. Ini memiliki banyak opsi yang dapat digunakan untuk mencapai banyak jenis aliran.
Contoh:
Lihatlah posting ini: https://medium.com/@tapanrgohil/constraintlayout-flow-bye-bye-to-linerlayout-78fd7fa9b679
Dan di sini: https://www.bignerdranch.com/blog/constraintlayout-flow-simple-grid-building-without-nested-layouts/
sumber