自定义view动态加载控件
先来讲下需求吧,可能我们开发中会遇到这样的场景,需要在一个父容器里加载多个子view,但是,子view的排版又有特殊要求,比如自适应屏幕宽度或者高度等,这样以来原本的控件无法满足需要了。先看下图的实现效果,界面有些粗糙,但是只需在用时稍作修饰即可。
实现了动态加载button,但是会根据button的宽度自动进行换行处理,当然你可以是其他控件如使用textview实现tag 的效果等。
实现分三步进行
- 新建xml布局
- 新建activity
- 自定义view继承自ViewGroup
1.新建xml one_layout.xml。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/androi d"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="@+id/one_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</FrameLayout>
<Button
android:layout_width="100dp"
android:layout_height="wrap_content"
android:text="btn12" />
</LinearLayout>
FrameLayout作为放自定义view的容器,这里不再赘述。
2.新建Activity OneActivity
先上实现代码,解释在后边。
public class OneActivity extends Activity{
String[] stringBt=new String[20];
Button button=null;
String messages="岭外音书绝,经冬复立春。近乡情更怯,不敢问来人。";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 屏幕宽度(像素)
int height = metric.heightPixels; // 屏幕高度(像素)
setContentView(R.layout.one_layout);
FrameLayout frameLayout(FrameLayout)findViewById(R.id.one_layout);
CustumViewGroup custumViewGroup=new CustumViewGroup(OneActivity.this,width);
custumViewGroup.setBackgroundColor(Color.parseColor("#ff0000"));
Random random=new Random();
String message="";
for (int i = 0; i <20; i++) {
button=new Button(this);
String srt=messages;
message=srt.substring(0,random.nextInt(10))+i;
button.setText(message);
custumViewGroup.addView(button);
}
frameLayout.addView(custumViewGroup);
}
}
Activity中的实现分几步
- 获取屏幕宽高
- 实例化自定义view
- 创建子view并且设置显示数据
- 装载子view到自定义view,将自定义view装载到frameLayout
3.自定义view
自定义view继承自ViewGroup,并且重写了 onMeasure,onLayout 方法。
1. onMeasure主要用于测量view宽高及模式,并且设置自定定义view宽高及子view宽高
2. onLayout 用于对子view进行排版
代码实现如下:
public class CustumViewGroup extends ViewGroup {
Context contexts;
int widthPixels;
public CustumViewGroup(Context context,int width) {
super(context);
this.contexts = context;
this.widthPixels=width;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
System.out.println("-onMeasure--" + getWidth());
//将所有的子View进行测量,这会触发每个子View的onMeasure函数
//注意要与measureChild区分,measureChild是对单个view进行测量
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int childCount = getChildCount();
if (childCount == 0) {//如果没有子View,当前ViewGroup没有存在的意义,不用占用空间
setMeasuredDimension(0, 0);
} else {
if (heightMode == MeasureSpec.AT_MOST) {//如果只有高度是包裹内容
//宽度设置为ViewGroup自己的测量宽度,高度设置为所有子View的高度总和
setMeasuredDimension(widthPixels, getMaxHeight());
}
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
//记录当前的高度位置
int curHeight = t;
int curWidth = l;
boolean isFirst = false;
boolean isLineFead = false;
int heights = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
int height = child.getMeasuredHeight();
int width = child.getMeasuredWidth();
System.out.println("-onLayout--。。》" + width);
if (widthPixels - curWidth > width) {//计算行的剩余宽度判断是否换行
if (isLineFead) {
curHeight = heights;
}
child.layout(curWidth, curHeight, curWidth + width, heights + height);
curWidth += width;
isLineFead = false;
isFirst = true;
} else {//此处进行换行处理
if (isFirst) {
curWidth = 0;
}
heights += height;
child.layout(l, heights, curWidth + width, heights + height);
curWidth += width;
isFirst = false;
isLineFead = true;
}
}
}
/**
* 计算子view所占的高度,以便父容器自适应包裹所有子view
* @return
*/
private int getMaxHeight() {
int count = getChildCount();
//记录当前的高度位置
int curWidth = 0;
boolean isFirst = false;
int heights = 0;
int widthM = 0;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
int height = child.getMeasuredHeight();
int width = child.getMeasuredWidth();
if (widthPixels - curWidth > width) {
curWidth += width;
isFirst = true;
} else {
if (isFirst) {
curWidth = 0;
}
heights += height;
curWidth += width;
isFirst = false;
widthM = heights + height;
}
}
return widthM;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
如有错误欢迎指正