layoutparser_你知道什么什么吗

layoutparser_你知道什么什么吗从概念讲起LayoutParams,顾名思义,就是布局参数。而且大多数人对此都是司空见惯,我们XML文件里面的每一个View都会接触到layout_xxx这样的属性,这实际上就是对布局参数的描述。大概大家也就清楚了,layout_这样开头的东西都不属于View,而是控制具体显示在哪里。LayoutParams都有哪些初始化方法通常来说,我们都会把我们的控件放在XML文件…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

从概念讲起

LayoutParams,顾名思义,就是布局参数。而且大多数人对此都是司空见惯,我们 XML 文件里面的每一个 View 都会接触到 layout_xxx 这样的属性,这实际上就是对布局参数的描述。大概大家也就清楚了,layout_ 这样开头的东西都不属于 View,而是控制具体显示在哪里。

LayoutParams 都有哪些初始化方法

通常来说,我们都会把我们的控件放在 XML 文件中,即使我们有时候需要对屏幕做比较「取巧」的适配,会直接通过 View.getLayoutParams() 这样的方法获取 LayoutParams 的实例,但我们接触的少并不代表它的初始化方法不重要。

实际上,用代码写出来的 View 加载效率要比在 XML 中加载快上大约 1 倍。只是在如今手机配置都比较高的情况下,我们常常忽略了这种方式。
我们来看看 ViewGroup.LayoutParams 到底有哪些构造方法。

public LayoutParams(Context c, AttributeSet attrs) { 
   
    TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
    setBaseAttributes(a,
            R.styleable.ViewGroup_Layout_layout_width,
            R.styleable.ViewGroup_Layout_layout_height);
    a.recycle();
}

public LayoutParams(int width, int height) { 
   
    this.width = width;
    this.height = height;
}

public LayoutParams(LayoutParams source) { 
   
    this.width = source.width;
    this.height = source.height;
}

LayoutParams() { 
     }
MarginLayoutParams

除去最后一个放给 MarginLayoutParams 做处理的方法外,我们在 ViewGroup 中还有 3 个构造方法。他们分别负责给 XML 处理、直接让用户指定宽高、还有类似集合的 addAll() 这样的方式的赋值方法。

实际上,ViewGroup 的子类的 LayoutParams 类拥有更多的构造方法,感兴趣的自己翻阅源码查看。在这里我想更加强调一下我上面提到的

MarginLayoutParams。

MarginLayoutParams 继承于 ViewGroup.LayoutParams。

public static class MarginLayoutParams extends ViewGroup.LayoutParams { 
   
    @ViewDebug.ExportedProperty(category = "layout")
    public int leftMargin;

    @ViewDebug.ExportedProperty(category = "layout")
    public int topMargin;

    @ViewDebug.ExportedProperty(category = "layout")
    public int rightMargin;

    @ViewDebug.ExportedProperty(category = "layout")
    public int bottomMargin;

    @ViewDebug.ExportedProperty(category = "layout")
    private int startMargin = DEFAULT_MARGIN_RELATIVE;

    @ViewDebug.ExportedProperty(category = "layout")
    private int endMargin = DEFAULT_MARGIN_RELATIVE;

    public MarginLayoutParams(Context c, AttributeSet attrs) { 
   
        super();
        TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
        setBaseAttributes(a,
                R.styleable.ViewGroup_MarginLayout_layout_width,
                R.styleable.ViewGroup_MarginLayout_layout_height);

        int margin = a.getDimensionPixelSize(
                com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
        if (margin >= 0) { 
   
            leftMargin = margin;
            topMargin = margin;
            rightMargin= margin;
            bottomMargin = margin;
        } else { 
   
            int horizontalMargin = a.getDimensionPixelSize(
                    R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
            // ... something
        }
        // ... something
    }
}

一看代码,自然就清楚了,为什么我们以前会发现在 XML 布局里, layout_margin 属性的值会覆盖 layout_marginLeft 与 layout_marginRight 等属性的值。

实际上,事实上,绝大部分容器控件都是直接继承 ViewGroup.MarginLayoutParams 而非 ViewGroup.LayoutParams。所以我们再自定义 LayoutParams 的时候记得继承 ViewGroup.MarginLayoutParams 。

在代码里面使用 LayoutParams

前面介绍了 LayoutParams 的几种构造方法,我们下面以 LinearLayout.LayoutParams 来看看几种简单的使用方式。

val textView1 = TextView(this)
textView1.text = "不指定 LayoutParams"
layout.addView(textView1)

val textView2 = TextView(this)
textView2.text = "手动指定 LayoutParams"
textView2.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
layout.addView(textView2)

val textView3 = TextView(this)
textView3.text = "手动传递 LayoutParams"
textView3.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams(100, 100))
layout.addView(textView3)

我们看看 addView() 都做了什么。

public void addView(View child) { 
   
    addView(child, -1);
}

public void addView(View child, int index) { 
   
    if (child == null) { 
   
        throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
    }
    LayoutParams params = child.getLayoutParams();
    if (params == null) { 
   
        params = generateDefaultLayoutParams();
        if (params == null) { 
   
            throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
        }
    }
    addView(child, index, params);
}

@Override
protected LayoutParams generateDefaultLayoutParams() { 
   
    if (mOrientation == HORIZONTAL) { 
   
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    } else if (mOrientation == VERTICAL) { 
   
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    }
    return null;
}

public void addView(View child, int index, LayoutParams params) { 
   
    if (DBG) { 
   
        System.out.println(this + " addView");
    }
    if (child == null) { 
   
        throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
    }
    requestLayout();
    invalidate(true);
    addViewInner(child, index, params, false);
}

private void addViewInner(View child, int index, LayoutParams params,
        boolean preventRequestLayout) { 
   

       // ...

    if (!checkLayoutParams(params)) { 
   
        params = generateLayoutParams(params);
    }

      // ...
}

@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 
   
