LayoutInflater的使用

Inflater英文意思是膨胀,在Android中应该是扩展的意思吧。
LayoutInflater
的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!而 findViewById()是找具体某一个xml下的具体 widget控件(:Button,TextView)

0)她可以有很多地方可以使用,如BaseAdaptergetView中,自定义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 是一个抽象类,在文档中如下声明:

Java代码

  1. publicabstractclassLayoutInflaterextendsObject

public abstract classLayoutInflater extends Object

获得 LayoutInflater 实例的三种方式:

Java代码

  1. 1.LayoutInflaterinflater=getLayoutInflater();//调用Activity的getLayoutInflater()
  2. 2.LayoutInflaterlocalinflater=(LayoutInflater)context.getSystemService
  3. (Context.LAYOUT_INFLATER_SERVICE);
  4. 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()方法,看一下该源代码:

Java代码

  1. publicPhoneWindow(Contextcontext){
  2. super(context);
  3. mLayoutInflater=LayoutInflater.from(context);
  4. }

public PhoneWindow(Contextcontext) {

super(context);

mLayoutInflater =LayoutInflater.from(context);

}

可以看出它其实是调用LayoutInflater.from(context)。

LayoutInflater.from(context)

Java代码

  1. publicstaticLayoutInflaterfrom(Contextcontext){
  2. LayoutInflaterLayoutInflater=
  3. (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  4. if(LayoutInflater==null){
  5. thrownewAssertionError("LayoutInflaternotfound.");
  6. }
  7. returnLayoutInflater;
  8. }

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 对象,如下:

Java代码

  1. publicViewinflate(intresource,ViewGrouproot)
  2. publicViewinflate(XmlPullParserparser,ViewGrouproot)
  3. publicViewinflate(XmlPullParserparser,ViewGrouproot,booleanattachToRoot)
  4. 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

示意代码:

Java代码

  1. LayoutInflaterinflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
  2. Viewview=inflater.inflate(R.layout.custom,(ViewGroup)findViewById(R.id.test));
  3. //EditTexteditText=(EditText)findViewById(R.id.content);//error
  4. 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);注:每解析一次都会产生不同的对象
然后你再引用没问题,使用自如了。

由于自己写了一个CustomAdapter来继承CursorAdapter,要重写bindView和newView方法。
当一个ListActivity的启动时,onCreate方法中会setListAdapter为CustomAdapter。
当我打Log的时候发现每一个Item中bindView方法被调用了两次。也就是说,如果你有3个Item在List中,bindView就被调用了6次。
我想问一下CursorAdapter的bindView方法在什么时候被调用,为什么一个Item要调用两次bindView来显示?谢谢大家
这样的情形导致的问题是,有时候在查看List的时候,会发现字体出现明显的抖动,因为第一次刷新显示了所有了Item,但是后面又刷新显示了一次,这是因为每个Item两次调用bindView所致。当然,这种问题只有在数据量比较大的时候会出现延迟显示。不知道哪位高人能不能帮我解决一下。下面是简化的代码:
public class MyNotepad extends ListActivity {

private NotesDbAdapter mDbHelper;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notes_list);
mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();

fillData();

registerForContextMenu(getListView());
}

private void fillData() {
Cursor notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor);

CustomAdapter adapter = new CustomAdapter (this, notesCursor);
setListAdapter(adapter);
}


final class CustomAdapter extends CursorAdapter{

public CustomAdapter (Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}


@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Log.i("huaping", "newView");
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return li.inflate(R.layout.notes_row, parent, false);
}


@Override
public void bindView(View view, Context context, Cursor cursor) {
// TODO Auto-generated method stub
Log.i("huaping", "bindView");
String title = cursor.getString(KEY_TITLE);
final TextView views = (TextView) view.findViewById(R.id.text1);
views.setText(title);
}
}

}

SimpleAdapter,跟名字一样,一个简单的适配器,既为简单,就只是被设计来做简单的应用的,比如静态数据的绑定,不过仍然有自定义的空间,比如说在每一个ListItem中加一个按钮并添加响应事件.首先还是先看一下SimpleAdapter的定义吧,直接翻译下SDK doc :

  这是一个简单的适配器,可以将静态数据映射到XML文件中定义好的视图。你可以指定由Map组成的List(比如ArrayList)类型的数据。在ArrayList中的每个条目对应List中的一行。Maps包含每一行的数据。你可以指定一个XML布局以指定每一行的视图,根据Map中的数据映射关键字到指定的视图。绑定数据到视图分两个阶段,首先,如果设置了SimpleAdapter.ViewBinder,那么这个设置的ViewBindersetViewValue(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循环中每个mapput进了两个键值对,键名跟from中定义的一一对应,这就表示对于ListView中的每一项,依次寻找在to参数中定义的资源ID,根据这个资源IDto参数数组中的位置,找到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调用bindersetViewValue(此例中是R.id.textR.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);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值