自定义SimpleAdapter

时光毁灭记忆、已成空白 提交于 2020-03-06 18:59:32

 

 

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)

参数:

  • context  SimpleAdapter关联的View的运行环境
  • data    一个Map组成的List。在列表中的每个条目对应列表中的一行,每一个map中应该包含所有在from参数中指定的键
  • resource    一个定义列表项的布局文件的资源ID。布局文件将至少应包含那些在to中定义了的ID
  • from          一个将被添加到Map映射上的键名
  • to     将绑定数据的视图的ID,跟from参数对应,这些应该全是TextView

举个例子:

复制代码
public void 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的函数实现的

复制代码
   private void bindView(int position, View view) {         final Map dataSet = mData.get(position);         if (dataSet == null) {             return;         }        final ViewBinder binder = mViewBinder;         final String[] from = mFrom;         final int[] to = mTo;         final int 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 (v instanceof Checkable) {                         if (data instanceof Boolean) {                             ((Checkable) v).setChecked((Boolean) data);                         } else if (v instanceof TextView) {                             // Note: keep the instanceof TextView check at the bottom of these                             // ifs since a lot of views are TextViews (e.g. CheckBoxes).                             setViewText((TextView) v, text);                         } else {                             throw new IllegalStateException(v.getClass().getName() +                                     " should be bound to a Boolean, not a " +                                     (data == null ? "<unknown type>" : data.getClass()));                         }                     } else if (v instanceof TextView) {                         // Note: keep the instanceof TextView check at the bottom of these                         // ifs since a lot of views are TextViews (e.g. CheckBoxes).                         setViewText((TextView) v, text);                     } else if (v instanceof ImageView) {                         if (data instanceof Integer) {                             setViewImage((ImageView) v, (Integer) data);                                                     } else {                             setViewImage((ImageView) v, text);                         }                     } else {                         throw new 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     public boolean setViewValue(View view, Object data, String textRepresentation) {          if (view instanceof Button) {             final View button = view; //            button.setBackgroundDrawable(getResources().getDrawable(R.drawable.ic_launcher));             view.setOnClickListener(new OnClickListener() {                LinearLayout listItem = (LinearLayout) button.getParent();                TextView tv = (TextView) listItem.findViewById(R.id.text);                 @Override                 public void onClick(View v) {                     Toast.makeText(AdapterDemoActivity.this, tv.getText(), Toast.LENGTH_SHORT).show();                 }             });             return false;         }         return false;     } }; 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     public boolean setViewValue(View view, Object data, String textRepresentation) {         if (view instanceof Button) {             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));             return false;         }         return false;     } };  adapter.setViewBinder(binder);
复制代码

 

 

 

作者:AngelDevil 出处:www.cnblogs.com/angeldevil

 

转载!

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)

参数:

  • context  SimpleAdapter关联的View的运行环境
  • data    一个Map组成的List。在列表中的每个条目对应列表中的一行,每一个map中应该包含所有在from参数中指定的键
  • resource    一个定义列表项的布局文件的资源ID。布局文件将至少应包含那些在to中定义了的ID
  • from          一个将被添加到Map映射上的键名
  • to     将绑定数据的视图的ID,跟from参数对应,这些应该全是TextView

举个例子:

复制代码
public void 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的函数实现的

复制代码
   private void bindView(int position, View view) {         final Map dataSet = mData.get(position);         if (dataSet == null) {             return;         }        final ViewBinder binder = mViewBinder;         final String[] from = mFrom;         final int[] to = mTo;         final int 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 (v instanceof Checkable) {                         if (data instanceof Boolean) {                             ((Checkable) v).setChecked((Boolean) data);                         } else if (v instanceof TextView) {                             // Note: keep the instanceof TextView check at the bottom of these                             // ifs since a lot of views are TextViews (e.g. CheckBoxes).                             setViewText((TextView) v, text);                         } else {                             throw new IllegalStateException(v.getClass().getName() +                                     " should be bound to a Boolean, not a " +                                     (data == null ? "<unknown type>" : data.getClass()));                         }                     } else if (v instanceof TextView) {                         // Note: keep the instanceof TextView check at the bottom of these                         // ifs since a lot of views are TextViews (e.g. CheckBoxes).                         setViewText((TextView) v, text);                     } else if (v instanceof ImageView) {                         if (data instanceof Integer) {                             setViewImage((ImageView) v, (Integer) data);                                                     } else {                             setViewImage((ImageView) v, text);                         }                     } else {                         throw new 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     public boolean setViewValue(View view, Object data, String textRepresentation) {          if (view instanceof Button) {             final View button = view; //            button.setBackgroundDrawable(getResources().getDrawable(R.drawable.ic_launcher));             view.setOnClickListener(new OnClickListener() {                LinearLayout listItem = (LinearLayout) button.getParent();                TextView tv = (TextView) listItem.findViewById(R.id.text);                 @Override                 public void onClick(View v) {                     Toast.makeText(AdapterDemoActivity.this, tv.getText(), Toast.LENGTH_SHORT).show();                 }             });             return false;         }         return false;     } }; 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     public boolean setViewValue(View view, Object data, String textRepresentation) {         if (view instanceof Button) {             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));             return false;         }         return false;     } };  adapter.setViewBinder(binder);
复制代码

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!