《Android自定义控件入门到精通》文章索引 ☞ https://blog.csdn.net/Jhone_csdn/article/details/118146683
《Android自定义控件入门到精通》所有源码 ☞ https://gitee.com/zengjiangwen/Code
文章目录
View树的布局
经过前面View树的绘制流程和View树的测量流程的学习,相信大家自己分析View树的布局流程已经没有什么难度了
ViewRootImpl.java
//ViewRootImpl.java
private void performTraversals() {
//测量流程
measureHierarchy(...)-->performMeasure(...);
//布局流程
performLayout(...);
//绘制流程
performDraw();
}
布局的操作是针对ViewGroup而言,且直接在onLayout()方法中实现就行了:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
}
LayoutParams
我们能用view.getLayoutParams()获取到布局参数LayoutParams,那么,这个对象是怎么生成的?
ViewGroup.java
//ViewGroup.java
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);
}
//生成Child的布局参数对象LayoutParams
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
可以看到,当ViewGroup添加Child的时候,是通过generateDefaultLayoutParams()来生成Child的LayoutParams对象的
当时翻看LayoutParams类的时候发现,它里面只有width、height两个属性
public static class LayoutParams {
public int width;
public int height;
}
我们知道:
- Child跟Parent相关的布局属性是放在LayoutParams中的,比如Child的width、height、margin
- Child的padding是跟Parent无关的,它属于width/height的一部分,通过child.getPadding就可以获取
那Child的margin值,我们怎么获取到呢
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYh58Pe6-1624353180372)(…/img/image-20210621103312840.png)]
在ViewGroup中,还提供了一个MarginLayoutParams
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
public int leftMargin;
public int topMargin;
public int rightMargin;
public int bottomMargin;
}
那么,我们在自己自定义的ViewGroup中,返回MarginLayoutParams不就可以了吗
protected LayoutParams generateDefaultLayoutParams() {
return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
然后通过xml等方式设置的margin值,就可以被MarginLayoutParams解析了
public MarginLayoutParams(Context c, AttributeSet attrs) {
super();
TypedArray a = c.