自定义view动态加载控件实现动态换行

自定义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);


}

如有错误欢迎指正

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值