自定义ViewGroup的学习:九宫格

本文介绍了自定义ViewGroup的核心方法onMeasure和onLayout的实现,详细讲解如何创建适应不同数量图片的九宫格布局。内容包括如何测量自身及子View的尺寸,以及如何定位子View。九宫格布局支持单张图片全屏、2x2和3x3格式。通过Adapter来展示内容,可适配不同类型的子View。

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

基础知识
自定义View需要实现2个方法 onMeasure和onLayout。
通过onMeasure 自身的宽高,如果是ViewGroup,还需要对子View的宽高进行测量。
通过onLayout对所有子View进行定位。

九宫格的要求:
只有一张图片,则占据全部空间。
四张图片以内,2X2的格式。
其他则以3X3的格式进行。
1X1
2X2
3X3

通过Adapter来提供每个子View显示的内容,可以是TextView,可以是ImageView.

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

        int widthValue = MeasureSpec.getSize(widthMeasureSpec);

        int heightValue = MeasureSpec.getSize(heightMeasureSpec);

        //获得内容展示的宽度
        int widthRealValue = widthValue - getPaddingLeft() - getPaddingRight();

        int heightRealValue = heightValue - getPaddingTop() - getPaddingBottom();

        //获得子View的数目
        int childCount = getChildCount();

        int width = widthRealValue > heightRealValue ? heightRealValue : widthRealValue;

        if (childCount == 1) {
            lineNum = 0;
        } else if (childCount < 5) {
            lineNum = 1;
        } else {
            lineNum = 2;
        }
        for (int i = 0; i < childCount; i++) {
            //如果只有一个子View  则父容器的高宽就是子容器的高宽
            //  count   line    n
            //  1       0       1
            //  2       1       2
            //  3       1       2
            //  4       1       2
            //  5       2       3
            //  6       2       3
            //  7       2       3
            //  ... ...
            int childWidth = (width - lineNum * mLineWidth) / (lineNum + 1);

            getChildAt(i).measure(MeasureSpec.makeMeasureSpec(childWidth,MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(childWidth,MeasureSpec.EXACTLY));
        }
        setMeasuredDimension(widthValue, heightValue);
    }

如上是 onMeasure()方法。其中,默认九宫格是不可以设置warp_content的,因为子View的大小是要根据父ViewGroup来确定的,所以onMeasure()中只关心了MeasureSpec.getSize(),而没有关注mode。通过确定宽度和高度的较小值,来确定实际的宽高。每个子View的宽度就是父View宽度减去左右padding,再减去可能存在的分割线的宽度,最后根据每行几个子View,由除法获得。测量每个子View。

   @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();

        for (int i = 0; i < childCount; i++) {

            int left = l + getPaddingLeft();
            int top = t + getPaddingTop();

            View childView = getChildAt(i);
            int viewWidth = childView.getMeasuredWidth();
            switch (lineNum) {
                case 0:
                    break;
                case 1: {
                    if (i % 2 == 1) {
                        left = left + viewWidth + mLineWidth;
                    }
                    if (i > 1) {
                        top = top + viewWidth + mLineWidth;
                    }
                }
                break;
                case 2:

                    int n = i % 3;
                    left = left + (viewWidth + mLineWidth) * n;

                    if (i > 5) {
                        top = top + 2 * (viewWidth + mLineWidth);
                    } else if (i > 2) {
                        top = top + viewWidth + mLineWidth;
                    }
                    break;
            }

            childView.layout(left, top, left + viewWidth, top + viewWidth);

        }

我对onLayout()方法的理解是,获得每个子View的坐标(left,top),然后childView.layout()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值