您好,登錄后才能下訂單哦!
在日常的app使用中,我們會(huì)在android 的app中看見熱門標(biāo)簽等自動(dòng)換行的流式布局,今天就為大家分享一種android流式布局的實(shí)現(xiàn)。
先看最終效果
自定義流式布局的實(shí)現(xiàn)
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; // 得到內(nèi)部元素的個(gè)數(shù) int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { View child = getChildAt(i); // 測(cè)量子View的寬和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); // 得到LayoutParams MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); // 子View占據(jù)的寬度 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; // 子View占據(jù)的高度 int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; // 換行 if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) { // 對(duì)比得到最大的寬度 width = Math.max(width, lineWidth); // 重置lineWidth lineWidth = childWidth; // 記錄行高 height += lineHeight; lineHeight = childHeight; } else // 未換行 { // 疊加行寬 lineWidth += childWidth; // 得到當(dāng)前行最大的高度 lineHeight = Math.max(lineHeight, childHeight); } // 最后一個(gè)控件 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()// ); } /** * 存儲(chǔ)所有的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(); // 當(dāng)前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); // 記錄當(dāng)前行的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); // 設(shè)置子View的位置 int left = getPaddingLeft(); int top = getPaddingTop(); // 行數(shù) int lineNum = mAllViews.size(); for (int i = 0; i < lineNum; i++) { // 當(dāng)前行的所有的View lineViews = mAllViews.get(i); lineHeight = mLineHeight.get(i); for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); // 判斷child的狀態(tài) 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進(jìn)行布局 child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; } left = getPaddingLeft(); top += lineHeight; } } /** * 與當(dāng)前ViewGroup對(duì)應(yīng)的LayoutParams */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }
流式布局代碼實(shí)現(xiàn)的注釋還算比較詳細(xì),請(qǐng)參考具體代碼及注釋說明。
流式布局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>
主頁(yè)面Activity的實(shí)現(xiàn)
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(); } //初始化數(shù)據(jù) 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設(shè)置背景樣式
<?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>
今天是第一次寫博客,今天是開始,我會(huì)一直堅(jiān)持下去,歡迎大家一塊交流學(xué)習(xí)
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。