今天搞了一个流式布局:如图
网上也有博客讲这方面的,只是每个人实现思路不一样,这是在网上看到一篇文章讲这个,我看了下,说下这个怎么实现原理,网上好多是直接继承了ViewGroup,那样的话就有个换行和计算子view的大小.子view的排放位置,但是这个就省略了那么多复杂的过程,因为我继承的是RelativeLayout,这样就不用实现onLayout()方法去计算每个子view排放的位置,而且我这个view是用布局文件实现的,画个图理解下
现在就有个问题了,因为是继承了RelativeLayout,那么它的位置是相对的,这个时候就要用到view的id了,那我们是给每个tag view设置id么,其实这个可以取巧的,因为我们是添加很多tagview,所以可以用标表示layout id,这样处理就方便多了,
现在贴代码:很多地方都注释了,如果想处理点击事件的话,看懂了,就很简单
activty_main.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.zhimore.customflowlayout.view.FlowLayout
xmlns:zhimore="http://schemas.android.com/apk/res-auto"
android:id="@+id/flowlayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingLeft="3dp"
zhimore:isDeletable="false"
zhimore:tagBackgroundColor="#ffff0000"
zhimore:tagTextSize="6sp"
zhimore:tagTextColor="#333333"
android:background="#ffffff"
zhimore:deletableTextSize="8sp"
zhimore:deletableTextColor="#ff9acd32"
/>
</RelativeLayout>
FlowLayout.java
package com.zhimore.customflowlayout.view;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.zhimore.customflowlayout.R;
import com.zhimore.customflowlayout.bean.TagView;
public class FlowLayout extends RelativeLayout {
private static final int DEFAULT_TAG_LAYOUT_COLOR = Color.parseColor("#aa66cc");//标签默认背景
private static final int DEFAULT_TAG_TEXT_COLOR = Color.parseColor("#1a1a1a");//标签文字的文字颜色
private static final int DEFAULT_DELETABLE_TEXT_COLOR = Color.parseColor("#1a1a1a");
private static final int INNER_VIEW_PADDING = 25;
private static final int DEFAULT_TEXT_SIZE = 14;
private static final int WIDTH = ViewGroup.LayoutParams.WRAP_CONTENT;
private static final int TAG_LAYOUT_LEFT_MERGIN = 20;
private int mTagBackgroundColor;//
private int mTagTextColor ;
private float mTagTextSize;
private boolean mIsDeletable;
private int mDeletableTextColor;
private float mDeletableTextSize;
private LayoutInflater mInflater;
private Display mDisplay;
private boolean mInitialized;
private ViewTreeObserver mViewTreeObserber;
private int mWidth;//FlowLayout 的宽度
private int mHeight;//FlowLayout 的高度
private static final int TAG_LAYOUT_TOP_MERGIN = 10;
private static final String DEFAULT_DELETABLE_STRING = "×";//删除的文字
private static final int LAYOUT_WIDTH_OFFSET = 5;
private static final String TAG = "FlowLayout";
private List<TagView> mTags = new ArrayList<TagView>();
public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context,attrs,defStyle);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs,0);
}
public FlowLayout(Context context) {
super(context);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
mDisplay = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);//获取LayoutInflater对象
TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
mTagBackgroundColor = typeArray.getColor(R.styleable.FlowLayout_tagBackgroundColor,DEFAULT_TAG_LAYOUT_COLOR);//标签的背景颜色
mTagTextColor = typeArray.getColor(R.styleable.FlowLayout_tagTextColor,DEFAULT_TAG_TEXT_COLOR);//标签的文字颜色
mTagTextSize = typeArray.getDimension(R.styleable.FlowLayout_tagTextSize,DEFAULT_TEXT_SIZE);//标签的文字大小
mIsDeletable = typeArray.getBoolean(R.styleable.FlowLayout_isDeletable, false);//是否设置删除
mDeletableTextColor = typeArray.getColor(R.styleable.FlowLayout_deletableTextColor,DEFAULT_TAG_TEXT_COLOR);//删除文字的颜色
mDeletableTextSize = typeArray.getDimension(R.styleable.FlowLayout_deletableTextSize,DEFAULT_DELETABLE_TEXT_COLOR);//删除文字的大小
typeArray.recycle();
mViewTreeObserber = getViewTreeObserver();
mViewTreeObserber.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if(!mInitialized) {//这是因为这个回调会调好几次,还有一种就是把这个监听移除也是可以的
mInitialized = true;
drawTags();
}
}
});
}
/**
* 当你view宽和高度发生改变会回调
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w;
mHeight = h;
}
public void remove(int position){
mTags.remove(position);//删除后要重新画过
drawTags();
}
public void addTag(TagView tag){
mTags.add(tag);
}
public void drawTags() {
if(!mInitialized){
return;
}
removeAllViews();
float total = getPaddingLeft() + getPaddingRight();//计算FlowLayout 这个控件设置的padding值
int index = 1;//现在的位置
int pindex = index;//相对起点位置
for(TagView item:mTags){
final TagView tag = item;//记录当前的标签view
View tagLayout = (View) mInflater.inflate(R.layout.layout_tag, null);
tagLayout.setId(index);//设置每一tag layout 对应的id 因为这是相对布局用于换或者当一行中有二个以上的tagview时设置他相对某个tagview的位置
// tagLayout.setBackgroundColor(mTagBackgroundColor);//设置tag背景颜色
TextView tagView = (TextView) tagLayout.findViewById(R.id.tag_txt);
tagView.setText(tag.getText());//设置标签view显示的文字
tagView.setPadding(INNER_VIEW_PADDING, INNER_VIEW_PADDING, INNER_VIEW_PADDING, INNER_VIEW_PADDING);//设置tag标签的内容和标签之间的距离//设置textveiw中文字和边框间的距离
tagView.setTextColor(mTagTextColor);//设置文字的颜色
tagView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTagTextSize);//设置文字的大小 单位为sp
float tagWidth = tagView.getPaint().measureText(tag.getText()) + INNER_VIEW_PADDING * 2; //获取每个tag view的宽度
TextView deletableView = (TextView) tagLayout.findViewById(R.id.delete_txt);
if(mIsDeletable) {
deletableView.setVisibility(View.VISIBLE);
deletableView.setText(DEFAULT_DELETABLE_STRING);
deletableView.setPadding(INNER_VIEW_PADDING, INNER_VIEW_PADDING, INNER_VIEW_PADDING, INNER_VIEW_PADDING);
deletableView.setTextColor(mDeletableTextColor);
deletableView.setTextSize(mDeletableTextSize);
tagWidth += deletableView.getPaint().measureText(DEFAULT_DELETABLE_STRING)+ INNER_VIEW_PADDING * 2;
} else {
deletableView.setVisibility(View.GONE);
}
LayoutParams tagParams = new LayoutParams(WIDTH, WIDTH);
tagParams.setMargins(0, 0, 0, 0);
if (mWidth <= total + tagWidth + LAYOUT_WIDTH_OFFSET) {//如果子view排放的宽度大于或者等于父view的宽度就换行
tagParams.addRule(RelativeLayout.BELOW, pindex);
tagParams.topMargin = TAG_LAYOUT_TOP_MERGIN;//向上的距离 也就是marginTop
total = getPaddingLeft() + getPaddingRight();//如果换行 对total重新赋值
pindex = index;//
}else{
tagParams.addRule(RelativeLayout.ALIGN_TOP, pindex);
tagParams.addRule(RelativeLayout.RIGHT_OF, index - 1);
if (index > 1) {//如果一行中有二个tagView 就要考虑位置了
tagParams.leftMargin = TAG_LAYOUT_LEFT_MERGIN;
total += TAG_LAYOUT_LEFT_MERGIN;
}
}
total += tagWidth;//子view的累加 和父view的宽度做对比
addView(tagLayout, tagParams);//添加到相对布局中
index++;
}
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FlowLayout">
<attr name="tagBackgroundColor" format="color" />
<attr name="tagTextColor" format="color" />
<attr name="tagTextSize" format="dimension" />
<attr name="isDeletable" format="boolean" />
<attr name="deletableTextColor" format="color" />
<attr name="deletableTextSize" format="dimension" />
</declare-styleable>
</resources>
TagView.java 封装了textview显示的文字,当要处理点击事件 比较方便获取textview上的文字,
package com.zhimore.customflowlayout.bean;
public class TagView {
private int id;//设置view tag的id 用于点击事件
private String text;//设置tag view上的文字
public TagView(int id, String text){
this.id = id;
this.text = text;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
MainActivity.java 添加tag view
package com.zhimore.customflowlayout;
import android.app.Activity;
import android.os.Bundle;
import com.zhimore.customflowlayout.bean.TagView;
import com.zhimore.customflowlayout.view.FlowLayout;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FlowLayout flowlayout = (FlowLayout) findViewById(R.id.flowlayout);
for(int i=0;i<20;i++){
TagView tagView = new TagView(i, "流式布局"+i);
flowlayout.addTag(tagView);
}
flowlayout.drawTags();
}
}
ok,到此结束