您的位置:首页 > 移动开发 > Android开发

android 深入理解LayoutInflater.inflate()

2016-02-25 16:08 525 查看
LayoutInflater类做过android开发的人都用过,它是负责把一个layout文件变成View对象的,LayoutInflater类有一个inflater(),它重载的方法有四个



我们就说前二个,现在对他的形参做下解释:

第一个参数是resource:表示是传递的layout文件

第二个参数:把第一个参数layout文件是否挂载在该ViewGroup中,

第三个参数:是一个boolean类型,是否第一个参数是否挂载在第二个参数viewgroup中

我在网上看了下对第三个参数的解释,还是挺好的:

被填充的层是否应该附在root参数内部?如果是false,root参数只是用于为XML根元素View创建正确的LayoutParams的子类

其实意思就是:如果attachToRoot是true的话,那第一个参数的layout文件就会被填充并附加在第二个参数所指定的ViewGroup内。方法返回结合后的View,根元素是第二个参数ViewGroup。如果是false的话,第一个参数所指定的layout文件会被填充并作为View返回。这个View的根元素就是layout文件的根元素。不管是true还是false,都需要ViewGroup的LayoutParams来正确的测量与放置layout文件所产生的View对象。

attachToRoot传入true代表layout文件填充的View会被直接添加进ViewGroup,而传入false则代表创建的View会以其他方式被添加进ViewGroup

相当于viewgroup.addView(view,layoutparams)现在写个demo演示下:

package com.zhimore.layoutinflaterdemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
private LinearLayout ll_root;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
ll_root = (LinearLayout) findViewById(R.id.ll_root);
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.btn_content,ll_root,true);
}
}


content_main.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:text="Hello World!"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
/>
<TextView
android:text="Hello World!"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
/>
<TextView
android:text="Hello World!"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
/>
<TextView
android:text="Hello World!"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
/>
</LinearLayout>

我们运行起来看下:



现在我们把第二个和第三方参数改成
inflater.inflate(R.layout.btn_content,null,false);


发现这样并没有任何效果,

我们现在自定义一个LinearLayout,

package com.zhimore.layoutinflaterdemo.com.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import com.zhimore.layoutinflaterdemo.R;
/**
* Created by Administrator on 2016/2/25.
*/
public class MyLinearLayout extends LinearLayout{
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.btn_content,this,true);
}
public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}


运行起来



我们发现在自定义ViewGroup的时候,使用这个就是往viewgroup中添加子view的,

当在Fragment的onCreateView()方法中填充并返回View时,要将attachToRoot设为false。如果传入true,会抛出IllegalStateException,因为指定的子View已经有父View了。你需要指定在哪里将Fragment的View放进Activity里,而添加、移除或替换Fragment则是FragmentManager的事情。

上面代码中root_viewGroup就是Activity中用于放置Fragment的容器,它会作为inflate()方法中的第二个参数被传入onCreateView()中。它也是你在inflate()方法中传入的ViewGroup。FragmentManager会将Fragment的View添加到ViewGroup中,你可不想添加两次。

问题是:如果我们不需在onCreateView()中将View添加进ViewGroup,为什么还要传入ViewGroup呢?为什么inflate()方法必须要传入根ViewGroup?

原因是及时不需要马上将新填充的View添加进ViewGroup,我们还是需要这个父元素的LayoutParams来在将来添加时决定View的size和position。

你在网上一定会遇到一些不正确的建议。有些人会建议你如果将attachToRoot设置为false的话直接将根ViewGroup传入null。但是,如果有父元素的话,还是应该传入的。



Lint会警告你不要讲null作为root传入。你的App不会挂掉,但是可能会表现异常。当你的子View没有正确的LayoutParams时,它会自己通过generateDefaultLayoutParams)计算。

你可能并不想要这些默认的LayoutParams。你在XML指定的LayoutParams会被忽略。我们可能已经指定了子View要填充父元素的宽度,但父View又wrap_content导致最终的View小很多。

下面是一种没有ViewGroup作为root传入inflate()方法的情况。当为AlertDialog创建自定义View时,还无法访问父元素。

在这种情况下,可以将null作为root ViewGroup传入。后来我发现AlertDialog还是会重写LayoutParams并设置各项参数为match_parent。但是,规则还是在有ViewGroup可以传入时传入它。


避开崩溃、异常表现与误解

希望这篇文章可以帮助你在使用LayoutInflater时避开崩溃、异常表现与误解。下面整理了文章的要点:

1:如果可以传入ViewGroup作为根元素,那就传入它。

2:避免将null作为根ViewGroup传入。

3:当我们不负责将layout文件的View添加进ViewGroup时设置attachToRoot参数为false。

4:不要在View已经被添加进ViewGroup时传入true。

5:自定义View时很适合将attachToRoot设置为true
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: