CardView的layout_margin属性不起作用

使用CardView作为适配器的Item布局的根View,在RecyclerView.Adapter中的onCreateViewHolder中加载Item布局的时候,如果使用的LayoutInflater.from(Context).inflate(layoutId,null)这个方法来加载布局的话,那么Item布局中的CardView中的有些属性是无法起作用的,比如:android:layout_margin=”xxdp”,就算设置了这个属性,但是在5.1系统是不能显示为卡片式的,但是在4.4系统是可以显示为卡片式的。

如果要在5.1系统中也能显示为卡片式布局,那么需要更换inflate加载布局的方法,更换为LayoutInflater.from(Context).inflate(layoutId,parent,false),

使用这个方法,就能在5.1系统显示卡片式布局,同时在4.4系统同样能够显示卡片式。

从源码层面查看两个方法的区别:

调用这两个方法都会执行到LayoutInflater的inflate方法中:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, “INFLATING from resource: \”” + res.getResourceName(resource) + “\” (”
+ Integer.toHexString(resource) + “)”);
}

final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
两个方法的区别:
1、LayoutInflater.from(Context).inflate(layoutId,null)

会先调用方法

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
*终调用inflate方法时,三个参数分别是 inflate(layoutId,null,false)。

2、LayoutInflater.from(Context).inflate(layoutId,parent,false)

这个方法会直接执行上面的方法,此时参数分别是inflate(layoutId,parent,false),在这个例子中parent为RecyclerView的实例。

这里采用加载布局的方法不同,其实*终是传入inflate的参数不同,那么参数不同会导致什么结果呢?

进入下面的方法查看:

inflate(parser, root, attachToRoot)
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
//省略其他代码,直接看相关的代码
if (root != null) {//第二种方法
final View temp = createViewFromTag(root, name, attrs, false);//temp就是CardView

// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);//给temp设置ViewGroup.LayoutParams的属性(在本例中是GridLayoutManager)
}
}

// 这个方法会将temp下的所有子控件全部加载进来。
rInflate(parser, temp, attrs, true, true);

if (root != null && attachToRoot) {//第二种方法会执行
root.addView(temp, params);
}

if (root == null || !attachToRoot) {
result = temp;//*终会返回这个result
}
}
*种方法是进入上面的方法后,加载完子控件后直接返回CardView,没有添加到root中,所以layout_margin属性不起作用,因为layout_margin属性是需要一个父控件作为参照物的,没有添加到root就没有参照物了。
第二种方法是加载完所有子控件并且添加到root后,再返回CardView,CardView已经有参照物父控件root,所以属性能起到作用。

在做的时候,因为采用的是*种方法,一直android:layout_margin=”xx”的值,但是一直都没起任何作用。在更换为第二种方法后,才显示正常。

写在*后的话:

本来想着能实现了就行了,但是作为一个有追求(…)的程序猿,必须得知道为什么会这样才行,所以才想看看源码,看能不能找到原因,看了这一点点源码后,就把自己的理解写出来了,正确与否还有待验证哈。

*次涉及源码的解读分析,才发现还是看源码看得少,虽然是个简单的分析,但还是有收获的。

遗留问题:

还有一个问题是,为什么*种方法在4.4系统时就可以显示想要的效果,在5.1系统就不能显示那种效果呢。

如果有人知道,能够知会一声就更好了。

————————————————