自定义自动换行的LinearLayout
1 MyAutoLineFeedLinearLayout
是用来承载内容的父控件,定义代码如下:
package com.gsww.hzz.uikit.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import com.gsww.hzz.uikit.R;
/**
* @author Qzl
* @desc 自定义自动换行LinearLayout
* @email 2538096489@qq.com
* @time 2019-02-25 16:02
* @class hzz
* @package com.gsww.hzz.uikit.view
*/
public class MyAutoLineFeedLinearLayout extends LinearLayout {
//设置一行显示多少个,默认为三个
int mAutoLineNum = 3;
/**
* 里面内容的行间距 下一行距离上一行的间距
*/
float mAutoLineTop = 0;
/**
* 每一行显示的view的总宽度
*/
private int childWidth = 0;
/**
* 屏幕的最大宽度
*/
private int maxWidth = 0;
public MyAutoLineFeedLinearLayout(Context context) {
super(context);
}
public MyAutoLineFeedLinearLayout(Context context, int horizontalSpacing, int verticalSpacing) {
super(context);
}
public MyAutoLineFeedLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
//获取自定义属性的值
TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.AutoLineFeedLinearLayout);
mAutoLineNum = arr.getInt(R.styleable.AutoLineFeedLinearLayout_auto_line_num,3);
mAutoLineTop = arr.getDimension(R.styleable.AutoLineFeedLinearLayout_auto_line_top,0);
//释放资源
arr.recycle();
}
/**
* @desc 测量方法,计算显示这些view所需要的高度
* @author 强周亮
* @time 2019-02-26 09:48
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取屏幕的宽度
maxWidth = MeasureSpec.getSize(widthMeasureSpec);
int y = getTotalHeight();
//设置容器所需的宽高
setMeasuredDimension(maxWidth, y);
}
/**
* @desc 获取布局总高度
* @author 强周亮
* @time 2019-02-26 11:48
*/
private int getTotalHeight() {
//每一次测量时,重新计算每行所有view的总宽度,用来做均分显示
childWidth = 0;
//获取总共的子view的个数
int childCount = getChildCount();
//计算子view所占的宽度
int x = 0;
//计算子view所占的高度
int y = 0;
//记录总共有多少行
int row = 0;
//记录是第几个孩子
int indexChild = -1;
for (int index = 0; index < childCount; index++){
final View child = getChildAt(index);
if (child.getVisibility() != View.GONE){
indexChild++;
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
//此处增加换行判断,用于计算所需的高度
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight();
x += width;
if (indexChild < mAutoLineNum) {
childWidth += width;
};
y = (row+1)*(int)(height+ mAutoLineTop);
if ((indexChild != 0 && indexChild%mAutoLineNum== 0) || x > maxWidth){
x = width;
row++;
y = (row+1)*(int)(height+ mAutoLineTop);
}
}
}
return y;
}
/**
* @desc 绘制要显示的view
* @author 强周亮
* @time 2019-02-26 09:53
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int x = 0,y,row = 0,span = 0,maxWidth = r - 1;
span = getSpan(span, maxWidth);
childLayout(childCount, x, row, span, maxWidth);
}
/**
* @desc 绘制每一个孩子
* @author 强周亮
* @time 2019-02-26 11:50
*/
private void childLayout(int childCount, int x, int row, int span, int maxWidth) {
int y;//记录是第几个孩子
int indexChild = -1;
for (int i = 0; i < childCount; i++) {
final View child = this.getChildAt(i);
if (child.getVisibility() != View.GONE){
indexChild++;
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight();
x += width+span;
y = (int) (row+1)*(int)(height+ mAutoLineTop);
if ((indexChild != 0 && indexChild%mAutoLineNum== 0) || x > maxWidth){
x = width+span;
row++;
y = (int) (row+1)*(int)(height+ mAutoLineTop);
}
child.layout(x - width, y - height, x, y);
}
}
}
/**
* @desc 获取每一行之间view的间距
* @author 强周亮
* @time 2019-02-26 11:49
*/
private int getSpan(int span, int maxWidth) {
if (childWidth < maxWidth){
span = (maxWidth-childWidth)/(mAutoLineNum+1);
}
return span;
}
}
2 attrs.xml 属性值
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--自定义linearlayout可以换行显示-->
<declare-styleable name="AutoLineFeedLinearLayout">
<!--每一行显示多少个-->
<attr name="auto_line_num" format="integer"/>
<!--行与行之间的间距-->
<attr name="auto_line_top" format="dimension"/>
</declare-styleable>
</resources>
3 使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"
tools:context=".fragment.JobsFragment">
<com.gsww.hzz.uikit.view.MyAutoLineFeedLinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:auto_line_num = "3"
app:auto_line_top = "@dimen/dp_26">
<LinearLayout
android:id="@+id/one_picture"
style="@style/job_tv_parent">
<ImageView
style="@style/job_img"
android:src="@drawable/icon_job_one_pic" />
<TextView
style="@style/job_tv"
android:text="@string/one_map"/>
</LinearLayout>
</com.gsww.hzz.uikit.view.MyAutoLineFeedLinearLayout>
</LinearLayout>
4 style样式
<!--每一行中每一个的父布局-->
<style name="job_tv_parent">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:gravity">center</item>
<item name="android:orientation">vertical</item>
</style>
<style name="job_img">
<item name="android:layout_width">@dimen/dp_54</item>
<item name="android:layout_height">@dimen/dp_54</item>
</style>
<!--TextView布局-->
<style name="job_tv">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">@dimen/text_size_14</item>
<item name="android:textColor">#666666</item>
<item name="android:layout_marginTop">@dimen/dp_8</item>
</style>