自定义viewgroup类似锤子系统

本文介绍了一个自定义的GridLayout布局管理器的实现细节,包括如何通过重写onMeasure和onLayout方法来控制子视图的排列方式。此外,还介绍了如何使用适配器动态填充网格布局。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1ViewGroup是一个容器,而这个容器是继承与View的。

2ViewGroup是一个基类,并且是Layout和一些View组件的基类。

要注意viewgroup 的三个方法

addview    向容器里添加子控件

onmeacure    对子控件的大小进行定义

onlayout    对控件的位置进行定义

public void layout(int l, int t, int r, int b);

onLayout(boolean changed, int l, int t, int r, int b)


该方法是View的放置方法,在View类实现。调用该方法需要传入放置View的矩形空间左上角left、top值和右下角right、bottom值。这四个值是相对于父控件而言的。例如传入的是(10, 10, 100, 100),则该View在距离父控件的左上角位置(10, 10)处显示,显示的大小是宽高是90(参数r,b是相对左上角的),这有点像绝对布局。

public class MyGridLayout extends ViewGroup {
int margin = 2;// 每个格子的水平和垂直间隔
int colums = 2;
int count = 0;


GridAdatper adapter;


@SuppressLint("Recycle")
public MyGridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.MyGridLayout);
colums = a.getInteger(R.styleable.MyGridLayout_numColumns, 2);
margin = (int) a.getInteger(R.styleable.MyGridLayout_itemMargin, 2);
}
}


public MyGridLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}


public MyGridLayout(Context context) {
this(context, null);
}


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {


count = getChildCount();
if (count == 0) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
return;
}


for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}


child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);


}


super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}


@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int height = b - t;// 布局区域高度
int width = r - l;// 布局区域宽度
int rows = count % colums == 0 ? count / colums : count / colums + 1;// 行数
if (count == 0)
return;
int gridW = (width - margin * (colums - 1)) / colums;// 格子宽度
int gridH = (height - margin * rows) / rows;// 格子高度


int left = 0;
int top = margin;


for (int i = 0; i < rows; i++) {// 遍历行
for (int j = 0; j < colums; j++) {// 遍历每一行的元素
View child = this.getChildAt(i * colums + j);
if (child == null)
return;
left = j * gridW + j * margin;
// 如果当前布局宽度和测量宽度不一样,就直接用当前布局的宽度重新测量
if (gridW != child.getMeasuredWidth()
|| gridH != child.getMeasuredHeight()) {
child.measure(makeMeasureSpec(gridW, EXACTLY),
makeMeasureSpec(gridH, EXACTLY));
}
child.layout(left, top, left + gridW, top + gridH);
}
top += gridH + margin;
}
}


public interface GridAdatper {
View getView(int index);


int getCount();
}


/** 设置适配器 */
public void setGridAdapter(GridAdatper adapter) {
this.adapter = adapter;
// 动态添加视图
int size = adapter.getCount();
for (int i = 0; i < size; i++) {
addView(adapter.getView(i));
}
}


public interface OnItemClickListener {
void onItemClick(View v, int index);
}


/**
* 设置item点击事件

* @param click
*/
public void setOnItemClickListener(final OnItemClickListener click) {
if (this.adapter == null)
return;
for (int i = 0; i < adapter.getCount(); i++) {
final int index = i;
View view = getChildAt(i);
view.setOnClickListener(new View.OnClickListener() {


@Override
public void onClick(View v) {
click.onItemClick(v, index);
}
});
}
}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值