说说Android桌面(Launcher应用)背后的故事(六)——研究Launcher而实现的附属品(可以拖拽的ListView)
2013-03-26 13:50
621 查看
本来这一篇将写Android中Launcher是如何实现桌面上item的拖拽的,当研究了其机理之后,突然大脑发热,想实现一个可以拖拽的ListView,在理解了Launcher中item的拖拽,再来实现可以拖拽的ListView简直就是小菜一碟了。于是将此篇位于Launcher中拖拽之前,可以起到一个过渡理解的作用。只是,这里还有些不一样的地方就是Launcher上item拖拽后可以放到一个空的位置,而ListView中某个item被拖拽之后是需要交换新位置和原来位置上的item。下面,就不再废话了,直接上代码,具体需要注意的地方请看注释:
[java]
view plaincopyprint?
public class DragListView extends ListView{
private static final String TAG = "DragListView";
private static final int INVALID_POSITION = -1;
private Bitmap mDragBitmap;
private View mDragView;
private UorderDeleteZone zone;
private View footer;
private Object srcContent;
private int startPosition;
private Paint mPaint = new Paint();
private float mLastMotionX;
private float mLastMotionY;
private float mTouchOffsetX;
private float mTouchOffsetY;
private float mBitmapOffsetX;
private float mBitmapOffsetY;
private boolean mDragging = false;
private Rect mDragRect = new Rect(); //当拖动一个item的时候,记录拖动经过的区域
//是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。
private int mScaledTouchSlop;
private float mTopScrollBound;//向上滑动超过这个边界的时候,上面的item向下滚动
private float mBottomScrollBound;//向下滑动超过这个边界的时候,下面的item开始向上滚动
public DragListView(Context context){
this(context, null);
}
public DragListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
/**
* 当某个item被拖拽时,将其颜色改变下,
*/
final int srcColor = context.getResources().getColor(R.color.drag_filter);
mPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
//是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。
mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if(mDragging && mDragBitmap != null){
final int scrollX = getScrollX();
final int scrollY = getScrollY();
float left = scrollX + mLastMotionX-mTouchOffsetX-mBitmapOffsetX;
float top = scrollY + mLastMotionY-mTouchOffsetY-mBitmapOffsetY;
canvas.drawBitmap(mDragBitmap, left, top, mPaint);
}
}
/**
* 在这个方法中判断当前用户按下事件所在的位置
* 如果该位置在右边30dip之内,就进行拖拽
*/
public boolean onInterceptTouchEvent(MotionEvent event){
int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
if(getWidth()-x > 30){
//不是位于拖拽区域,直接返回就OK了
return super.onInterceptTouchEvent(event);
}
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastMotionX = x;
mLastMotionY = y;
break;
default:
break;
}
Log.e(TAG, "touchSlop:"+mScaledTouchSlop);
//计算滚动边界
/**
* 这里当向上拖拽到1/3屏幕高度的时候就滚动,但是这里如果开始拖拽的item就是位于这1/3屏幕内位置的
* 则,取当前小的一个.当然你也就可以设置成1/3的屏幕
*/
mTopScrollBound = Math.min(y-mScaledTouchSlop, getHeight()/3);
mBottomScrollBound = Math.min(y + mScaledTouchSlop, getHeight()*2/3);
// mTopScrollBound = getHeight()/3;
// mBottomScrollBound = getHeight()*2/3;
Log.e(TAG, "bound scroll:"+mTopScrollBound+","+mBottomScrollBound);
//获取当前事件坐标所在的item项,ListView中拖动是上下拖动的,所以,和x坐标关系不大
int position = this.pointToPosition((int)x, (int)y);
if(position == INVALID_POSITION){
return super.onInterceptTouchEvent(event);
}
startPosition = position;
/**
* 这里获取当前被拖拽的item,注意,因为ListView中并不是每个item都是一个View,这个View是重用的
*/
mDragView = getChildAt(position-getFirstVisiblePosition());
srcContent = getItemAtPosition(position);
if(mDragView != null){
mDragBitmap = createViewBitmap(mDragView);
//当item被拖拽后,删除原来位置上的item,其实就是将Adapter中该位置的内容给删掉
/**
* 注意,该ListView用的Adapter是ArrayAdapter,其有remove(Object item)方法
* 但是,经常处理ListView显示数据的应该知道,ArrayList的remove(object)方法实现了,
* 但是我们使用ArrayAdatper的时候,如果我们的数据传递到Adapter用的是数组,那么ArrayAdapter内
* 默认使用Arrays.asList(Object[])方法将数组转换为List对象,这样,当我们调用ArrayList的
* removeItem方法的时候,就会出现java.lang.UnsupportedOperationException异常。这是因为
* Arrays.asList(Object[])转换后的List是Arrays.ArrayList对象,而不是java.utils.ArrayList
* Arrays.ArrayList并没有实现remove方法,所以,执行父类AbstractList默认的remove方法,而
* AbstractList的remove方法就是抛出一个UnsupportedOperationException异常
*/
removeItem(position);
mDragging = true;
}
return true;
}
@SuppressWarnings("unchecked")
private void removeItem(int position){
ArrayAdapter<Object> adapter = (ArrayAdapter<Object>)this.getAdapter();
adapter.remove(adapter.getItem(position));
}
@SuppressWarnings("unchecked")
private void addItem(int position){
ArrayAdapter<Object> adapter = (ArrayAdapter<Object>)this.getAdapter();
adapter.insert((String)srcContent, position);
}
public boolean onTouchEvent(MotionEvent event){
super.onTouchEvent(event);
if(!mDragging){
return false;
}
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
//mLastMotionX = x;
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
final int scrollX = getScrollX();
final int scrollY = getScrollY();
int left = (int)(scrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX);
int top = (int)(scrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY);
final int width = mDragBitmap.getWidth();
final int height = mDragBitmap.getHeight();
mDragRect.set(left-1, top-1, width+left+1, top+height+1);
Log.e(TAG, "每次move的距离:"+(y-mLastMotionY));
//mLastMotionX = x;
mLastMotionY = y;
left = (int)(scrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX);
top = (int)(scrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY);
mDragRect.union(left-1, top-1, width+left+1, top+height+1);
invalidate(mDragRect);
int scrollHeight = 0;
if(y < mTopScrollBound){
/**
* 如果当前move到的y位置为mTopScrollBound之上,则下面获取当前位置的item,
* 并将该item在当前位置的基础上,向下移动15个dip的偏移量,这样,当向上drag的时候
* 后面的item向下在滚动
*
* 向下拖拽的时候同理
*/
scrollHeight = 15;
}else if(y > mBottomScrollBound){
scrollHeight = -15;
}
if(scrollHeight != 0){
//调用Listview方法实现滚动
int position = this.pointToPosition((int)x, (int)y);
if(position != INVALID_POSITION){
/**
* 将当前位置的item向上或者向下移动scrollHeight个单位的距离
*/
setSelectionFromTop(position, getChildAt(position - getFirstVisiblePosition()).getTop()+scrollHeight);
}
}
break;
case MotionEvent.ACTION_UP:
int position = this.pointToPosition((int)x, (int)y);
if(position == INVALID_POSITION){
position = startPosition;
}
float listTop = getChildAt(0).getTop();
//这个是ListView可视区域的最下方,但是不一定数据集中的最后一项的位置
float listBottom = getChildAt(getChildCount()-1).getBottom();
if(y<listTop){
position = 0;
}else if(y > listBottom){
/**
* 因为向下拖动的时候,ListView是向下滑动的
* 这里当item被往下拖到最下面时,将其添加到数据集中最后一个位置
* 这里注意是getCount()而不是getCount()-1。是向最后插入一个
*/
position = getAdapter().getCount();
}
stopDrag(position);
break;
}
return true;
}
private void stopDrag(int newPosition) {
mDragging = false;
if(mDragBitmap != null){
mDragBitmap.recycle();
}
//将拖动的item加入新的位置
addItem(newPosition);
invalidate();
}
/**
* 用当前View的绘制缓冲区创建一个Bitmap
* 同时进行一定的缩放
* @param view
* @return
*/
private Bitmap createViewBitmap(View view) {
final int left = view.getLeft();
final int top = view.getTop();
//当前按住的位置相对于View本身的偏移量
mTouchOffsetX = mLastMotionX - left;
mTouchOffsetY = mLastMotionY - top;
view.clearFocus();
view.setPressed(false);
boolean willNotCache = view.willNotCacheDrawing();
view.setWillNotCacheDrawing(false);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
//使用一个简单的Scale缩放
Matrix matrix = new Matrix();
float scaleFactor = view.getHeight();
scaleFactor = (scaleFactor+40)/scaleFactor;
matrix.setScale(1.0f, scaleFactor);
Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
view.destroyDrawingCache();
view.setWillNotCacheDrawing(willNotCache);
//创建的缩放后的Bitmap和原Bitmap的padding
mBitmapOffsetX = (newBitmap.getWidth()-width)/2;
mBitmapOffsetY = (newBitmap.getHeight()-height)/2;
return newBitmap;
}
}
[java]
view plaincopyprint?
public class DragListView extends ListView{
private static final String TAG = "DragListView";
private static final int INVALID_POSITION = -1;
private Bitmap mDragBitmap;
private View mDragView;
private UorderDeleteZone zone;
private View footer;
private Object srcContent;
private int startPosition;
private Paint mPaint = new Paint();
private float mLastMotionX;
private float mLastMotionY;
private float mTouchOffsetX;
private float mTouchOffsetY;
private float mBitmapOffsetX;
private float mBitmapOffsetY;
private boolean mDragging = false;
private Rect mDragRect = new Rect(); //当拖动一个item的时候,记录拖动经过的区域
//是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。
private int mScaledTouchSlop;
private float mTopScrollBound;//向上滑动超过这个边界的时候,上面的item向下滚动
private float mBottomScrollBound;//向下滑动超过这个边界的时候,下面的item开始向上滚动
public DragListView(Context context){
this(context, null);
}
public DragListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
/**
* 当某个item被拖拽时,将其颜色改变下,
*/
final int srcColor = context.getResources().getColor(R.color.drag_filter);
mPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP));
//是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。
mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if(mDragging && mDragBitmap != null){
final int scrollX = getScrollX();
final int scrollY = getScrollY();
float left = scrollX + mLastMotionX-mTouchOffsetX-mBitmapOffsetX;
float top = scrollY + mLastMotionY-mTouchOffsetY-mBitmapOffsetY;
canvas.drawBitmap(mDragBitmap, left, top, mPaint);
}
}
/**
* 在这个方法中判断当前用户按下事件所在的位置
* 如果该位置在右边30dip之内,就进行拖拽
*/
public boolean onInterceptTouchEvent(MotionEvent event){
int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
if(getWidth()-x > 30){
//不是位于拖拽区域,直接返回就OK了
return super.onInterceptTouchEvent(event);
}
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastMotionX = x;
mLastMotionY = y;
break;
default:
break;
}
Log.e(TAG, "touchSlop:"+mScaledTouchSlop);
//计算滚动边界
/**
* 这里当向上拖拽到1/3屏幕高度的时候就滚动,但是这里如果开始拖拽的item就是位于这1/3屏幕内位置的
* 则,取当前小的一个.当然你也就可以设置成1/3的屏幕
*/
mTopScrollBound = Math.min(y-mScaledTouchSlop, getHeight()/3);
mBottomScrollBound = Math.min(y + mScaledTouchSlop, getHeight()*2/3);
// mTopScrollBound = getHeight()/3;
// mBottomScrollBound = getHeight()*2/3;
Log.e(TAG, "bound scroll:"+mTopScrollBound+","+mBottomScrollBound);
//获取当前事件坐标所在的item项,ListView中拖动是上下拖动的,所以,和x坐标关系不大
int position = this.pointToPosition((int)x, (int)y);
if(position == INVALID_POSITION){
return super.onInterceptTouchEvent(event);
}
startPosition = position;
/**
* 这里获取当前被拖拽的item,注意,因为ListView中并不是每个item都是一个View,这个View是重用的
*/
mDragView = getChildAt(position-getFirstVisiblePosition());
srcContent = getItemAtPosition(position);
if(mDragView != null){
mDragBitmap = createViewBitmap(mDragView);
//当item被拖拽后,删除原来位置上的item,其实就是将Adapter中该位置的内容给删掉
/**
* 注意,该ListView用的Adapter是ArrayAdapter,其有remove(Object item)方法
* 但是,经常处理ListView显示数据的应该知道,ArrayList的remove(object)方法实现了,
* 但是我们使用ArrayAdatper的时候,如果我们的数据传递到Adapter用的是数组,那么ArrayAdapter内
* 默认使用Arrays.asList(Object[])方法将数组转换为List对象,这样,当我们调用ArrayList的
* removeItem方法的时候,就会出现java.lang.UnsupportedOperationException异常。这是因为
* Arrays.asList(Object[])转换后的List是Arrays.ArrayList对象,而不是java.utils.ArrayList
* Arrays.ArrayList并没有实现remove方法,所以,执行父类AbstractList默认的remove方法,而
* AbstractList的remove方法就是抛出一个UnsupportedOperationException异常
*/
removeItem(position);
mDragging = true;
}
return true;
}
@SuppressWarnings("unchecked")
private void removeItem(int position){
ArrayAdapter<Object> adapter = (ArrayAdapter<Object>)this.getAdapter();
adapter.remove(adapter.getItem(position));
}
@SuppressWarnings("unchecked")
private void addItem(int position){
ArrayAdapter<Object> adapter = (ArrayAdapter<Object>)this.getAdapter();
adapter.insert((String)srcContent, position);
}
public boolean onTouchEvent(MotionEvent event){
super.onTouchEvent(event);
if(!mDragging){
return false;
}
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
//mLastMotionX = x;
mLastMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
final int scrollX = getScrollX();
final int scrollY = getScrollY();
int left = (int)(scrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX);
int top = (int)(scrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY);
final int width = mDragBitmap.getWidth();
final int height = mDragBitmap.getHeight();
mDragRect.set(left-1, top-1, width+left+1, top+height+1);
Log.e(TAG, "每次move的距离:"+(y-mLastMotionY));
//mLastMotionX = x;
mLastMotionY = y;
left = (int)(scrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX);
top = (int)(scrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY);
mDragRect.union(left-1, top-1, width+left+1, top+height+1);
invalidate(mDragRect);
int scrollHeight = 0;
if(y < mTopScrollBound){
/**
* 如果当前move到的y位置为mTopScrollBound之上,则下面获取当前位置的item,
* 并将该item在当前位置的基础上,向下移动15个dip的偏移量,这样,当向上drag的时候
* 后面的item向下在滚动
*
* 向下拖拽的时候同理
*/
scrollHeight = 15;
}else if(y > mBottomScrollBound){
scrollHeight = -15;
}
if(scrollHeight != 0){
//调用Listview方法实现滚动
int position = this.pointToPosition((int)x, (int)y);
if(position != INVALID_POSITION){
/**
* 将当前位置的item向上或者向下移动scrollHeight个单位的距离
*/
setSelectionFromTop(position, getChildAt(position - getFirstVisiblePosition()).getTop()+scrollHeight);
}
}
break;
case MotionEvent.ACTION_UP:
int position = this.pointToPosition((int)x, (int)y);
if(position == INVALID_POSITION){
position = startPosition;
}
float listTop = getChildAt(0).getTop();
//这个是ListView可视区域的最下方,但是不一定数据集中的最后一项的位置
float listBottom = getChildAt(getChildCount()-1).getBottom();
if(y<listTop){
position = 0;
}else if(y > listBottom){
/**
* 因为向下拖动的时候,ListView是向下滑动的
* 这里当item被往下拖到最下面时,将其添加到数据集中最后一个位置
* 这里注意是getCount()而不是getCount()-1。是向最后插入一个
*/
position = getAdapter().getCount();
}
stopDrag(position);
break;
}
return true;
}
private void stopDrag(int newPosition) {
mDragging = false;
if(mDragBitmap != null){
mDragBitmap.recycle();
}
//将拖动的item加入新的位置
addItem(newPosition);
invalidate();
}
/**
* 用当前View的绘制缓冲区创建一个Bitmap
* 同时进行一定的缩放
* @param view
* @return
*/
private Bitmap createViewBitmap(View view) {
final int left = view.getLeft();
final int top = view.getTop();
//当前按住的位置相对于View本身的偏移量
mTouchOffsetX = mLastMotionX - left;
mTouchOffsetY = mLastMotionY - top;
view.clearFocus();
view.setPressed(false);
boolean willNotCache = view.willNotCacheDrawing();
view.setWillNotCacheDrawing(false);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
final int width = bitmap.getWidth();
final int height = bitmap.getHeight();
//使用一个简单的Scale缩放
Matrix matrix = new Matrix();
float scaleFactor = view.getHeight();
scaleFactor = (scaleFactor+40)/scaleFactor;
matrix.setScale(1.0f, scaleFactor);
Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
view.destroyDrawingCache();
view.setWillNotCacheDrawing(willNotCache);
//创建的缩放后的Bitmap和原Bitmap的padding
mBitmapOffsetX = (newBitmap.getWidth()-width)/2;
mBitmapOffsetY = (newBitmap.getHeight()-height)/2;
return newBitmap;
}
}
public class DragListView extends ListView{ private static final String TAG = "DragListView"; private static final int INVALID_POSITION = -1; private Bitmap mDragBitmap; private View mDragView; private UorderDeleteZone zone; private View footer; private Object srcContent; private int startPosition; private Paint mPaint = new Paint(); private float mLastMotionX; private float mLastMotionY; private float mTouchOffsetX; private float mTouchOffsetY; private float mBitmapOffsetX; private float mBitmapOffsetY; private boolean mDragging = false; private Rect mDragRect = new Rect(); //当拖动一个item的时候,记录拖动经过的区域 //是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。 private int mScaledTouchSlop; private float mTopScrollBound;//向上滑动超过这个边界的时候,上面的item向下滚动 private float mBottomScrollBound;//向下滑动超过这个边界的时候,下面的item开始向上滚动 public DragListView(Context context){ this(context, null); } public DragListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); /** * 当某个item被拖拽时,将其颜色改变下, */ final int srcColor = context.getResources().getColor(R.color.drag_filter); mPaint.setColorFilter(new PorterDuffColorFilter(srcColor, PorterDuff.Mode.SRC_ATOP)); //是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。 mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if(mDragging && mDragBitmap != null){ final int scrollX = getScrollX(); final int scrollY = getScrollY(); float left = scrollX + mLastMotionX-mTouchOffsetX-mBitmapOffsetX; float top = scrollY + mLastMotionY-mTouchOffsetY-mBitmapOffsetY; canvas.drawBitmap(mDragBitmap, left, top, mPaint); } } /** * 在这个方法中判断当前用户按下事件所在的位置 * 如果该位置在右边30dip之内,就进行拖拽 */ public boolean onInterceptTouchEvent(MotionEvent event){ int action = event.getAction(); final float x = event.getX(); final float y = event.getY(); if(getWidth()-x > 30){ //不是位于拖拽区域,直接返回就OK了 return super.onInterceptTouchEvent(event); } switch (action) { case MotionEvent.ACTION_DOWN: mLastMotionX = x; mLastMotionY = y; break; default: break; } Log.e(TAG, "touchSlop:"+mScaledTouchSlop); //计算滚动边界 /** * 这里当向上拖拽到1/3屏幕高度的时候就滚动,但是这里如果开始拖拽的item就是位于这1/3屏幕内位置的 * 则,取当前小的一个.当然你也就可以设置成1/3的屏幕 */ mTopScrollBound = Math.min(y-mScaledTouchSlop, getHeight()/3); mBottomScrollBound = Math.min(y + mScaledTouchSlop, getHeight()*2/3); // mTopScrollBound = getHeight()/3; // mBottomScrollBound = getHeight()*2/3; Log.e(TAG, "bound scroll:"+mTopScrollBound+","+mBottomScrollBound); //获取当前事件坐标所在的item项,ListView中拖动是上下拖动的,所以,和x坐标关系不大 int position = this.pointToPosition((int)x, (int)y); if(position == INVALID_POSITION){ return super.onInterceptTouchEvent(event); } startPosition = position; /** * 这里获取当前被拖拽的item,注意,因为ListView中并不是每个item都是一个View,这个View是重用的 */ mDragView = getChildAt(position-getFirstVisiblePosition()); srcContent = getItemAtPosition(position); if(mDragView != null){ mDragBitmap = createViewBitmap(mDragView); //当item被拖拽后,删除原来位置上的item,其实就是将Adapter中该位置的内容给删掉 /** * 注意,该ListView用的Adapter是ArrayAdapter,其有remove(Object item)方法 * 但是,经常处理ListView显示数据的应该知道,ArrayList的remove(object)方法实现了, * 但是我们使用ArrayAdatper的时候,如果我们的数据传递到Adapter用的是数组,那么ArrayAdapter内 * 默认使用Arrays.asList(Object[])方法将数组转换为List对象,这样,当我们调用ArrayList的 * removeItem方法的时候,就会出现java.lang.UnsupportedOperationException异常。这是因为 * Arrays.asList(Object[])转换后的List是Arrays.ArrayList对象,而不是java.utils.ArrayList * Arrays.ArrayList并没有实现remove方法,所以,执行父类AbstractList默认的remove方法,而 * AbstractList的remove方法就是抛出一个UnsupportedOperationException异常 */ removeItem(position); mDragging = true; } return true; } @SuppressWarnings("unchecked") private void removeItem(int position){ ArrayAdapter<Object> adapter = (ArrayAdapter<Object>)this.getAdapter(); adapter.remove(adapter.getItem(position)); } @SuppressWarnings("unchecked") private void addItem(int position){ ArrayAdapter<Object> adapter = (ArrayAdapter<Object>)this.getAdapter(); adapter.insert((String)srcContent, position); } public boolean onTouchEvent(MotionEvent event){ super.onTouchEvent(event); if(!mDragging){ return false; } final int action = event.getAction(); final float x = event.getX(); final float y = event.getY(); switch(action){ case MotionEvent.ACTION_DOWN: //mLastMotionX = x; mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: final int scrollX = getScrollX(); final int scrollY = getScrollY(); int left = (int)(scrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX); int top = (int)(scrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY); final int width = mDragBitmap.getWidth(); final int height = mDragBitmap.getHeight(); mDragRect.set(left-1, top-1, width+left+1, top+height+1); Log.e(TAG, "每次move的距离:"+(y-mLastMotionY)); //mLastMotionX = x; mLastMotionY = y; left = (int)(scrollX + mLastMotionX - mTouchOffsetX - mBitmapOffsetX); top = (int)(scrollY + mLastMotionY - mTouchOffsetY - mBitmapOffsetY); mDragRect.union(left-1, top-1, width+left+1, top+height+1); invalidate(mDragRect); int scrollHeight = 0; if(y < mTopScrollBound){ /** * 如果当前move到的y位置为mTopScrollBound之上,则下面获取当前位置的item, * 并将该item在当前位置的基础上,向下移动15个dip的偏移量,这样,当向上drag的时候 * 后面的item向下在滚动 * * 向下拖拽的时候同理 */ scrollHeight = 15; }else if(y > mBottomScrollBound){ scrollHeight = -15; } if(scrollHeight != 0){ //调用Listview方法实现滚动 int position = this.pointToPosition((int)x, (int)y); if(position != INVALID_POSITION){ /** * 将当前位置的item向上或者向下移动scrollHeight个单位的距离 */ setSelectionFromTop(position, getChildAt(position - getFirstVisiblePosition()).getTop()+scrollHeight); } } break; case MotionEvent.ACTION_UP: int position = this.pointToPosition((int)x, (int)y); if(position == INVALID_POSITION){ position = startPosition; } float listTop = getChildAt(0).getTop(); //这个是ListView可视区域的最下方,但是不一定数据集中的最后一项的位置 float listBottom = getChildAt(getChildCount()-1).getBottom(); if(y<listTop){ position = 0; }else if(y > listBottom){ /** * 因为向下拖动的时候,ListView是向下滑动的 * 这里当item被往下拖到最下面时,将其添加到数据集中最后一个位置 * 这里注意是getCount()而不是getCount()-1。是向最后插入一个 */ position = getAdapter().getCount(); } stopDrag(position); break; } return true; } private void stopDrag(int newPosition) { mDragging = false; if(mDragBitmap != null){ mDragBitmap.recycle(); } //将拖动的item加入新的位置 addItem(newPosition); invalidate(); } /** * 用当前View的绘制缓冲区创建一个Bitmap * 同时进行一定的缩放 * @param view * @return */ private Bitmap createViewBitmap(View view) { final int left = view.getLeft(); final int top = view.getTop(); //当前按住的位置相对于View本身的偏移量 mTouchOffsetX = mLastMotionX - left; mTouchOffsetY = mLastMotionY - top; view.clearFocus(); view.setPressed(false); boolean willNotCache = view.willNotCacheDrawing(); view.setWillNotCacheDrawing(false); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); final int width = bitmap.getWidth(); final int height = bitmap.getHeight(); //使用一个简单的Scale缩放 Matrix matrix = new Matrix(); float scaleFactor = view.getHeight(); scaleFactor = (scaleFactor+40)/scaleFactor; matrix.setScale(1.0f, scaleFactor); Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); view.destroyDrawingCache(); view.setWillNotCacheDrawing(willNotCache); //创建的缩放后的Bitmap和原Bitmap的padding mBitmapOffsetX = (newBitmap.getWidth()-width)/2; mBitmapOffsetY = (newBitmap.getHeight()-height)/2; return newBitmap; } }
相关文章推荐
- 说说Android桌面(Launcher应用)背后的故事(六)——研究Launcher而实现的附属品(可以拖拽的ListView)
- 说说Android桌面(Launcher应用)背后的故事(六)——研究Launcher而实现的附属品(可以拖拽的ListView)
- 说说Android桌面(Launcher应用)背后的故事(七)——又是一个附属品(可以转动的绚烂饼图)
- 说说Android桌面(Launcher应用)背后的故事(七)——又是一个附属品(可以转动的绚烂饼图)
- 说说Android桌面(Launcher应用)背后的故事(七)——又是一个附属品(可以转动的绚烂饼图)
- 说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
- 说说Android桌面(Launcher应用)背后的故事(九)——让我的桌面多姿多彩
- 说说Android桌面(Launcher应用)背后的故事(一)——揭开她神秘的面纱
- 说说Android桌面(Launcher应用)背后的故事(三)——CellLayout的秘密
- 说说Android桌面(Launcher应用)背后的故事(三)——CellLayout的秘密
- 说说Android桌面(Launcher应用)背后的故事(五)——桌面壁纸的添加
- 说说Android桌面(Launcher应用)背后的故事(八)——让桌面的精灵穿越起来
- 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加
- 说说Android桌面(Launcher应用)背后的故事(大结局)——让Widget拥有Application同等的待遇
- 说说Android桌面(Launcher应用)背后的故事(八)——让桌面的精灵穿越起来
- 说说Android桌面(Launcher应用)背后的故事1
- 说说Android桌面(Launcher应用)背后的故事(一)——揭开她神秘的面纱
- 说说Android桌面(Launcher应用)背后的故事(九)——让我的桌面多姿多彩
- 说说Android桌面(Launcher应用)背后的故事2
- 说说Android桌面(Launcher应用)背后的故事(二)——应用程序的添加