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

LayoutInflater三种模式的差别

2015-09-06 15:15 239 查看
LayoutInflater有三种加载方法,分别是inflate(layoutId, null ),inflate(layoutId,
root, false ) ,inflate(layoutId, root, true ).对于这三种方法加载有什么区别呢?下面我们用一个listview去看一下,新建一个listview,里面只有一个button:

Activity的布局文件:<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/id_listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
Listview的Item文件:
<Button xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/id_btn"
android:layout_width="120dp"
android:layout_height="120dp" >

</Button>
Listview的适配器:
<pre name="code" class="java">public class MyAdapter extends BaseAdapter
{

private LayoutInflater mInflater;
private List<String> mDatas;

public MyAdapter(Context context, List<String> datas)
{
mInflater = LayoutInflater.from(context);
mDatas = datas;
}

@Override
public int getCount()
{
return mDatas.size();
}

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

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

@Override
public View getView(int position, View convertView, ViewGroup parent)
{

ViewHolder holder = null;
if (convertView == null)
{
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.item, null);
//			convertView = mInflater.inflate(R.layout.item, parent ,false);
//			convertView = mInflater.inflate(R.layout.item, parent ,true);
holder.mBtn = (Button) convertView.findViewById(R.id.id_btn);
convertView.setTag(holder);
} else
{
holder = (ViewHolder) convertView.getTag();
}

holder.mBtn.setText(mDatas.get(position));

return convertView;
}

private final class ViewHolder
{
Button mBtn;
}
}



主Activity:
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class MainActivity extends Activity
{

private ListView mListView;
private MyAdapter mAdapter;
private List<String> mDatas = Arrays.asList("Hello", "Java", "Android");

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

mListView = (ListView) findViewById(R.id.id_listview);
mAdapter = new MyAdapter(this, mDatas);
mListView.setAdapter(mAdapter);

}

}

我们主要关注getView里面的inflate那行代码:下面我依次把getView里的写成:
1、convertView = mInflater.inflate(R.layout.item, null);
2、convertView = mInflater.inflate(R.layout.item, parent ,false);
3、convertView = mInflater.inflate(R.layout.item, parent ,true);
第一个方法加载后,我们会发现listView中的item设置的宽高无效,显示的item为wrap_content的

第二个方法加载后,我们会发现listView中的item设置的宽高得到了正确的执行,显示的item为我们设置的宽高

第三个方法加载后,会报“addView(View)
is not supported in AdapterView”错误。

然后观察源码我们会发现:

对于第一种加载方法,没有为其设置相应于父布局的layoutParams所以无法显示正常的宽高

对于第二种加载方法,为其设置了相应于父布局的layoutParams,所以可以正常显示item制定的宽高

对于第三种加载方法,会调用root.addview()方法,而adapterview是不支持addview()的,所以会抛出异常

那么为什么设置layoutParams就无法显示正常的宽高呢?我们从viewgroup和view的onmeasure()方法解析:

ViewGroup的onMeasure方法所做的是:

为childView设置测量模式和测量出来的值。

如何设置呢?就是根据LayoutParams。
如果childView的宽为:LayoutParams. MATCH_PARENT,则设置模式为MeasureSpec.EXACTLY,且为childView计算宽度如果childView的宽为:固定值(即大于0),则设置模式为MeasureSpec.EXACTLY,且将lp.width直接作为childView的宽度如果childView的宽为:LayoutParams.
WRAP_CONTENT,则设置模式为:MeasureSpec.AT_MOST

View的onMeasure方法:

主要做的就是根据ViewGroup传入的测量模式和测量值,计算自己应该的宽和高:
一般是这样的流程:
如果宽的模式是AT_MOST:则自己计算宽的值。
如果宽的模式是EXACTLY:则直接使用MeasureSpec.getSize(widthMeasureSpec);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息