4.实现自定义的ListView
如果用系统自己的ListView,将不会将滑动事件发送到SlideView,故需要实现自己的ListView,然而我们并不 是直接继承ListView,而是ListViewCompat,该类也继承自ListView,不过有些扩展的方法可以使用,更加全能。
代码如下:
public class MyListView extends ListViewCompat { private SlideView chooseSlideView; public MyListView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { switch(event.getAction()){ case MotionEvent.ACTION_DOWN:{ int x=(int)event.getX(); int y=(int)event.getY(); int position=pointToPosition(x,y); if(position!= ListView.INVALID_POSITION){ MessageItem item=(MessageItem)getItemAtPosition(position); this.chooseSlideView=item.mSlideView; } break; } default: break; } //将操作提交给SlideView处理 if(this.chooseSlideView!=null){ this.chooseSlideView.onRequiredToEvent(event); } return super.onTouchEvent(event); } }
当接收到触摸事件后,根据X,Y坐标,获得item的ID,提供给我们的方法为pointToPosition(x,y),一看就知道该方法的:point点到Position。每个ListView都有一个无效的位置,比如第一行的前一行,最后一行的后一行,需要作一个判断:position!= ListView.INVALID_POSITION。如果是有效的位置,就获得该item的信息,并设置chooseSlideView。然后将触摸事件提交给item的包装View处理(也就是SlideView)。
MessageItem代码如下:
public class MessageItem { public int iconRes; public String title; public String msg; public String time; public SlideView mSlideView; }
5.最后实现Activity代码
启动的Activity需要实现两个接口,一个是SlideView.OnSlideViewOnListener,一个是View.OnClickListener点击事件。
对于ListView需要一个适配器adapter,代码如下:
private class SlideAdapter extends BaseAdapter { private LayoutInflater mInflater; SlideAdapter() { super(); this.mInflater = getLayoutInflater(); } @Override public int getCount() { return mMessageItem.size(); } @Override public Object getItem(int position) { return mMessageItem.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; SlideView slideView = (SlideView) convertView; if (slideView == null) { View itemView = this.mInflater.inflate(R.layout.list_item, null); slideView = new SlideView(MainActivity.this); slideView.setContentView(itemView); holder = new ViewHolder(slideView); slideView.setmOnSlideViewOnListener(MainActivity.this); slideView.setTag(holder); } else { holder = (ViewHolder) slideView.getTag(); } MessageItem item = mMessageItem.get(position); item.mSlideView = slideView; item.mSlideView.shrink(); holder.icon.setImageResource(item.iconRes); holder.title.setText(item.title); holder.msg.setText(item.msg); holder.time.setText(item.time); holder.delete.setOnClickListener(MainActivity.this); holder.top.setOnClickListener(MainActivity.this); return slideView; } }
定义LayoutInflater都是用来加载布局文件的,不管是Activity里的setContentView()还是刚才的SlideView的Viiew.inflate其内部实现都是这样做的。
其中list_item代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/icon" android:layout_width="50dp" android:layout_height="50dp"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@+id/icon" android:layout_toRightOf="@+id/icon" android:orientation="vertical"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/msg" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <TextView android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true"/> </RelativeLayout>
这里定义了一个ViewHolder,为的就是防止二次加载。其代码如下:
public class ViewHolder { public ImageView icon; public TextView title; public TextView msg; public TextView time; public TextView delete; public TextView top; ViewHolder(View view) { this.icon = (ImageView) view.findViewById(R.id.icon); this.title = (TextView) view.findViewById(R.id.title); this.msg = (TextView) view.findViewById(R.id.msg); this.time = (TextView) view.findViewById(R.id.time); this.delete = (TextView) view.findViewById(R.id.delete); this.top = (TextView) view.findViewById(R.id.top); } }
每次获得MessageItem都调用了item.mSlideView.shrink();将隐藏控件隐藏。其他的代码不用多作解释,ListView基本都是这么用的。
下面我们来看一个接口SlideView.OnSlideViewOnListener实现,代码如下:
@Override public void Slide(View view, int status) { if (this.mLastSlideViewWithStatusOn != null && this.mLastSlideViewWithStatusOn != view) { this.mLastSlideViewWithStatusOn.shrink(); } if (status == SlideView.OnSlideViewOnListener.SLIDE_STATUS_ON) { this.mLastSlideViewWithStatusOn = (SlideView) view; } }
我们定义了一个记录打开隐藏控件的SlideView:
private SlideView mLastSlideViewWithStatusOn;
当滑动某个控件的时候,就将上一个打开隐藏控件的item关闭。如果这个控件滑动开了,也就记录这个控件status ==SlideView.OnSlideViewOnListener.SLIDE_STATUS_ON:
this.mLastSlideViewWithStatusOn = (SlideView) view;
在来看看实现点击事件的代码:
@Override public void onClick(View v) { switch (v.getId()) { case R.id.delete: { int position = this.mListView.getPositionForView(v); if (position != ListView.INVALID_POSITION) { this.mMessageItem.remove(position); this.adapter.notifyDataSetChanged(); } break; } case R.id.top: { int position = this.mListView.getPositionForView(v); if (position != ListView.INVALID_POSITION) { MessageItem item = this.mMessageItem.get(position); this.mMessageItem.remove(position); this.mMessageItem.add(0, item); this.adapter.notifyDataSetChanged(); } break; } default: break; } }
怎么删除item,因为这个代码没有任何解释,有必要说明一下。
为了获取操作屏幕的时值,点击的是那个item的删除按钮,就必须获取他的位置position,我们使用getPositionForView(),position for view,也就是位置根据View获取。接着也是判断获取的position是不是有效的。然后将根据位置删除这个item。mMessageItem:
private List<MessageItem> mMessageItem = new ArrayList<MessageItem>();
是信息的集合。
然后更新ListView:
this.adapter.notifyDataSetChanged();
而置顶思考的思路如下:
获取该item的位置,如上面代码所示,然后获得具体的MessageItem,将集合该位置的MessageItem删除,将具体的MessageItem插入到第一个位置。然后更新ListView如上所示。
置顶后的效果图如下所示:
下面为初始化Activity:
public void initView() { this.mListView = (ListViewCompat) findViewById(R.id.myList); for (int i = 0; i < 20; i++) { MessageItem item = new MessageItem(); if (i < 10) { item.iconRes =imgRes[i]; item.title = name[i]; item.msg = author[i]; item.time = time[i]; } else { item.iconRes = imgRes[19-i]; item.title = name[19 - i]; item.msg = author[19 - i]; item.time = time[19 - i]; } this.mMessageItem.add(item); } this.adapter = new SlideAdapter(); this.mListView.setAdapter(this.adapter); this.mListView.setOnItemClickListener(this); }
成员变更如下:
private String[] name = {"吾国之教育病理", "谷物大脑", "中国历代经济变革得失", "了凡四训", "耶路撒冷三千年", "如果这是宋史", "中国近代史", "罗马人的故事", "光荣与梦想", "大秦帝国"}; private String[] author = {"郑也夫", "戴维·珀尔马特", "吴晓波", "袁了凡", "西蒙·蒙蒂菲奥里", "高天流云 ", "王奇生", "盐野七生 ", "威廉·曼彻斯特 ", "孙皓晖"}; private String[] time = {"2013-10-1 ", " 2015-5-20", "2013-8-1 ", "2007", "2013年3月", "2008", "2013年7月22日", "2011 年12月", "2006年", "2012年5月"}; private int[] imgRes = {R.drawable.book1, R.drawable.book2, R.drawable.book3, R.drawable.book4, R.drawable.book5, R.drawable.book6, R.drawable.book7, R.drawable.book8, R.drawable.book9, R.drawable.book10}; private ListViewCompat mListView; private List<MessageItem> mMessageItem = new ArrayList<MessageItem>(); private SlideAdapter adapter; // 上次处于打开状态的SlideView private SlideView mLastSlideViewWithStatusOn;
activity_main.xml代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.liyuanjing.slidelistview.MyListView android:id="@+id/myList" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
本文章代码下载地址如下: