Inflater英文意思是膨胀,在Android中应该是扩展的意思吧。
LayoutInflater的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!而 findViewById()是找具体某一个xml下的具体 widget控件(如:Button,TextView等)。
(0)她可以有很多地方可以使用,如BaseAdapter的getView中,自定义Dialog中取得view中的组件widget等等。
它的用法有2种:
复制到剪贴板Java代码
1. viewplaincopytoclipboardprint?
2. LayoutInflaterinflater=LayoutInflater.from(this);
3. Viewview=inflater.inflate(R.layout.ID,null);
4. 或者干脆并成一句:
5. Viewview=LayoutInflater.from(this).inflate(R.layout.ID,null);
另一种方法:
复制到剪贴板Java代码
1. viewplaincopytoclipboardprint?
2. LayoutInflaterinflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
3. Viewview=inflater.inflate(R.layout.ID,null);
上面2种方法本质上是一样的,看下面的源码,form()调用的就是getSystemService():
复制到剪贴板Java代码
1. Java代码
2. publicstaticLayoutInflaterfrom(Contextcontext){
3. LayoutInflaterLayoutInflater=
4. (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
5. if(LayoutInflater==null){
6. thrownewAssertionError("LayoutInflaternotfound.");
7. }
8. returnLayoutInflater;
9. }
另外getSystemService()是Android很重要的一个API,它是Activity的一个方法,根据传入的NAME来取得对应的Object,然后转换成相应的服务对象。以下介绍系统相应的服务。
传入的Name | 返回的对象 | 说明 |
WINDOW_SERVICE | WindowManager | 管理打开的窗口程序 |
LAYOUT_INFLATER_SERVICE | LayoutInflater | 取得xml里定义的view |
ACTIVITY_SERVICE | ActivityManager | 管理应用程序的系统状态 |
POWER_SERVICE | PowerManger | 电源的服务 |
ALARM_SERVICE | AlarmManager | 闹钟的服务 |
NOTIFICATION_SERVICE | NotificationManager | 状态栏的服务 |
KEYGUARD_SERVICE | KeyguardManager | 键盘锁的服务 |
LOCATION_SERVICE | LocationManager | 位置的服务,如GPS |
SEARCH_SERVICE | SearchManager | 搜索的服务 |
VEBRATOR_SERVICE | Vebrator | 手机震动的服务 |
CONNECTIVITY_SERVICE | Connectivity | 网络连接的服务 |
WIFI_SERVICE | WifiManager | Wi-Fi服务 |
TELEPHONY_SERVICE | TeleponyManager | 电话服务 |
复制到剪贴板Java代码
1. Java代码
2. //基本用法
3. publicvoidshowCustomDialog(){
4. AlertDialog.Builderbuilder;
5. AlertDialogalertDialog;
6. ContextmContext=AppActivity.this;
7. //下面俩种方法都可以
8. //LayoutInflaterinflater=getLayoutInflater();
9. LayoutInflaterinflater=(LayoutInflater)
10.mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
11.Viewlayout=inflater.inflate(R.layout.custom_dialog,null);
12.TextViewtext=(TextView)layout.findViewById(R.id.text);
13.text.setText("Hello,WelcometoMrWei'sblog!");
14.ImageViewimage=(ImageView)layout.findViewById(R.id.image);
15.image.setImageResource(R.drawable.icon);
16.builder=newAlertDialog.Builder(mContext);
17.builder.setView(layout);
18.alertDialog=builder.create();
19.alertDialog.show();
20.}
21.}
22.
23.protectedvoidshowToast(inttype){
24.Toast.makeText(this,"*********",Toast.LENGTH_LONG).show();
25.
26.LayoutInflaterli=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
27.Viewview=li.inflate(R.layout.toast,null);
28.
29.Toasttoast=newToast(this);
30.toast.setView(view);
31.toast.setDuration(type);
32.toast.show();
33.}
在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()。不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如 Button、TextView等)。
具体作用:
1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;
2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。
LayoutInflater 是一个抽象类,在文档中如下声明:
- publicabstractclassLayoutInflaterextendsObject
public abstract classLayoutInflater extends Object
获得 LayoutInflater 实例的三种方式:
- 1.LayoutInflaterinflater=getLayoutInflater();//调用Activity的getLayoutInflater()
- 2.LayoutInflaterlocalinflater=(LayoutInflater)context.getSystemService
- (Context.LAYOUT_INFLATER_SERVICE);
- 3.LayoutInflaterinflater=LayoutInflater.from(context);
1. LayoutInflater inflater =getLayoutInflater(); //调用Activity的getLayoutInflater()
2. LayoutInflater localinflater= (LayoutInflater)context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
3. LayoutInflater inflater =LayoutInflater.from(context);
其实,这三种方式本质是相同的,从源码中可以看出:
getLayoutInflater():
Activity 的 getLayoutInflater()方法是调用 PhoneWindow 的getLayoutInflater()方法,看一下该源代码:
- publicPhoneWindow(Contextcontext){
- super(context);
- mLayoutInflater=LayoutInflater.from(context);
- }
public PhoneWindow(Contextcontext) {
super(context);
mLayoutInflater =LayoutInflater.from(context);
}
可以看出它其实是调用LayoutInflater.from(context)。
LayoutInflater.from(context):
- publicstaticLayoutInflaterfrom(Contextcontext){
- LayoutInflaterLayoutInflater=
- (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- if(LayoutInflater==null){
- thrownewAssertionError("LayoutInflaternotfound.");
- }
- returnLayoutInflater;
- }
public static LayoutInflaterfrom(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw newAssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
可以看出它其实调用 context.getSystemService()。
结论:所以这三种方式最终本质是都是调用的Context.getSystemService()。
inflate 方法
通过 sdk 的 api 文档,可以知道该方法有以下几种过载形式,返回值均是 View 对象,如下:
- publicViewinflate(intresource,ViewGrouproot)
- publicViewinflate(XmlPullParserparser,ViewGrouproot)
- publicViewinflate(XmlPullParserparser,ViewGrouproot,booleanattachToRoot)
- publicViewinflate(intresource,ViewGrouproot,booleanattachToRoot)
public View inflate (intresource, ViewGroup root)
public View inflate(XmlPullParser parser, ViewGroup root)
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)
public View inflate (intresource, ViewGroup root, boolean attachToRoot)
1:
public View inflate (int resource,ViewGroup root)
reSource:View的layout的ID
root:如果为null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null,则将默认的layout作为View的根。
2:
public View inflate ( XmlPullParser parser, ViewGrouproot)
parser:你需要解析xml的解析接口
root:如果null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null, 则将默认的layout作为View的根。
3:
public View inflate ( XmlPullParser parser, ViewGrouproot, boolean attachToRoot)
parser:你需要解析View的xml的解析接口
root:如果null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null, 则将默认的layout作为View的根。
attachToRoot:
ture:也就将此解析的xml作为View根
fase:则为默认的xml,做为根视图View
4:
public View inflate (int resource,ViewGroup root, boolean attachToRoot)
resource:View的layout的ID
root:如果null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null, 则将默认的layout作为View的根。
attachToRoot:
ture:也就将此解析的xml作为View根
fase:则为默认的xml,做为根视图View
示意代码:
- LayoutInflaterinflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
- Viewview=inflater.inflate(R.layout.custom,(ViewGroup)findViewById(R.id.test));
- //EditTexteditText=(EditText)findViewById(R.id.content);//error
- EditTexteditText=(EditText)view.findViewById(R.id.content);
LayoutInflater inflater =(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
View view =inflater.inflate(R.layout.custom, (ViewGroup)findViewById(R.id.test));
//EditText editText =(EditText)findViewById(R.id.content);// error
EditText editText =(EditText)view.findViewById(R.id.content);
同时在此讲讲让我去API中去理解这四个函数的原因吧!嘿嘿!你肯定又会多学一招!
在Activity中:
大家是否知道,在setContentView(newMySurfaceView(this))后,此Activity中声明的View控件,
如:TextView 为什么引用不到layout布局文件中的控件ID呢!初一看能够应用到,但是为什么编译就报空指针呢!原因:在setContentView(newMySurfaceView(this))后,此时的View变为了根视图了,虽然能应用到TextView对应的ID,但是我在MySurfaceView中根本就没有这个对象,所以就报空指针咯!解决办法:
View view = LayoutInflater.from(this).inflate(R.layout.passover, null);注:每解析一次都会产生不同的对象
然后你再引用没问题,使用自如了。
|
SimpleAdapter,跟名字一样,一个简单的适配器,既为简单,就只是被设计来做简单的应用的,比如静态数据的绑定,不过仍然有自定义的空间,比如说在每一个ListItem中加一个按钮并添加响应事件.首先还是先看一下SimpleAdapter的定义吧,直接翻译下SDK doc 吧:
这是一个简单的适配器,可以将静态数据映射到XML文件中定义好的视图。你可以指定由Map组成的List(比如ArrayList)类型的数据。在ArrayList中的每个条目对应List中的一行。Maps包含每一行的数据。你可以指定一个XML布局以指定每一行的视图,根据Map中的数据映射关键字到指定的视图。绑定数据到视图分两个阶段,首先,如果设置了SimpleAdapter.ViewBinder,那么这个设置的ViewBinder的setViewValue(android.view.View,Object, String)将被调用。如果setViewValue的返回值是true,则表示绑定已经完成,将不再调用系统默认的绑定实现。如果返回值为false,视图将按以下顺序绑定数据:
·如果View实现了Checkable(例如CheckBox),期望绑定值是一个布尔类型。
·TextView.期望绑定值是一个字符串类型,通过调用setViewText(TextView, String)绑定。
·ImageView,期望绑定值是一个资源id或者一个字符串,通过调用setViewImage(ImageView,int) 或 setViewImage(ImageView, String)绑定数据。
如果没有一个合适的绑定发生将会抛出IllegalStateException。
先看一下构造函数:
public SimpleAdapter (Context context,List<?extends Map<String, ?>> data,int resource, String[] from,int[] to)
参数
contextSimpleAdapter关联的View的运行环境
data一个Map组成的List。在列表中的每个条目对应列表中的一行,每一个map中应该包含所有在from参数中指定的键
resource 一个定义列表项的布局文件的资源ID。布局文件将至少应包含那些在to中定义了的ID
from 一个将被添加到Map映射上的键名
to将绑定数据的视图的ID,跟from参数对应,这些应该全是TextView
举个例子:
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView lv = (ListView)findViewById(R.id.listView1);
String[] from = {"Text", "Button" };
int[] to = { R.id.text, R.id.button };
List<Map<String, ?>>list = new ArrayList<Map<String,?>>();
for (int i = 0; i < 10; i++) {
Map<String, String> m =new HashMap<String, String>();
m.put("Text","Text" + i);
m.put("Button","Button" + i);
list.add(m);
}
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.listitem, from, to);
lv.setAdapter(adapter);
}
listitem.xml
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:id="@+id/text"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
ListView中的每一项都包含一个TextView跟一个Button,在SimpleAdapter的构造函数中,我们指定了要绑定的数据:list, list是一个由Map组成的ArrayList, Map的作用就是连同后面的from, to参数定义数据是如何绑定的,在上面的例子中
String[]from = { "Text", "Button" };
int[] to = { R.id.text, R.id.button };
而在for循环中每个map都put进了两个键值对,键名跟from中定义的一一对应,这就表示对于ListView中的每一项,依次寻找在to参数中定义的资源ID,根据这个资源ID在to参数数组中的位置,找到from参数中对应位置的值,以这个值为键,在list中的相应项(一个Map)中以这个值为键取出这个键对应的值绑定到这个资源ID对应的视图中.
在上面的例子中每一个ListItem都包含一个TextView与一个Button,但程序运行起来后会发现,按钮可以点击,而ListItem却无法点击,而且没有对每一个Button关联响应事件,ListItem无法点击是因为按钮抢占了ListItem的焦点,在listitem.xml而已文件中对LinearLayout加上一个属性就可解决问题:
android:descendantFocusability="blocksDescendants"
下面的问题就是Button的响应事件了.
我的们下SimpleAdaper的源码会发现,数据的绑定是能过一个叫bindView的函数实现的
privatevoid bindView(int position, View view) {
final Map dataSet = mData.get(position);
if (dataSet ==null) {
return;
}
final ViewBinder binder = mViewBinder;
final String[] from = mFrom;
finalint[] to = mTo;
finalint count =to.length;
for (int i = 0; i <count; i++) {
final View v = view.findViewById(to[i]);
if (v !=null) {
final Object data = dataSet.get(from[i]);
String text = data == null ? "" : data.toString();
if (text ==null) {
text = "";
}
boolean bound =false;
if (binder !=null) {
bound =binder.setViewValue(v, data, text);
}
if (!bound) {
if (vinstanceofCheckable) {
if (datainstanceofBoolean) {
((Checkable)v).setChecked((Boolean) data);
} elseif (vinstanceof TextView) {
// Note: keep the instanceof TextViewcheck at the bottom of these
// ifs since a lot of views areTextViews (e.g. CheckBoxes).
setViewText((TextView) v, text);
} else {
thrownew IllegalStateException(v.getClass().getName() +
"should be bound to a Boolean, not a " +
(data== null ? "<unknown type>" :data.getClass()));
}
} elseif (vinstanceof TextView) {
// Note: keep the instanceof TextView checkat the bottom of these
// ifs since alot of views are TextViews (e.g. CheckBoxes).
setViewText((TextView)v, text);
} elseif (vinstanceof ImageView) {
if (datainstanceofInteger) {
setViewImage((ImageView) v, (Integer) data);
} else {
setViewImage((ImageView)v, text);
}
} else {
thrownew IllegalStateException(v.getClass().getName() + " is not a " +
"view that can be bounds by this SimpleAdapter");
}
}
}
}
}
其流程大致是,首先检查SimpleAdapter有没有指定SimpleAdapter.ViewBinder,如果指定了就调用其setViewValue方法, SimpleAdapter.ViewBinder是一个接口,也只有这一个方法,如果ViewBinder返回true表示我们已经完成了对这个View的数据绑定,就不再调用系统默认的实现,当然我们也可以设置一个ViewBinder添加一些功能后通过返回false再让系统绑定数据,比如对按钮添加响应事件,而按钮上的文字由默认实现绑定.通过看bindView的实现就可以明白开始时所说的绑定顺序了:Checkable,TextView,ImageView.
我们对ListItem的自定义是通过对SimpleAdapter设置ViewBinder来实现的
SimpleAdapter.ViewBinder binder = new SimpleAdapter.ViewBinder() {
@Override
publicboolean setViewValue(View view, Object data, String textRepresentation) {
if (viewinstanceofButton) {
final View button = view;
// button.setBackgroundDrawable(getResources().getDrawable(R.drawable.ic_launcher));
view.setOnClickListener(new OnClickListener() {
LinearLayoutlistItem = (LinearLayout) button.getParent();
TextView tv =(TextView) listItem.findViewById(R.id.text);
@Override
publicvoid onClick(View v) {
Toast.makeText(AdapterDemoActivity.this, tv.getText(), Toast.LENGTH_SHORT).show();
}
});
returnfalse;
}
returnfalse;
}
};
adapter.setViewBinder(binder);
系统对每一个view调用binder的setViewValue(此例中是R.id.text和R.id.button,一个TextView与一个Button),我们首先检测这个view是不是一个Button,如果是的话就关联点击事件,可能通过getParent()函数取得parentView以找到这个view的兄弟view,比如这个例子中的实现就是点击Button后输出这个Button所在的ListItem中的TextView上的文字.
在setViewValue中可以完全自定义我们的实现,比如在Button后加一个TextView,当然可以加任何View,但这样做没任何意义,当你需要这样做时你不需要用SimpleAdater而应该用BaseAdapter:
SimpleAdapter.ViewBinder binder = new SimpleAdapter.ViewBinder() {
@Override
publicboolean setViewValue(View view, Object data, String textRepresentation) {
if (viewinstanceofButton) {
final View button = view;
LinearLayout listItem= (LinearLayout) button.getParent();
TextView textView = new TextView(AdapterDemoActivity.this);
textView.setText("AA");
listItem.addView(textView,new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
returnfalse;
}
returnfalse;
}
};
adapter.setViewBinder(binder);