Android UI 代码实现:可换行的布局控件

文章目录

ShifterLayout:子控件的宽度不固定

复制代码
/**
 * 可以换行的布局控件,其中的子控件宽度不固定
 */
public class ShifterLayout extends ViewGroup {
    public ShifterLayout(Context context) {
        super(context);
    }


    public ShifterLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childTop = this.getPaddingTop();
        int childLeft = this.getPaddingLeft();
        int childWidth = 0;
        int childHeight  = 0;
        int tempChildLeft = 0;
        for(int i=0; i<getChildCount(); i++) {
            View child = getChildAt(i);
            if(child.getVisibility() == VISIBLE) {
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                childWidth = child.getMeasuredWidth();
                childHeight  = child.getMeasuredHeight();
                //换行
                tempChildLeft = childLeft +lp.leftMargin + childWidth;
                if(tempChildLeft >= getMeasuredWidth()) {
                    childLeft = this.getPaddingLeft();
                    childTop += childHeight + lp.bottomMargin+lp.topMargin;
                }
                //
                child.layout(childLeft , childTop,
                        childLeft+childWidth, childTop+ childHeight);
                childLeft += childWidth+lp.rightMargin+lp.leftMargin;
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int childTop = this.getPaddingTop();
        int childLeft = this.getPaddingLeft();
        int childWidth = 0;
        int childHeight  = 0;
        int height = 0;
        int tempChildLeft = 0;

        int width = MeasureSpec.getSize(widthMeasureSpec);
        for(int i=0; i<getChildCount(); i++) {
            View child = this.getChildAt(i);
            if(child.getVisibility() == VISIBLE) {
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
                childWidth = child.getMeasuredWidth();
                childHeight  = child.getMeasuredHeight();
                //换行
                tempChildLeft = childLeft +lp.leftMargin + childWidth;
                if(tempChildLeft >= width) {
                    childLeft = this.getPaddingLeft();
                    childTop += childHeight + lp.bottomMargin+lp.topMargin;
                }
                childLeft += childWidth+lp.rightMargin+lp.leftMargin;
             }

        }
        height = childTop + childHeight + this.getPaddingBottom();
        setMeasuredDimension(width, height);

    }

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

ShifterLayout2:子控件的宽度一致且固定

复制代码
/**
 * 可以换行的布局控件,其中的子控件宽度相同且固定
 */
public class ShifterLayout2 extends ViewGroup {
    private int childWidth, childHeight;
    public ShifterLayout2(Context context) {
        super(context);
    }

    public ShifterLayout2(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
//        super.onLayout(changed, l, t, r, b);
        int childTop = this.getPaddingTop();
        int childLeft = this.getPaddingLeft();
        int tempChildLeft = 0;
        for(int i=0; i<getChildCount(); i++) {
            View child = getChildAt(i);
            if(child.getVisibility() == VISIBLE) {
                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
                //换行
                tempChildLeft = childLeft +lp.leftMargin + childWidth;
                if(tempChildLeft >= getMeasuredWidth()) {
                    childLeft = this.getPaddingLeft();
                    childTop += childHeight + lp.bottomMargin+lp.topMargin;
                }
                //
                child.layout(childLeft , childTop,
                        childLeft+childWidth, childTop+ childHeight);
                childLeft += childWidth+lp.rightMargin+lp.leftMargin;
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        View childView = getChildAt(0);
        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
        //其他类想要获取布局控件中的子控件的宽高:布局控件.getChildAt(0).getMeasuredWidth/Height()
        //不measure其他子控件,目前没有遇到问题
        measureChildWithMargins(childView, widthMeasureSpec, 0, heightMeasureSpec, 0);
//        for(int i=0; i<getChildCount(); i++) {
//            View child = getChildAt(i);
//            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
//        }
        MarginLayoutParams lp =
                (MarginLayoutParams) childView.getLayoutParams();
        int childLeftMargin = lp.leftMargin;
        int childTopMargin = lp.topMargin;
        int childBottomMargin = lp.bottomMargin;
        childWidth = childView.getMeasuredWidth();
        childHeight = childView.getMeasuredHeight();
        int childWidth2 = childWidth + childLeftMargin;
        int childHeight2 = childHeight + childTopMargin + childBottomMargin;;
        int columnNum = (measureWidth)/(childWidth2);
        int height = 0;
        int childCount = getChildCount();
        if(childCount<columnNum) {
            height = childHeight2;
        }
        else {
            height += (childCount/columnNum)*childHeight2;
            if(childCount%columnNum != 0) {
                height += childHeight2;
            }
        }
        height -= childBottomMargin;
        setMeasuredDimension(measureWidth, height);

    }

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

​​​​​​​

相关推荐
驰骋工作流4 小时前
流程时效考核的表结构:从待办时限到 WF_CH 考核结果驰骋BPM驰骋低代码低代码工作流引擎
android·低代码·rxjava
oicola5 小时前
【UI动效】科幻风长任务进度动效设计方案
ui
传奇开心果编程6 小时前
【Flutter踩坑排雷】第7课:巨型 build 函数坑|全部 UI 写在同一个 build,维护难、隐性异常
android·flutter·ios·移动开发·跨平台·dart·声明式ui
方白羽10 小时前
Android 双开环境底层剖析与风控检测落地
android·安全·app
weixin_5633714710 小时前
Android Studio 2024 版 Device Explorer 打开方法
android·ide·android studio
AIsoft_868913 小时前
职场音频文件怎么整理?录音APP有哪些用法
android·音视频
booboosui13 小时前
第一批个人 Agent 用户正在卸载,问题不在模型,在它住在哪儿
android
洞见前行13 小时前
点击图标到内容出现,你的 App 在这几秒里做了什么:Android 冷启动全链路优化实战
android·性能优化·android studio
凯基迪科技13 小时前
芯片UID绑定修改 加密与逆向修改思路分析
android
Liben14 小时前
Weex开发踩坑记录
android·前端·ios