Android自定义流式布局-FlowLayout

    很多App在搜索页时都有对热门标签的一个排列,而Android官方没有对应的布局控件,所以自己写了一个流式布局(也称标签布局)--FlowLayout。

    为了大家使用的方便,没有添加自定义属性,所以需要在代码中设置下列两个属性值:

        /**
	 * 上下行间距
	 */
	public int veticalSpace = 30;
	/**
	 * Item间距
	 */
	public int horSpace = 30;

    其它的只需关注填充数据方法setAdapter,及设置点击事件setOnItemClick即可。


先上个效果图:

wKioL1W67kGymuW0AAGXc514TYw858.jpg

贴出完整代码,复制即用:


package com.custom.widget;

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;

public class FlowLayout extends AdapterView<ListAdapter> implements
		View.OnClickListener {
	private ListAdapter mAdapter;

	/**
	 * 上下行间距
	 */
	public int veticalSpace = 30;
	/**
	 * Item间距
	 */
	public int horSpace = 30;

	/**
	 * 每一行有多少个view
	 */
	private SparseIntArray mLineViews = new SparseIntArray();
	
	private AdapterDataSetObserver mDataSetObserver;
	
	/**
	 * 一行的高度由最高的item决定
	 */
	private int lineHeight;

	public FlowLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public ListAdapter getAdapter() {
		return mAdapter;
	}
		@Override
	public void setAdapter(ListAdapter adapter) {
		if (mAdapter != null && mDataSetObserver != null) {
			mAdapter.unregisterDataSetObserver(mDataSetObserver);
		}
		mAdapter = adapter;
		if (mAdapter != null) {
			mDataSetObserver = new AdapterDataSetObserver();
			mAdapter.registerDataSetObserver(mDataSetObserver);
			makeView();
		} else {
			removeAllViewsInLayout();
			invalidate();
		}
	}
	private void makeView() {
		removeAllViewsInLayout();
		int count = mAdapter.getCount();
		for (int i = 0; i < count; i++) {
			View child = mAdapter.getView(i, null, this);
			LayoutParams params = child.getLayoutParams();
			if (params == null)
				params = generateDefaultLayoutParams();
			addViewInLayout(child, i, params);
		}
	}
	
	private class AdapterDataSetObserver extends DataSetObserver {

		@Override
		public void onChanged() {
			super.onChanged();
			makeView();
			requestLayout();
		}
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
		int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

		int layoutWidth = 0;
		int layoutHeight = 0;
		
		int lineWidth = getPaddingLeft() + getPaddingRight();
		
		if (mAdapter == null)
			return;
		int count = getChildCount();
		mLineViews.clear();
		int lineCount = 0;
		int line = 0;
		for (int i = 0; i < count; i++) {
			View child = getChildAt(i);
			measureChild(child, widthMeasureSpec, heightMeasureSpec);
			lineHeight = Math.max(lineHeight, child.getMeasuredHeight());
			int childWidth = child.getMeasuredWidth();
			if (lineWidth + childWidth > widthSize) {
				mLineViews.put(line, lineCount);
				lineWidth -= horSpace;
				layoutWidth = Math.max(layoutWidth, lineWidth);
				line++;
				lineWidth = getPaddingLeft() + getPaddingRight();
				lineCount = 0;
			}
			lineCount++;
			lineWidth += childWidth + horSpace;

			if (i == count - 1) {
				mLineViews.put(line, lineCount);
				lineWidth -= horSpace;
				layoutWidth = Math.max(layoutWidth, lineWidth);
				lineCount = 0;
			}
		}

		if (modeWidth == MeasureSpec.EXACTLY) {
			layoutWidth = widthSize;
		}

		if (modeHeight == MeasureSpec.EXACTLY) {
			layoutHeight = heightSize;
		} else {
			int lines = mLineViews.size();
			layoutHeight = getPaddingTop() + getPaddingBottom() + lines
					* lineHeight + (lines - 1) * veticalSpace;
		}	
		setMeasuredDimension(layoutWidth, layoutHeight);

	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		int leftPos = 0;
		int topPos = 0;

		int lines = mLineViews.size();
		int lineCount;
		
		int position = 0;

		for (int i = 0; i < lines; i++) {
		    lineCount = mLineViews.get(i);
		    View child;

		    topPos = getPaddingTop() + i * veticalSpace + i * lineHeight;
	            leftPos = getPaddingLeft();

		    for (int j = 0; j < lineCount; j++) {
		        child = getChildAt(position);
			if (child == null)
				return;
			position++;
			child.setOnClickListener(this);
			int childWidth = child.getMeasuredWidth();
			child.layout(leftPos, topPos, leftPos + childWidth, topPos
					+ lineHeight);

			leftPos += childWidth + horSpace;
		    }
		}

	}
	
	@Override
	public void onClick(View v) {
		int pos = indexOfChild(v);
		performItemClick(v, pos, 0);
	}

	@Override
	public void setSelection(int position) {
		// TODO Auto-generated method stub

	}

	@Override
	public View getSelectedView() {
		// TODO Auto-generated method stub
		return null;
	}
	
}

    有些需求是对标签进行散乱排列的,这个计划有时间再写一个。


    

你可能感兴趣的:(FlowLayout,自定义布局,流式布局,标签布局)