其实通过inflate从xml加载的view,被动态的添加到其他视图中,view的layout_xx属性是否有效,关键在于,加载完后,view的LayoutParam属性是否和xml中的layout_xx属性一致。因为当系统无法计算view的layout_xx属性时,view 的LayoutParam是空的,所以在addView的时候,系统会设置一个默认的LayoutParam,导致我们xml中设置的属性失效。
下面介绍为何view的layout_xx何时失效:
在这里我们将我们需要从布局文件加载的视图成为view,当加载的布局的layout_width 和layout_height 不为warp_content(因为默认的便是warp_content)时(当然还有其他layout_xx属性,这里都是类似的)
inflate 时root为null时:
因为view没有父布局,所以view无法计算layout_xx属(因为layout_xx的意思是view在 父布局中的位置尺寸信息,所以没有父布局,layout_xx属性无法计算),所以此时的布局属性都为默认(layout_width 和 layout_height 都为warp_content,这样设计也是很合理的,因为虽然不能得知自身的大小,而且系统又必须需要一个尺寸去绘制,所以布局会算出自身最小的尺寸为多少,当布局中没有任何子视图时,那么它就会得到自身最小的尺寸为0)
示例:
首先我们建议个activity的布局文件,并在该布局中添加我们要动态加载的view
activity布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rl_parent">
<Button
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:text="添加"
android:id="@+id/btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
我们要加载的view的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#00ff00">
<Button
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button" />
</LinearLayout>
上面我们设置view的layout_width和layout_height属性都为200dp
在代码中加载view并将该view添加到我们的activity的布局中
public class InlterAndAddViewDemoActivity extends BaseActivity {
@ViewInject(id = R.id.btn_add)
private Button mBtnAdd;
private LayoutInflater mInflater;
private ViewGroup mLayout;
@Override
protected int initLayout() {
return R.layout.activity_inlter_and_add_view_demo;
}
@Override
protected void initView() {
ViewUtils.inject(this);
mBtnAdd.setOnClickListener(this);
mInflater = LayoutInflater.from(this);
mLayout = (ViewGroup) findViewById(R.id.rl_parent);
}
@Override
protected void OnClick(View v) {
switch (v.getId()) {
case R.id.btn_add: {
addButton();
}
break;
}
}
private void addButton() {
View v = mInflater.inflate(R.layout.inlatebutton_layout, null, false);
mLayout.addView(v);
}
}
运行后如下图:
可以看到我们设置的layout_width 和 layout_height并未生效,下面我们看一下view的LayoutParam
继续查看addView(child,-1)
可以看到,如果LayoutParam为空时,系统会为view生成一个默认的layoutparam,我们在看一下generateDfaultLayoutparams();
这样我们就明白了,当我们加载view时,root为空,系统会为view设置layout_width和layout_height设置为warp_content,以及其他layout_xx设置默认值,所以我们在xml设置的layout_xx属性无法生效。
当inflate中的root不为null时 attachToRoot为false:
我们修改上面的添加view的代码
LinearLayout l = new LinearLayout(this);
View v = mInflater.inflate(R.layout.inlatebutton_layout, l, false);
Log.i(TAG,"LayoutParam===" + v.getLayoutParams());
mLayout.addView(v);
运行结果:
可以看到我们的view的layout_width和layout_height生效了,下面我们为view多添加几个layout_xx属性看一下
inflate_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="200dp"
android:orientation="vertical"
android:layout_margin="20dp"
android:layout_gravity="center_horizontal"
android:background="#00ff00">
<Button
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="button" />
</LinearLayout>
我们添加了margin和gravity属性,看下效果
可以看到和我们之前没有添加时下效果是一样的,为什么呢?之前我们已经得到结论,当一个view的LayoutParams为空时,则系统为他默认设置一个默认的LayutParam,而默认的layout_width和layout_height 都为warp_content,所以当root没有设置LayoutParam时,它的layout_width和layout_height都为warp_content,那么root将包裹view,所以也就不存在margin和gravity属性的意义了。
所以我们需要给root手动的设置以个LayoutParam,而且如果我们需要view的其他layout_xx属性生效,我们只要将attachToRoot设置为true就行了(详情参见郭神的文章)
本文为本人学习研究记录.