最近一直在學習自定義View和自定義ViewGroup的東西析校,今天沒事干就研究了一下FlowLayout掐松,記錄下實現步驟,參考自鴻洋博客
AndroidStudio使用
在根projcet的build.gradle中添加.
maven { url 'https://jitpack.io' }
在項目的build.gradle添加:
compile 'com.github.superSp:FlowLayout:1.0'
效果圖 自適應
圖片.png
效果圖 固定大小
圖片.png
使用方法——靜態(tài)添加
<lsp.com.library.FlowLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
style="@style/text_flag_01"
android:text="Welcome" />
<TextView
style="@style/text_flag_01"
android:text="IT工程師" />
<TextView
style="@style/text_flag_01"
android:text="學習ing" />
<TextView
style="@style/text_flag_01"
android:text="戀愛ing" />
<TextView
style="@style/text_flag_02"
android:text="戀愛ing" />
<TextView
style="@style/text_flag_02"
android:text="掙錢ing" />
<TextView
style="@style/text_flag_02"
android:text="努力ing" />
<TextView
style="@style/text_flag_02"
android:text="I thick i can" />
</lsp.com.library.FlowLayout>
style文件:
<style name="text_flag_01">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_margin">5dp</item>
<item name="android:background">@drawable/flag_01</item>
</style>
drawable文件:
樣式1(flag_01)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#7690A5"/>
<corners android:radius="5dp"/>
<padding android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp"/>
</shape>
樣式2(flag_02)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#E7E7E7" >
</solid>
<corners
android:radius="30dp"
/>
<padding
android:bottom="2dp"
android:left="10dp"
android:right="10dp"
android:top="2dp" />
</shape>
按自己喜好設置就行~~
使用方法——動態(tài)添加
FlowLayout flowLayout = new FlowLayout(this);
flowLayout.initData(Arrays.asList("Welcome","IT工程師","學習ing","戀愛ing"
,"掙錢ing","努力ing","I thick i can"));
setContentView(flowLayout);
initData方法
public void initData(List<String> list)
public void initData(List<String> list, int margin, int drawable)
添加點擊事件
flowLayout.setOnTabClickListener(new FlowLayout.IOnTabClickListener() {
@Override
public void onTabClick(int position, TextView textView) {
Toast.makeText(Test.this,position+" "+textView.getText(),Toast.LENGTH_SHORT).show();
}
});
setContentView(flowLayout);
實現思路
構造方法
public FlowLayout(Context context) {
this(context, null);
}
public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
子view支持margin屬性
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
onMeasure方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//測量子view的大小
measureChildren(widthMeasureSpec, heightMeasureSpec);
//最終的寬和高
int width = 0;
int height = 0;
//記錄每一行的寬和高
int lineWidth = 0;
//子view數量
int cCount = getChildCount();
View cView;
MarginLayoutParams params;
int cWidth, cHeight;
for (int i = 0; i < cCount; i++) {
cView = getChildAt(i);
params = (MarginLayoutParams) cView.getLayoutParams();
cWidth = cView.getMeasuredWidth() + params.leftMargin + params.rightMargin;
cHeight = cView.getMeasuredHeight() + params.topMargin + params.bottomMargin;
ViewBean viewBean = new ViewBean();
if (lineWidth + cWidth < widthSize) {
lineWidth += cWidth;
height = Math.max(height, cHeight);
width = Math.max(lineWidth, width);
} else {
width = Math.max(lineWidth, width);
height += cHeight;
lineWidth = cWidth;
}
viewBean.setLeft(lineWidth - cWidth + params.leftMargin);
viewBean.setTop(height - cHeight + params.topMargin);
viewBean.setRight(lineWidth - params.rightMargin);
viewBean.setBottom(height - params.bottomMargin);
list.add(viewBean);
}
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : width, heightMode == MeasureSpec.EXACTLY ? heightSize : height);
}
onLayout方法
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cCount = getChildCount();
for (int i = 0; i < cCount; i++) {
getChildAt(i).layout(list.get(i).getLeft(), list.get(i).getTop(), list.get(i).getRight(), list.get(i).getBottom());
}
}
ViewBean方法
private class ViewBean {
private int left;
private int right;
private int top;
private int bottom;
public int getLeft() {
return left;
}
public void setLeft(int left) {
this.left = left;
}
public int getRight() {
return right;
}
public void setRight(int right) {
this.right = right;
}
public int getTop() {
return top;
}
public void setTop(int top) {
this.top = top;
}
public int getBottom() {
return bottom;
}
public void setBottom(int bottom) {
this.bottom = bottom;
}
}
動態(tài)填充數據實現
public void initData(List<String> list) {
ViewGroup.MarginLayoutParams pa = new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.WRAP_CONTENT,
ViewGroup.MarginLayoutParams.WRAP_CONTENT);
int size = list.size();
for (int i = 0; i < size; i++) {
TextView tv = new TextView(getContext());
tv.setText(list.get(i));
addView(tv, pa);
((ViewGroup.MarginLayoutParams) tv.getLayoutParams()).setMargins(DensityUtils.dp2px(getContext(), 5), DensityUtils.dp2px(getContext(), 5),
DensityUtils.dp2px(getContext(), 5), DensityUtils.dp2px(getContext(), 5));
tv.setBackgroundResource(R.drawable.flag_01);
}
}
添加點擊事件
public interface IOnTabClickListener {
void onTabClick(int position, TextView textView);
}
private void setOnclick(final int position, final TextView textView) {
textView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
iOnTabClickListener.onTabClick(position, textView);
}
});
}
后記
比較難理解的部分應該就是onMeasure了。。當設置wrap的時候找到寬度最大的值几睛。。并且設置每個view的坐標.