addView时子项布局变化考虑inflate加载方式

题记:如果遇到子项布局的样式在动态加载到父布局时发生了改变,不妨考虑一下布局加载方式和参数设置

背景

问题的发生是这样的:
我需要将RadioButton动态插入到RadioGroup中,RadioButton为自定义样式,文字居左,按钮居右,布局和添加布局代码如下,上图说话



radioGroup = findViewById(R.id.radio_group);
radioGroup.removeAllViews();
View view = View.inflate(this,R.layout.item_radio_button,null);
((RadioButton) view).setText("多拍/错拍");
radioGroup.addView(view);

理想:


addView时子项布局变化考虑inflate加载方式_第1张图片
image.png

现实:


addView时子项布局变化考虑inflate加载方式_第2张图片
image.png

在inflate的root参数设为null的基础上,试验过将CheckBox和RadioButton动态加载到LinearLayout和RadioGroup中,产生结果如下:
父(子)布局 LinearLayout RadioGroup
CheckBox 布局没发生改变 布局发生改变
RadioButton 布局没发生改变 布局发生改变

看结果来说,应该是RadioGroup的问题,但是通过addView一层一层看,发现其实是infate参数设置惹的祸,不是RadioGroup的锅,先解释一下引发的原因,然后具体对inflate加载进行说明。

背后的锅

1.进入addView方法,其params的来源为child.getLayoutParams()
情况一:inflate设为null,则params = null;
情况二:inflate有root,则params != null;

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);
    }

2.params的赋值:
情况一:params == null,params = generateDefaultLayoutParams();每个ViewGroup的generateDefaultLayoutParams方法设置不同,有的为WRAP_CONTENT,有的为MATCH_CONTENT
情况二:params != null,params = root.generateLayoutParams(attrs);(参见inflate方法内),root会为创建的View对象提供LayoutParams参数

加载布局的方案

LayoutInflater之inflate

  • 三个参数的inflate方法,主要是对root和attachToRoot的设置,主要分3种情况:
// 3个参数的构造函数
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot){......}

1.root=null
这种情况下,不管attachToRoot为true还是false,子项根结点的属性都是无效的
2.root!=null,attachToRoot=true
这种情况下会直接将子布局加载到父布局中,且子布局根结点设置的属性是有效的,注意此时不需要操作addView这一步,因为已经加载过了

// 返回的view.getClass为class android.widget.RadioGroup
View view = LayoutInflater.from(this).inflate(R.layout.item_radio_button,radioGroup,true);

3.root!=null,attachToRoot=false,表示不将子布局加载到父布局中,但是可以实现子布局根结点的属性不失效,但又不处于某个容器中,这种情况下需要执行addView方法

// 返回的view.getClass为class android.support.v7.widget.AppCompatRadioButton
View view = LayoutInflater.from(this).inflate(R.layout.item_radio_button,radioGroup,false);
  • 两个参数的inflate方法
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    return inflate(resource, root, root != null);
}

这种方式将root和attachToRoot做了关联,简化成两种情况:root=null&&attachToRoot=false和root!=null&&attachToRoot=true,情况参照三种参数的情况

View之inflate

public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
    LayoutInflater factory = LayoutInflater.from(context);
    return factory.inflate(resource, root);
}

可以看到,View的inflate方法最终也调用了LayoutInflate方法两个参数的情况

你可能感兴趣的:(addView时子项布局变化考虑inflate加载方式)