自定义View

主要包括:布局,绘制,触摸反馈

1,布局,主要是View在父容器的位置以及自身的尺寸。

布局中,所有layout开头的都是给父容器看的,

子布局通过onMeasure 的measure方法获取自身所需要的尺寸,父容器获取子布局的期望值,

在计算然后父容器通过layout方法把实际尺寸发给子布局

onDraw和onMeasure是 总调度。draw和measure是实际代码的地方。

 

2,layout是把父容器传过来的尺寸值保存起来,是操作自己的布局,一般layout是不需要重写的。因为这里操作布局,父容器是不知道的,会对其他布局有影响,应该去操作onMeasure()方法,然后把这个值传给父容器再次计算。

onLayout是对子控件进行布局的,是自定义ViewGroup的时候用的。值是onMeasure中测量出来的。

 

3,onMeasure:自己对自己的测量,getMeasureWidth() 获取自己的期望宽度,setMeasureDimension() ,保存测得的尺寸。也可以说把自己的尺寸通过这个方法,告诉父容器,进行自己尺寸的修改。父容器接收到,进行对子容器的布局。

onMeasure 中有具体值,有上限,和无上限三种区别。

resolverSize(  ,) 方法修正 自己测量的宽高,主要是为了替换,根据模式来获取width和height

 

4,整体流程:

     子View在onMeasure方法,计算自己的大小,通过setMeasureDimension()方法,把自己的期望值传给父容器。

     父容器接受到子控件传给自己的数据,再onLayout()方法中,把所有的控件的实际值计算出来,通过layout() 

     方法传回给子控件。子View在自己的onLayout() 方法中接受自己实际值,从而绘画布局。

 

5,View的控件,重写onMeasure()和onDraw()方法。

      ViewGroup的控件,重写onMeasure(),onLayout()方法。

 

 

自定义View

 

自定义ViewGroup之瀑布流

public class TagLayout extends ViewGroup {

    List<Rect> childrenBounds = new ArrayList<>();

    public TagLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthUsed = 0; // 最宽宽度
        int heightUsed = 0; // 已用高度
        int lineWidthUsed = 0; // 每行已用宽度
        int lineMaxHeight = 0;  // 每行的最大高度
        int specMode = MeasureSpec.getMode(widthMeasureSpec); // 一行的宽度
        int specWidth = MeasureSpec.getSize(widthMeasureSpec); // 一行的宽度
        // 子布局的尺寸
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            // 重新测量子View的位置 widthUsed = 0 是为了避免压缩子View
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, heightUsed);

            if (specMode != MeasureSpec.UNSPECIFIED && lineWidthUsed + child.getMeasuredWidth() > specWidth){
                // 换行
                lineWidthUsed = 0;
                heightUsed += lineMaxHeight;
                lineMaxHeight = 0;
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, heightUsed);
            }

            Rect childBound;
            if (childrenBounds.size() <= i) {
                childBound = new Rect();
                childrenBounds.add(childBound);
            } else {
                childBound = childrenBounds.get(i);
            }
            childBound.set(lineWidthUsed, heightUsed, lineWidthUsed + child.getMeasuredWidth(), heightUsed + child.getMeasuredHeight());

            lineWidthUsed += child.getMeasuredWidth();
            widthUsed = Math.max(widthUsed,lineWidthUsed);
            lineMaxHeight = Math.max(lineMaxHeight, child.getMeasuredHeight());
        }

        // 自身尺寸
        int width = widthUsed;
        int height = heightUsed + lineMaxHeight;
        setMeasuredDimension(width, height);
    }

    //测量各个子View的尺寸
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        for (int i = 0; i < getChildCount(); i++) {
            View view = getChildAt(i);
            Rect childBounds = childrenBounds.get(i);
            //把子View的尺寸传给他们
            view.layout(childBounds.left, childBounds.top, childBounds.right, childBounds.bottom);
        }
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(),attrs);
    }
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值