Android ListView 可拖拽Item 1 - 创建浮动Item
2013-04-22 21:18
375 查看
当前是ListView 可拖拽Item第一步,显示浮动视图。看看下面的图片演示浮动视图,但是也可以看到浮动视图之外的Item不会自动移动,并且浮动视图还可以左右移动等问题存在,所以这是第一部分,也是这个效果的起步。
一、有图有真相
二、分析
1. 效果布局,因为是控制ListView子视图Item,而要控制的Item的父类ListView并没有提供可直接控制Item的方法和其他方式,所以这里选择自定义ListView来进行扩展。
2. 首先是浮动视图的实现,当前是使用在ListView中隐藏选中的Item,并绘制出选中Item视图。具体实现分析请参考《Android 浮动视图效果 第三种实现方式》
这种浮动视图的实现我也是第一次见,之前都没想象过还能这样实现浮动视图,把视图转换为图片,然后把图片绘制出来实现浮动效果。
3. ListView 可拖拽Item中会使用很多手势,这些手势可以通过自己监听判断来得到,但是也可以使用系统提供的手势辅助类实现。具体实现可以参考
《Android 手势识别,使用SimpleOnGestureListener,OnGestureListener,OnDoubleTapListener》
三、伪代码
1. 首先自定义ListView\
2. 自定义ListView构造参数中添加了Touch Event 事件监听,用于把手势相关的代码摘出来,不用都放到自定义ListView代码也更清晰,下面再来看看自定义手势类中都做了些什么? 先来看看自定义手势:
3. 自定义手势中onDown事件中触发ListView Item拖动,用于获取当前拖动Item位置,手指在Item中离当前Item左侧与顶部的偏移量。
4. 创建浮动视图
上面的3中最后会调用ListView.startDrag,并传递手势类中进行判断收集到了选中的位置,手指在Item中离当前Item左侧与顶部的偏移量。下面来看看ListView.startDrag的具体实现
先由ListView获取到选中Item的信息,然后传递给自定义ListView,其中把当前Item隐藏掉,隐藏之前把视图转为图片,并设置到ImageView,创建浮动视图重新绘制。
浮动视图已经创建完成了,如何显示呢? 上面最后执行了requestLayout(), 这个方法会再次请求重新布局,会执行onMeasure,onLayout,onDraw等方法。
5. 显示浮动视图
6. 简单的拖动,最初模型待完善所以只是能拖动,其他任何效果都没有添加比如Item不能左右移动。
四、源码下载
点击下载源码
转载请注明出处:http://blog.csdn.net/love_world_/article/details/8836449
一、有图有真相
二、分析
1. 效果布局,因为是控制ListView子视图Item,而要控制的Item的父类ListView并没有提供可直接控制Item的方法和其他方式,所以这里选择自定义ListView来进行扩展。
2. 首先是浮动视图的实现,当前是使用在ListView中隐藏选中的Item,并绘制出选中Item视图。具体实现分析请参考《Android 浮动视图效果 第三种实现方式》
这种浮动视图的实现我也是第一次见,之前都没想象过还能这样实现浮动视图,把视图转换为图片,然后把图片绘制出来实现浮动效果。
3. ListView 可拖拽Item中会使用很多手势,这些手势可以通过自己监听判断来得到,但是也可以使用系统提供的手势辅助类实现。具体实现可以参考
《Android 手势识别,使用SimpleOnGestureListener,OnGestureListener,OnDoubleTapListener》
三、伪代码
1. 首先自定义ListView\
public class DragSortListView extends ListView { public DragSortListView(Context context) { super(context); initCustomListView(); } public DragSortListView(Context context, AttributeSet attrs) { super(context, attrs); initCustomListView(); } public DragSortListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initCustomListView(); } private void initCustomListView() { // setOnTouchListener 与 当前视图onTouchEvent回到不冲突 // 前者是在dispatchTouchEvent中调用,后者是在其后执行 DragSortController controller = new DragSortController(this); setOnTouchListener(controller); } }
2. 自定义ListView构造参数中添加了Touch Event 事件监听,用于把手势相关的代码摘出来,不用都放到自定义ListView代码也更清晰,下面再来看看自定义手势类中都做了些什么? 先来看看自定义手势:
public class DragSortController extends SimpleOnGestureListener implements OnTouchListener { private GestureDetector mDetector; private DragSortListView mListView; public DragSortController(DragSortListView listView) { mListView = listView; mDetector = new GestureDetector(this); } @Override public boolean onTouch(View v, MotionEvent event) { mDetector.onTouchEvent(event); // 永远返回false,当前只是辅助手势处理 // 不消耗Touch Event return false; } }
3. 自定义手势中onDown事件中触发ListView Item拖动,用于获取当前拖动Item位置,手指在Item中离当前Item左侧与顶部的偏移量。
@Override public boolean onDown(MotionEvent event) { mHitPos = startDragPosition(event); if (mHitPos != MISS) { int deltaX = (int) event.getX() - mItemX; int deltaY = (int) event.getY() - mItemY; startDragPosition(mHitPos, deltaX, deltaY); } return true; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } @Override public boolean onSingleTapUp(MotionEvent e) { return true; } @Override public void onShowPress(MotionEvent e) { } // =========================================================== // Private Methods // =========================================================== /** * 在ACTION_DOWN获取开始拖动时的Item位置 * * @param event ACTION_DOWN MotionEvent对象 * @return */ public int startDragPosition(MotionEvent event) { return dragHandleHitPosition(event); } /** * 检测Item是否可拖拽,如果可以返回拖动的Item位置 * * @param event * @return 拖动的Item位置 */ private int dragHandleHitPosition(MotionEvent event) { return viewIdHitPosition(event, 0); } /** * 获取拖拽Item位置 * * @param event * @param id 可移动区域视图ID,如果整个Item拖动,传入0 * @return 拖动的Item位置 */ public int viewIdHitPosition(MotionEvent event, int id) { final int x = (int) event.getX(); final int y = (int) event.getY(); // 当前选中项 int touchPos = mListView.pointToPosition(x, y); // 判断是否在ListView上 final int numHeaders = mListView.getHeaderViewsCount(); final int numFooters = mListView.getFooterViewsCount(); final int count = mListView.getCount(); // 仅对Header与Footer之间的Item进行拖动处理 if (touchPos != AdapterView.INVALID_POSITION && touchPos >= numHeaders && touchPos < (count - numFooters)) { final View item = mListView.getChildAt(touchPos - mListView.getFirstVisiblePosition()); final int rawX = (int) event.getRawX(); final int rawY = (int) event.getRawY(); // 获取拖动区域视图,如果没有则Item真个视图为可拖动区域 View dragBox = id == 0 ? item: item.findViewById(id); if (dragBox != null) { // 选中的是否在拖拽图形内 // 获取拖动区域视图,以当期屏幕左上角为原点的相对坐标 dragBox.getLocationOnScreen(mTempLoc); if (rawX > mTempLoc[0] && rawY > mTempLoc[1] && rawX < mTempLoc[0] + dragBox.getWidth() && rawY < mTempLoc[1] + dragBox.getHeight()) { // 获取与当前Item左上角的距离 mItemX = item.getLeft(); mItemY = item.getTop(); return touchPos; } } } // 没找到拖动视图 return MISS; } /** * 启动拖动Item * * @param position 拖动Item为孩子 * @param deltaX 手指拖动Item距自身左侧偏移量 * @param deltaY 手指拖动Item距自身顶部偏移量 * * @return 是否可以拖动 */ private boolean startDragPosition(int position, int deltaX, int deltaY) { mDraging = mListView.startDrag(position - mListView.getHeaderViewsCount(), deltaX, deltaY); return mDraging; }
4. 创建浮动视图
上面的3中最后会调用ListView.startDrag,并传递手势类中进行判断收集到了选中的位置,手指在Item中离当前Item左侧与顶部的偏移量。下面来看看ListView.startDrag的具体实现
/** * 开始拖动指定位置Item * * @param position 拖动Item位置 * @param deltaX 手指拖动Item距自身左侧偏移量 * @param deltaY 手指拖动Item距自身顶部偏移量 * @return 是否可以拖动 */ public boolean startDrag(int position, int deltaX, int deltaY) { if (position == MISS) { return false; } // 创建浮动视图 ImageView floatView = onCreateFloatView(position); if (floatView == null) { return false; } else { return startDrag(position, floatView, deltaX, deltaY); } } /** * 创建浮动视图 * * @param position * @return */ public ImageView onCreateFloatView(int position) { // 获取当前拖动Item View srcItem = getChildAt(position + getHeaderViewsCount() - getFirstVisiblePosition()); if (srcItem == null) { return null; } // 取消选中状态 srcItem.setPressed(false); // 转换为图片 srcItem.setDrawingCacheEnabled(true); mSelectedItemBitmap = Bitmap.createBitmap( srcItem.getDrawingCache() ); srcItem.setDrawingCacheEnabled(false); // 创建浮动视图 if (mFloatView == null) { mFloatView = new ImageView(getContext()); } mFloatView.setPadding(0, 0, 0, 0); mFloatView.setImageBitmap(mSelectedItemBitmap); mFloatView.setLayoutParams(new LayoutParams(srcItem.getWidth(), srcItem.getHeight())); return mFloatView; } /** * 处理开始拖动Item * * @param position * @param floatView 获取的悬浮视图 * @param deltaX * @param deltaY * @return */ public boolean startDrag(int position, ImageView floatView, int deltaX, int deltaY) { if (floatView == null) { return false; } // 记录 mFloatView = floatView; measureFloatView(); // 记录偏移量,供移动时使用 mDragDeltaX = deltaX; mDragDeltaY = deltaY; // 更新当前浮动视图位置 mFloatLoc.x = mX - mDragDeltaX; mFloatLoc.y = mY - mDragDeltaY; // 当前触摸的Item视图 View srcItem = getChildAt(position - getFirstVisiblePosition()); if (srcItem != null) { // 隐藏拖动Item srcItem.setVisibility(View.INVISIBLE); } // 重新请求布局,使以上设置生效,最终会触发dispatchDraw requestLayout(); return true; }
先由ListView获取到选中Item的信息,然后传递给自定义ListView,其中把当前Item隐藏掉,隐藏之前把视图转为图片,并设置到ImageView,创建浮动视图重新绘制。
浮动视图已经创建完成了,如何显示呢? 上面最后执行了requestLayout(), 这个方法会再次请求重新布局,会执行onMeasure,onLayout,onDraw等方法。
5. 显示浮动视图
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mFloatView != null) { if (mFloatView.isLayoutRequested()) { measureFloatView(); } mFloatViewOnMeasured = true; } mWidthMeasureSpec = widthMeasureSpec; } @Override protected void layoutChildren() { super.layoutChildren(); if (mFloatView != null) { if (mFloatView.isLayoutRequested() && !mFloatViewOnMeasured) { measureFloatView(); } // 测量宽高后,指定位置 mFloatView.layout(0, 0, mFloatView.getMeasuredWidth(), mFloatView.getMeasuredHeight()); mFloatViewOnMeasured = false; } } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if (mFloatView != null) { int width = mFloatView.getWidth(); int height = mFloatView.getHeight(); canvas.save(); // 绘制到当前ListView左上角为坐标原点的相应位置 canvas.translate(mFloatLoc.x, mFloatLoc.y); canvas.clipRect(0, 0, width, height); canvas.saveLayerAlpha(0, 0, width, height, getAlpha(), canvas.ALL_SAVE_FLAG); // 浮动视图绘制到回调提供的当前Canvas上 mFloatView.draw(canvas); canvas.restore(); } }关于浮动视图的显示与浮动视图的多种实现方式可以查看《Android 浮动视图效果 第三种实现方式》
6. 简单的拖动,最初模型待完善所以只是能拖动,其他任何效果都没有添加比如Item不能左右移动。
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { // * 保存坐标信息 saveTouchCoords(ev); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { saveTouchCoords(ev); switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: continueDrag((int)ev.getX(), (int)ev.getY()); break; } return super.onTouchEvent(ev); } /** * 记录当前触摸时间参数 * * @param event */ private void saveTouchCoords(MotionEvent event) { mX = (int) event.getX(); mY = (int) event.getY(); } /** * 控制浮动视图随手指拖动 * * @param x * @param y */ private void continueDrag(int x, int y) { mFloatLoc.x = x - mDragDeltaX; mFloatLoc.y = y - mDragDeltaY; }
四、源码下载
点击下载源码
转载请注明出处:http://blog.csdn.net/love_world_/article/details/8836449
相关文章推荐
- Android超炫特效:ListView item拖拽效果(上)
- android listview拖拽,拖动item 改变位置
- Android动态创建ListView视图,动态增加和删除Item.
- android listview拖拽,拖动item 改变位置
- Android自定义控件:左滑删除itemRecyclerView,ListView,GrdiView通配,教你如何最快最轻松定制,而不是复制粘贴!
- Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换
- Android ListView的不同样式,getItemViewType,getViewTypeCount
- android捕获ListView中每个item点击事件{转}
- 无废话Android之listview入门,自定义的数据适配器、采用layoutInflater打气筒创建一个view对象、常用数据适配器ArrayAdapter、SimpleAdapter、使用ContentProvider(内容提供者)共享数据、短信的备份、插入一条记录到系统短信应用(3)
- android收藏之一:Android美工坊->listview更改选中时item背景色
- android 关于如何设置ListView中item高度问题的解决方案
- android屏蔽listview 的item点击事件
- android ListView的Item中有CheckBox,导致OnItemClick不响应的解决办法
- Android RecyclerView ListView 获取不到Item点击事件
- android listview实现点击某个item后使其显示在屏幕顶端
- android给listview的item设定高度
- android开发之 listview中的item去掉分割线 隐藏分割线
- Android使用RecycleView实现拖拽交换item位置
- GridView长按拖拽Item效果(android)
- Android编程心得-ListView的Item高亮显示的办法