Android中自定义ListView
2014-02-02 01:57
225 查看
在使用Android的ListView的时候,Android系统自带了一些简单的布局,但是如果要做出比较复杂的显示列表——像新浪微博的微博列表,就需要对列表的显示进行自定义。
在自定义时,大致需要一下步骤:
一、在res/layout/文件下新建一个布局文件
假设新建一个文件名叫做custom_list_view.xml,此文件用于显示单个列表项,相当于显示一条微博,包含的内容有头像、微博内容、图片、转发数、评论数等。这个布局文件和Activity的布局文件并没有什么不同。<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:descendantFocusability="blocksDescendants"> <TextView android:id="@+id/large_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/test" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/small_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/test2" /> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout>
二、覆写BaseAdapter类
Adapter的作用就是将数据集合中的每个条目取出,将条目内的每个数据项放入到对应的控件中。最主要的方法是getView,在显示ListView的时候,每取出列表一个列表项数据,就会调用一次getView方法,并返回要显示的view。class MyAdapter extends BaseAdapter { private LayoutInflater inflater; private List<Map<String,Object>> data; private TextView largeText; private TextView smallText; private ImageView imageView; private List<View> holder; public MyAdapter(Context context,List<Map<String,Object>> data){ this.inflater = LayoutInflater.from(context); this.data = data; } public int getCount() { return data.size(); } public Object getItem(int arg0) { return data.get(arg0); } @Override public long getItemId(int arg0) { return arg0; } @Override public View getView(int p, View v, ViewGroup parent) { if(v == null){ v = inflater.inflate(R.layout.custom_list_view, null); largeText= (TextView)v.findViewById(R.id.large_text); smallText= (TextView)v.findViewById(R.id.small_text); imageView= (ImageView)v.findViewById(R.id.image); holder = new ArrayList<View>(); holder.add(largeText); holder.add(smallText); holder.add(imageView); v.setTag(holder); }else{ holder = (ArrayList)v.getTag(); } ((TextView)holder.get(0)).setText((String)data.get(p).get("large_text")); ((TextView)holder.get(1)).setText((String)data.get(p).get("small_text"));((ImageView)holder.get(2)).setImageDrawable(getResources().getDrawable((int)data.get(p).get("drawable_id"))); return v; } }
三、在Activity中为ListView设置Adapter,并将数据传入Adapter。
通常数据来自数据库查询结果,这里只是简单的将构造的数据传给Adapter。List<Map<String,Object>> data = new ArrayList<Map<String,Object>>(); Map<String,Object> d1 = new HashMap<String,Object>(); d1.put("large_text", "Large Text1"); d1.put("small_text", "Small Text1"); d1.put("drawable_id", R.id.testImage1); d2.put("large_text", "Large Tex2t"); d2.put("small_text", "Small Text2"); d2.put("drawable_id", R.id.testImage2); d3.put("large_text", "Large Text3"); d3.put("small_text", "Small Text3"); d3.put("drawable_id", R.id.testImage3); d4.put("large_text", "Large Text4"); d4.put("small_text", "Small Text4"); d4.put("drawable_id", R.id.testImage4); data.add(d1); data.add(d2); data.add(d3); data.add(d4); ListView list = (ListView)findViewById(R.id.customList); list.setAdapter(new MyAdapter(this,data));
这样,就可以通过覆写BaseAdapter创建自定义的Adapter并显示自定义的ListView了。
自定义ListView的item无法响应OnItemClickListener的OnItemClick方法问题的解决方案
查看第一步的布局文件,可以看到最外层的RelativeLayout中有一行android:descendantFocusability=”blocksDescendants”,这样就可以响应item的click事件了。关于这个方案的解释,来自这里:
在Android软件设计与实现中我们通常都会使用到ListView这个控件,系统有一些预置的Adapter可以使用,例如SimpleAdapter和ArrayAdapter,但是总是会有一些情况我们需要通过自定义ListView来实现一些效果,那么在这个时候,我们通常会碰到自定义ListView无法选中整个ListViewItem的情况,也就是无法响应ListView的onItemClickListener中的onItemClick()方法,究竟是为什么呢?我之前也在网上查过不少的资料,但是没有发现什么有价值的文章,有一些是建议在Adapter的getView方法中对自己需要响应单击事件的控件进行设置。但是最终的效果并不是特别理想,而且我认为这是一种取巧的方式,并不推荐。之后自己查看了一下ViewGroup的源码,发现了以下的一段常量声明:
public static final int FOCUS_BEFORE_DESCENDANTS = 0×20000;
public static final int FOCUS_AFTER_DESCENDANTS = 0×40000;
public static final int FOCUS_BLOCK_DESCENDANTS = 0×60000;
public static final int FOCUS_BEFORE_DESCENDANTS = 0×20000;
public static final int FOCUS_AFTER_DESCENDANTS = 0×40000;
public static final int FOCUS_BLOCK_DESCENDANTS = 0×60000;
我们看到了一行代码定义的变量的意思是:
“当前View将屏蔽他所有子控件的Focus状态,即便这些子控件是可以Focus的”,
其实这段话的意思就是这个变量代表着当前的View将不顾其子控件是否可以Focus自身接管了所有的Focus,通常默认能获得focus的控件有Button,Checkable继承来的所有控件,这就意味着如果你的自定义ListViewItem中有Button或者Checkable的子类控件的话,那么默认focus是交给了子控件,而ListView的Item能被选中的基础是它能获取Focus,也就是说我们可以通过将ListView中Item中包含的所有控件的focusable属性设置为false,这样的话ListView的Item自动获得了Focus的权限,也就可以被选中了,也就会响应onItemClickListener中的onItemClick()方法,然而将ListView的Item
Layout的子控件focusable属性设置为false有点繁琐,我们可以通过对Item Layout的根控件设置其android:descendantFocusability=”blocksDescendant”即可,这样Item Layout就屏蔽了所有子控件获取Focus的权限,不需要针对Item Layout中的每一个控件重新设置focusable属性了,如此就可以顺利的响应onItemClickListener中的onItenClick()方法了。
相关文章推荐
- Android自定义listview布局实现上拉加载下拉刷新功能
- [转]Android自定义Adapter的ListView的思路及代码
- Android中ListView同过自定义布局并使用SimpleAdapter的方式实现数据的绑定
- Android自定义一个时间轴,通过ListView来实现时间轴的效果
- android自定义listview实现圆角
- Android中自定义ListView实现上拉加载更多和下拉刷新
- android 自定义ListView实现下拉刷新、分页加载、点击事件——自定义控件学习(七)
- Android之自定义ListView滚动条样式
- Android自定义组件ListView
- android 自定义adapter extends BaseAdapter,做有自己布局的listView
- Android——自定义Adapter的ListView
- Android之自定义Adapter的ListView
- Android开发:自定义GridView/ListView数据源
- Android中自定义仿IOS回弹效果的ListView
- android自定义ListView高度设置无效
- 美化你的android程序:自定义ListView背景
- [Android UI] listview 自定义style
- 【转】Android之自定义Adapter的ListView
- android listView 自定义布局结合CheckedTextView实现多选
- android自定义tabwidget,popupwindow,spinner,dialog,listview