您好,登錄后才能下訂單哦!
本篇文章為大家展示了如何在Android中實現一個流式布局,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
現下流式布局:
onMeasure
onLayout
通過以上兩個方法我們就可以完成對流式布局的基本操作:
onMeasure
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 獲得它的父容器為它設置的測量模式和大小 int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // 如果是warp_content情況下,記錄寬和高 int width = 0; int height = 0; //記錄每一行的寬度,width不斷取最大寬度 int lineWidth = 0; //記錄每一行的寬度,不斷累加每行最大高度獲取height int lineHeight = 0; //獲取子View的數量 int childCount = getChildCount(); //遍歷每個子元素 for (int i = 0; i < childCount; i++) { //獲取每一個子View View childView = getChildAt(i); //測量每一個子View的寬和高 measureChild(childView,widthMeasureSpec,heightMeasureSpec); //得到子View的lp LayoutParam lp = (LayoutParam) childView.getLayoutParams(); //當前子View實際占據的寬度 int childWidth = childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; //當前子View實際占據的高度 int childHeight = childView.getMeasuredHeight() + lp.bottomMargin + lp.topMargin; //如果加入當前childView,超出最大寬度,則得到目前最大寬度給width,類加height 然后開啟新行 if (lineWidth + childWidth > sizeWidth) { // 取最大的寬度 width = Math.max(lineWidth, childWidth); //重新開啟新行,重新計算 lineWidth = childWidth; //疊加當前高度 height += childHeight; //記錄下一行高度 lineHeight = childHeight; }else { // 累加值lineWidth,lineHeight取最大高度 lineWidth += childWidth; lineHeight = Math.max(lineHeight,childHeight); } // 如果是最后一個,則將當前記錄的最大寬度和當前lineWidth做比較 if (i == childCount - 1) { width = Math.max(width,lineWidth); height += lineHeight; } } setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY?sizeWidth:width,modeHeight == MeasureSpec.EXACTLY?sizeHeight:height); }
在onMeasure方法中負責設置子控件的測量模式和大小 根據所有子控件設置自己的寬和高,一旦寬度超出最大寬度便進行換行處理。高度不斷累加從而獲取最終高度。
onLayout
//存儲所有的View,按行記錄 private List<List<View>> mAllViews = new ArrayList<>(); //記錄每一行的最大高度 private List<Integer> mLineHeight = new ArrayList<>(); @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mAllViews.clear(); mLineHeight.clear(); int lineWidth = 0; int lineHeight = 0; int width = getWidth(); int childCount = getChildCount(); // 存儲每一行所有的childView List<View> lineViews = new ArrayList<>(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); LayoutParam lp = (LayoutParam) childView.getLayoutParams(); int childWidth = childView.getMeasuredWidth() + lp.rightMargin + lp.leftMargin; int childHeight = childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; if (lineWidth + childWidth > width) { // 記錄這一行所有的View以及最大高度 mLineHeight.add(lineHeight); // 將當前行的childView保存,然后開啟新的ArrayList保存下一行的childView mAllViews.add(lineViews); lineWidth = 0; lineViews = new ArrayList<>(); } //如果不需要換行,則累加 lineWidth += childWidth; lineHeight = Math.max(lineHeight,childHeight); lineViews.add(childView); } // 記錄最后一行 mAllViews.add(lineViews); mLineHeight.add(lineHeight); int left = 0; int top = 0; // 得到總行數 int size = mAllViews.size(); for (int i = 0; i < size; i++) { // 每一行的所有的views lineViews = mAllViews.get(i); // 當前行的最大高度 lineHeight = mLineHeight.get(i); for (View view : lineViews) { LayoutParam lp = (LayoutParam) view.getLayoutParams(); //計算childView的left,top,right,bottom int lc = left + lp.leftMargin; int tc = top + lp.topMargin; int rc = lc + view.getMeasuredWidth(); int bc = tc + view.getMeasuredHeight(); view.layout(lc,tc,rc,bc); left += view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } left = 0; top += lineHeight; } }
通過onLayout方法給子View布局,前提,我們必須得知道每個子View的寬度和高度。所以我們先要在onMeasure的時候,測量一下每個子View的具體大小。
測試
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FlowLayout flowLayout = ((FlowLayout) findViewById(R.id.flowLayout)); FlowLayout.LayoutParam params = new FlowLayout.LayoutParam(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.setMargins(10,10,10,10); for (int i = 0; i < 10; i++) { TextView textView = new TextView(this); textView.setPadding(i * 10,10,i * 10,10); textView.setBackgroundColor(Color.BLUE); textView.setText("哈哈哈哈"); textView.setTextColor(Color.WHITE); textView.setLayoutParams(params); flowLayout.addView(textView); } } }
這里我們要注意下FlowLayout.LayoutParam params = new FlowLayout.LayoutParam(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);這個方法,有的小伙伴在寫的過程中可能點不出來這個方法,那是因為這個方法是需要我們自己寫一個靜態內部類來實現。
@Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParam(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParam(getContext(),attrs); } @Override protected LayoutParams generateLayoutParams(LayoutParams p) { return new LayoutParam(p); } public static class LayoutParam extends MarginLayoutParams{ public LayoutParam(Context c, AttributeSet attrs) { super(c, attrs); } public LayoutParam(@Px int width, @Px int height) { super(width, height); } public LayoutParam(MarginLayoutParams source) { super(source); } public LayoutParam(LayoutParams source) { super(source); } }
上述內容就是如何在Android中實現一個流式布局,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。