溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

android流式布局熱門標(biāo)簽的實(shí)現(xiàn)

發(fā)布時(shí)間:2020-09-17 19:45:04 來源:網(wǎng)絡(luò) 閱讀:1596 作者:sunnyhack 欄目:移動(dòng)開發(fā)

        在日常的app使用中,我們會(huì)在android 的app中看見熱門標(biāo)簽等自動(dòng)換行的流式布局,今天就為大家分享一種android流式布局的實(shí)現(xiàn)。

        先看最終效果

android流式布局熱門標(biāo)簽的實(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í)

    

附件:http://down.51cto.com/data/2365789
向AI問一下細(xì)節(jié)

免責(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)容。

AI