在日常的app使用中,我們會在android 的app中看見熱門標簽等自動換行的流式布局,今天就為大家分享一種android流式布局的實現。
先看最終效果
自定義流式布局的實現
package com.sunny.flowlayout.view; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; public class FlowLayout extends ViewGroup { public FlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context) { this(context, null); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // wrap_content int width = 0; int height = 0; // 記錄每一行的寬度與高度 int lineWidth = 0; int lineHeight = 0; // 得到內部元素的個數 int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { View child = getChildAt(i); // 測量子View的寬和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); // 得到LayoutParams MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); // 子View占據的寬度 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; // 子View占據的高度 int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; // 換行 if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) { // 對比得到最大的寬度 width = Math.max(width, lineWidth); // 重置lineWidth lineWidth = childWidth; // 記錄行高 height += lineHeight; lineHeight = childHeight; } else // 未換行 { // 疊加行寬 lineWidth += childWidth; // 得到當前行最大的高度 lineHeight = Math.max(lineHeight, childHeight); } // 最后一個控件 if (i == cCount - 1) { width = Math.max(lineWidth, width); height += lineHeight; } } setMeasuredDimension( modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(), modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()// ); } /** * 存儲所有的View */ private List<List<View>> mAllViews = new ArrayList<List<View>>(); /** * 每一行的高度 */ private List<Integer> mLineHeight = new ArrayList<Integer>(); @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mAllViews.clear(); mLineHeight.clear(); // 當前ViewGroup的寬度 int width = getWidth(); int lineWidth = 0; int lineHeight = 0; List<View> lineViews = new ArrayList<View>(); int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { View child = getChildAt(i); MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); // 如果需要換行 if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width - getPaddingLeft() - getPaddingRight()) { // 記錄LineHeight mLineHeight.add(lineHeight); // 記錄當前行的Views mAllViews.add(lineViews); // 重置我們的行寬和行高 lineWidth = 0; lineHeight = childHeight + lp.topMargin + lp.bottomMargin; // 重置我們的View集合 lineViews = new ArrayList<View>(); } lineWidth += childWidth + lp.leftMargin + lp.rightMargin; lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin); lineViews.add(child); }// for end // 處理最后一行 mLineHeight.add(lineHeight); mAllViews.add(lineViews); // 設置子View的位置 int left = getPaddingLeft(); int top = getPaddingTop(); // 行數 int lineNum = mAllViews.size(); for (int i = 0; i < lineNum; i++) { // 當前行的所有的View lineViews = mAllViews.get(i); lineHeight = mLineHeight.get(i); for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); // 判斷child的狀態 if (child.getVisibility() == View.GONE) { continue; } MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); int lc = left + lp.leftMargin; int tc = top + lp.topMargin; int rc = lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); // 為子View進行布局 child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } left = getPaddingLeft(); top += lineHeight; } } /** * 與當前ViewGroup對應的LayoutParams */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }
流式布局代碼實現的注釋還算比較詳細,請參考具體代碼及注釋說明。
流式布局xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.sunny.flowlayout.view.FlowLayout android:id="@+id/id_flowlayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#E5E5F5" android:padding="20dp"> </com.sunny.flowlayout.view.FlowLayout> </RelativeLayout>
主頁面Activity的實現
package com.sunny.flowlayout; import com.sunny.flowlayout.view.FlowLayout; import android.R.mipmap; import android.os.Bundle; import android.app.ActionBar.LayoutParams; import android.app.Activity; import android.view.LayoutInflater; import android.view.Menu; import android.view.ViewGroup.MarginLayoutParams; import android.widget.Button; import android.widget.TextView; public class FlowLayoutActivity extends Activity { private FlowLayout mFlowLayout; private String[] mVals =new String[]{ "Hello","Android","Welcome","Music","Sport","Working", "Game","Fishing","Shopping","Music Singing","Sport happy", "Working Hard","Game Team","Fishing river","Shopping more" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_flow_layout); mFlowLayout = (FlowLayout) findViewById(R.id.id_flowlayout); initData(); } //初始化數據 public void initData(){ LayoutInflater mInflater = LayoutInflater.from(this); for (int i = 0; i < mVals.length; i++) { TextView tv = (TextView) mInflater.inflate(R.layout.tv, mFlowLayout, false); tv.setText(mVals[i]); mFlowLayout.addView(tv); } } }
TextView布局xml文件
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World" android:background="@drawable/textview_bg" android:layout_margin="5dp" android:textColor="#5BC4ED"> </TextView>
為TextView設置背景樣式
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="#ffffff"/> <corners android:radius="5dp"/> <padding android:top="2dp" android:left="10dp" android:right="10dp" android:bottom="2dp"/> </shape>
今天是第一次寫博客,今天是開始,我會一直堅持下去,歡迎大家一塊交流學習
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。