Android 自己动手写ListView学习其原理 3 ItemClick,ItemLongClick,View复用
来源:互联网 发布:未知usb设备 端口重置 编辑:程序博客网 时间:2024/05/21 15:01
《Android 自己动手写ListView学习其原理 1 显示第一屏Item》
《Android 自己动手写ListView学习其原理 2 上下滚动》
本篇主要是添加ItemClick,ItemLongClick,View复用,都比较简单前两个点击事件是在onTouchEvent里面处理,View复用与onLayout先关的时候使用,代码里面注释比较完整,直接上代码把。
一、有图有真相
二、ItemClick 与 ItemLongClick
1. 启动LongClick子线程,在onTouchEvent Down事件时执行
/** * 开启异步线程,条件允许时调用LongClickListener */private void startLongPressCheck() {// 创建子线程if (mLongPressRunnable == null) {mLongPressRunnable = new Runnable() {@Overridepublic void run() {if (mTouchMode == TOUCH_MODE_DOWN) {final int index = getContainingChildIndex(mTouchStartX, mTouchStartY);if (index != INVALID_INDEX) {longClickChild(index);}}}};}// ViewConfiguration.getLongPressTimeout() 获取系统配置的长按的时间间隔// 如果点击已经超过长按要求时间,才开始执行此线程postDelayed(mLongPressRunnable, ViewConfiguration.getLongPressTimeout());}/** * 调用ItemLongClickListener提供点击位置等信息 * * @param index Item索引值 */private void longClickChild(final int index) {final View itemView = getChildAt(index);final int position = mFirstItemPosition + index;final long id = mAdapter.getItemId(position);// 从父类获取绑定的OnItemLongClickListenerOnItemLongClickListener listener = getOnItemLongClickListener();if (listener != null) {listener.onItemLongClick(this, itemView, position, id);}}
2. itemClick,在onTouchEvent UP事件中触发(只有手指抬起时才会触发)
case MotionEvent.ACTION_UP:// 如果当前触摸没有触发滚动,状态依然是DOWN// 说明是点击某一个Itemif (mTouchMode == TOUCH_MODE_DOWN) {clickChildAt((int)event.getX(), y);}
具体执行
/** * 调用ItemClickListener提供当前点击位置 * * @param x 触摸点X轴值 * @param y 触摸点Y轴值 */private void clickChildAt(int x, int y) {// 触摸点在当前显示所有Item中哪一个final int itemIndex = getContainingChildIndex(x, y);if (itemIndex != INVALID_INDEX) {final View itemView = getChildAt(itemIndex);// 当前Item在ListView所有Item中的位置final int position = mFirstItemPosition + itemIndex;final long id = mAdapter.getItemId(position);// 调用父类方法,会触发ListView ItemClickListenerperformItemClick(itemView, position, id);}}
3. 如何使用呢? 直接在Activity中添加相关内部类即可,和ListView自身的itemclick和longclick相同
// item Click listView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {String itemName = (String) customAdapter.getItem(position);Toast.makeText(getBaseContext(), "点击 " + itemName, Toast.LENGTH_SHORT).show();}}); listView.setOnItemLongClickListener(new OnItemLongClickListener() {@Overridepublic boolean onItemLongClick(AdapterView<?> parent, View view,int position, long id) {String itemName = (String) customAdapter.getItem(position);Toast.makeText(getBaseContext(), "长按 " + itemName, Toast.LENGTH_SHORT).show();return true;}});
三、视图复用
如何向知道ListView到底如何复用视图的,可以看看之前的博文《Android ListView使用Holder优化原理》,下面实现的是一个简化版,其复用原理都是一样的,把移除屏幕的视图都保存起来,如果有需要新视图对象可以从保存视图中取。
1. 新来看数据结构
// View复用当前仅支持一种类型Item视图复用// 想更多了解ListView视图如何复用可以看AbsListView内部类RecycleBinprivate final LinkedList<View> mCachedItemViews = new LinkedList<View>();
/** * 删除当前已经移除可视范围的Item View * * @param offset 可视区域偏移量 */private void removeNonVisibleViews(final int offset) {int childCount = getChildCount();/** ListView向上滚动,删除顶部移除可视区域的所有视图 **/// 不在ListView底部,子视图大于1if (mLastItemPosition != mAdapter.getCount() -1 && childCount > 1) {View firstChild = getChildAt(0);// 通过第二条件判断当前最上面的视图是否被移除可是区域while (firstChild != null && firstChild.getBottom() + offset < 0) {// 既然顶部第一个视图已经移除可视区域从当前ViewGroup中删除掉removeViewInLayout(firstChild);// 用于下次判断,是否当前顶部还有需要移除的视图childCount--;// View对象回收,目的是为了复用mCachedItemViews.addLast(firstChild);// 既然最上面的视图被干掉了,当前ListView第一个显示视图也需要+1mFirstItemPosition++;// 同上更新mListTopOffset += firstChild.getMeasuredHeight();// 为下一次while遍历获取参数if (childCount > 1) {// 当前已经删除第一个,再接着去除删除后剩余的第一个firstChild = getChildAt(0);} else {// 没啦firstChild = null;}}}/** ListView向下滚动,删除底部移除可视区域的所有视图 **/// 与上面操作一样,只是方向相反一个顶部操作一个底部操作if (mFirstItemPosition != 0 && childCount > 1) {View lastChild = getChildAt(childCount - 1);while (lastChild != null && lastChild.getTop() + offset > getHeight()) {removeViewInLayout(lastChild);childCount--;mCachedItemViews.addLast(lastChild);mLastItemPosition--;if (childCount > 1) {lastChild = getChildAt(childCount - 1);} else { lastChild = null;}}}}/** * 获取一个可以复用的Item View * * @return view 可以复用的视图或者null */private View getCachedView() {if (mCachedItemViews.size() != 0) {return mCachedItemViews.removeFirst();}return null;}
3. 怎么用呢?removeNonVisibleViews在onLayout中使用
@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);// 异常处理if (mAdapter == null) {return;}// 当前ListView没有任何子视图(Item),所以依次在从上向下填充子视图if (getChildCount() == 0) {mLastItemPosition = -1;// add and measurefillListDown(mListTop, 0);} else {final int offset = mListTop + mListTopOffset - getChildAt(0).getTop();// 移除可视区域的都干掉removeNonVisibleViews(offset);fillList(offset);}// layout,添加测量完后,获取视图摆放位置positioinItems();// draw, 上面子视图都添加完了,重绘布局把子视图绘制出来吧invalidate();}
4. getCachedView在fillUp与fillDown中使用,只贴出fillDown,fillUp使用方式相同
/** * 向当前最后一个子视图下面添加,填充到当前ListView底部无再可填充区域为止 * * @param bottomEdge 当前最后一个子视图底部边界值 * @param offset 显示区域偏移量 */private void fillListDown(int bottomEdge, int offset) {while (bottomEdge + offset < getHeight() && mLastItemPosition < mAdapter.getCount() - 1) {// 现在添加的视图时当前子视图后面,所以位置+1mLastItemPosition++;// 数据和视图通过Adapter适配,此处从Adapter获取视图。// 第二个参数传入复用的View对象,先出入null,之后再添加View对象复用机制View newBottomChild = mAdapter.getView(mLastItemPosition, getCachedView(), this);// **具体添加视图处理addAndMeasureChild(newBottomChild, LAYOUT_MODE_BELOW);// 添加一个子视图(Item),随之底部边界也发生改变bottomEdge += newBottomChild.getMeasuredHeight();}}
四、源码下载
参考资料:
Making your own 3D list – Part 1
转载请注明出处:http://blog.csdn.net/love_world_/article/details/8744423
- Android 自己动手写ListView学习其原理 3 ItemClick,ItemLongClick,View复用
- Android 自己动手写ListView学习其原理 2 上下滚动
- Android 自己动手写ListView学习其原理 1 显示第一屏Item
- Android ListView无法触发ItemClick事件
- Android ListView无法触发ItemClick事件
- Android ListView无法触发ItemClick事件
- Android ListView无法触发ItemClick事件
- Android-自己动手写ButterKnife与原理解析
- Android ListView中有Button,ItemClick事件失效
- Android ListView中加入Button导致ItemClick事件失效
- Android ListView ItemClick和Button冲突的解决
- 解决ListView里TextView设置LinkMovementMethod后导致其ItemClick失效的问题
- 解决ListView里TextView设置LinkMovementMethod后导致其ItemClick失效
- Android View与GroupView原理以及其子类描述
- Android View与GroupView原理以及其子类描述
- Android View与GroupView原理以及其子类描述
- Android View与GroupView原理以及其子类描述
- Android View与GroupView原理以及其子类描述
- 解决linux下/etc/rc.local开机器不执行的原因。
- c++标准库——set和multiset容器
- c++标准库——STL容器的通用能力和操作
- 学习笔记——简单的正则表达式测试器
- Tomcat热部署方法(3种)
- Android 自己动手写ListView学习其原理 3 ItemClick,ItemLongClick,View复用
- ThinkPHP中的Session用法
- OpenGL环境搭建(Windows下VS2010)和版本信息查询
- 学习笔记——JavaScript中的正则表达式
- 经典开源C/C++项目
- java中的IO基础
- java中的IO基础2
- java中的IO基础3
- 总结一下各种IO方式