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

LayoutInflater的inflate方法学习

2016-04-20 19:45 513 查看
LayoutInflater的inflate方法很常用,用于动态加载布局。inflate方法有四种调用方式:

public View inflate(int resource, ViewGroup root);

public View inflate(XmlPullParser parser, ViewGroup root);

public View inflate(int resource, ViewGroup root, boolean attachToRoot);

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot);

实质上最后都是调用第4个方法,内部原理即用XmlPullParser解析xml文件,然后返回view对象。

接下来针对我们最常用的public View inflate(int resource, ViewGroup root, boolean attachToRoot)方法进行说明。

首先,参数说明。

1. resource:布局的资源id

2. root:填充的根视图

3. attachToRoot:是否将创建的师傅绑定到根视图中

那么问题来了?

inflate(layoutId, null )

inflate(layoutId, root, false)

inflate(layoutId, root, true)

以上三种方式到底有什么区别?接下来通过一个简单的示例来说明。

首页放置一个listview。下面是list_item.xml的内容。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="50dp">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text_tv"
android:textSize="16sp"
android:text="Hello world!"/>
</LinearLayout>


main_activity.java的内容如下:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);

ListView myListView = (ListView)findViewById(R.id.list_view);
myListView.setAdapter(new MyAdapter(this));
}

private class MyAdapter extends BaseAdapter {

private LayoutInflater inflater;

public MyAdapter(Context context) {
inflater = LayoutInflater.from(context);
}

@Override
public int getCount() {
return 10;
}

@Override
public Object getItem(int position) {
return position;
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = inflater.inflate(R.layout.list_item,null);
}

return convertView;
}
}
}


区别在于getView中的布局加载方式:

①convertView = inflater.inflate(R.layout.list_item,null);

②convertView = inflater.inflate(R.layout.list_item,parent,false);

③convertView = inflater.inflate(R.layout.list_item,parent,true);

三者的运行结果分别是这样的:

方式①如图。可见list_item根布局的属性没有生效。



方式②:



方式③:

程序crash。log如下:



接下来,回到inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) 方法中看看为什么会这样。

ViewGroup.LayoutParams params = null;

if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// 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);
}
}

if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp
rInflate(parser, temp, attrs, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}

// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}

// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}


从源码中可以发现,如果root为null,因为layout_width,layout_height是相对父级视图设置的,必须与父级的LayoutParams一致。而此时的getLayoutParams为null,list_item根布局的属性会被忽略掉,而使用默认的wrap_content方式。所以设置的高度被忽略。如果要使高度生效,可以将根布局的layout_height改为wrap_content, 而将textview的layout_height改为50dp。如果root不为null,attachToRoot为false,则可以正确地处理。

如果root不为null,attachToRoot为true,则会将改布局通过addview绑定到root视图里去,而此时的root是我们的ListView,ListView为AdapterView的子类,listview不支持addview方法,因此方式③就报错了。但是如果换一种场景,假设根布局是LinearLayout,用方式③是正确的,相当于在原有布局中动态加载布局。

如果root不为null,attachToRoot为true则返回root;attachToRoot为false则返回加载的view本身。

看到这里,平时在使用inflate方法时,属性不生效、或者参数到底该怎么传也就明白了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android