    return p instanceof LinearLayout.LayoutParams;
}

看起来 ViewGroup 真是煞费苦心,如果我们没有给 View 设置 LayoutParams,则系统会帮我们根据 orientation 设置默认的 LayoutParams。甚至是我们即使在 addView() 之前设置了错误的 LayoutParams 值,系统也会我们帮我们进行纠正。

虽然系统已经做的足够完善,帮我们各种矫正错误,但在 addView() 之后,我们还强行设置错误的 LayoutParams,那还是一定会报 ClassCastException 的。

LayoutParams 很重要,每一名 Android 开发都应该尽力地去掌握,只有弄清楚了系统的编写方式,应对上面类似简书的流式布局才能更好处理。

实际上 Google 出的 FlexboxLayout 已经做的相当完美。
当然如果使用的 RecyclerView,还可以自己写一个 FlowLayoutManager 进行处理。

##读者福利限时分享

Android开发资料+面试架构资料 免费分享 点击链接 即可领取

《Android架构师必备学习资源免费领取(架构视频+面试专题文档+学习笔记)》

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/193546.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • opencv-python图像二值化函数cv2.threshold函数详解及参数cv2.THRESH_OTSU使用「建议收藏」

    opencv-python图像二值化函数cv2.threshold函数详解及参数cv2.THRESH_OTSU使用「建议收藏」通常情况,我们一般不知道设定怎样的阈值thresh才能得到比较好的二值化效果,只能去试。如对于一幅双峰图像(理解为图像直方图中存在两个峰),我们指定的阈值应尽量在两个峰之间的峰谷#ret:暂时就认为是设定的thresh阈值,mask:二值化的图像ret,mask=cv2.threshold(img2gray,175,255,cv2.THRESH_BINARY)plt.imshow(mask,cmap=’gray’)上面代码的作用是,将灰度图img2gray中灰度值小于175的点置…

    2025年7月27日
    5
  • mysql基本操作_MySQL创建数据库表

    mysql基本操作_MySQL创建数据库表1、数据库简单来说,所谓的数据库就是存储数据的容器,而且是永久存储的。2、为什么需要数据库3、为什么要学习MySQL数据库最早MySQL数据,瑞典AB公司开发的一款开源型的关系型数据库。随着时间的推移,瑞典AB公司把MySQL数据库转让给Sun公司(Java语言的创始公司)后来,Sun公司经营不善,又把MySQL数据库转让给甲骨文公司(Oracle数据库)4、数

    2022年10月6日
    3
  • mqttnet 详解_MQTTnet 3.0.5学习笔记

    mqttnet 详解_MQTTnet 3.0.5学习笔记段时间在使用MQTTnet,都说这个东西比较好,可是翻了翻网上没有例子给参考一下。今天算是找到了,给高手的帖子做个宣传吧.由于GitHub上介绍的东西比较少,以我的水平真是不知道怎么用,先照葫芦画瓢,再看看怎么回事吧:功能:把订阅与发布做成一个类,还带有自动重连的功能usingSystem.Threading;usingSystem.Threading.Tasks;usingMQTTnet;usi…

    2022年6月25日
    61
  • .bat文件打开方式[通俗易懂]

    .bat文件打开方式[通俗易懂]有的时候不小心将后缀名.bat文件在选择打开方式时误勾选了用记事本或者其他文本编辑器打开,结果电脑上的*.bat文件的打开方式都变成了记事本或者其他文本编辑器。本方法就是恢复.bat文件的默认打开方式。1、同时按住windows键和R键,在出来的框中输入regedit,打开注册表编辑器。2、找到:计算机\HKEY_CURRENT_USER\SOFTWARE\MICROSOFT\WINDOWS\currentversion\Explorer\FileExts.bat删除除了openwithlist

    2022年7月15日
    22
  • 关于左值和右值的一些问题总结[通俗易懂]

    在C语言当中,我们经常会遇见一些平时感觉怎么用都不会出错的小知识点,但是再将它的难度提高一点点的时候,或者将它改变一点点,我们就不再将它用起来那么的得心应手。左值和右值正是一个这样的十足十的例子。在学习了指针知识之后,高度理解左值与右值便不再显得那么的无聊。这个解释看起来有点傻,但是不得不说:左值就是那些能够出现在赋值符号左边的东西,右值就是那些能够出现在赋值符号右边的东西。例如:a=b+25;这…

    2022年4月10日
    61
  • nodejs开发http接口

    nodejs开发http接口目录nodejs的启动方式安装依赖生成package.json新建app.js启动服务调用接口nodejs的启动方式使用nodenodeapp.js使用nodemonnodemonapp.js可以将其配置到package.json的script:start中,然后调用npmstart安装依赖express是一个web应用开发框架nodemon可以用来启…

    2022年5月10日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号