import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageView;
import com.ebensz.enote.notepad.R;
import com.ebensz.enote.notepad.browser.BrowserController;
import com.ebensz.enote.notepad.ui.adapter.BrowserGridAdapter;
public class DraggableGridView extends GridView {
private static final int DRAG_MODE_DELAY = 500;
private static final int DRAG_MODE_MSG = 10001;
private static final int UP_SCROLL_BOUNCE = 150;// 拖动的时候,开始向上滚动的边界
private static final int DOWN_SCROLL_BOUNCE = 850;// 拖动的时候,开始向下滚动的边界
public DraggableGridView(Context context, AttributeSet attrs) {
super(context, attrs);
columns = context.getResources().getInteger(R.integer.grid_columns);
}
public void setBrowserController(BrowserController browserController) {
this.browserController = browserController;
}
public boolean isDataChanged() {
return isDataChanged;
}
public void cancelDrag() {
isDataChanged = false;
isDragMode = false;
}
public int getDropPosition() {
return dropPosition;
}
public int getColumns() {
return columns;
}
public void sendMsgDelayed() {
handler.removeMessages(DRAG_MODE_MSG);
if (!browserController.isStartDragEnable() || startPosition == AdapterView.INVALID_POSITION || getAdapter().getCount() < 2) {
return;
}
handler.sendEmptyMessageDelayed(DRAG_MODE_MSG, DRAG_MODE_DELAY);
}
public View getChildViewAt(int index) {
int position = getVisibleItemIndex(index);
if (position < 0 || position > (getCount() - 1)) {
return null;
}
return getChildAt(position);
}
@Override
public boolean onHoverEvent(MotionEvent event) {
handler.removeMessages(DRAG_MODE_MSG);
if (isDragMode) {
isDragMode = false;
onDrop();
}
return super.onHoverEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int x = (int) ev.getX();
int y = (int) ev.getY();
final int rawY = (int) ev.getRawY();
final int action = ev.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
init(ev);
if (null == itemView) {
return super.onTouchEvent(ev);
}
if (isDragMode) {
prepareDrag(itemView);
}
break;
case MotionEvent.ACTION_MOVE:
if (isDragMode) {
onDrag(x, y, rawY);
if (!isMoving && (rawY > UP_SCROLL_BOUNCE && rawY < DOWN_SCROLL_BOUNCE)) {
onMove(x, y);
}
}
break;
case MotionEvent.ACTION_UP:
handler.removeMessages(DRAG_MODE_MSG);
if (!isDataChanged && null != itemView) {
itemView.setVisibility(View.VISIBLE);
}
if (isDragMode) {
onDrop();
}
isDragMode = false;
break;
}
return super.onTouchEvent(ev);
}
private void prepareDrag(View itemView) {
itemView.destroyDrawingCache();
itemView.setDrawingCacheEnabled(true);
itemView.setDrawingCacheBackgroundColor(0x000000);
Bitmap drawingCache = Bitmap.createBitmap(itemView
.getDrawingCache(true));
Bitmap substitute = Bitmap.createBitmap(drawingCache, 0, 0,
drawingCache.getWidth(),
drawingCache.getHeight());
startDrag(substitute, downX, downY);
setDropItemVisible(false);
itemView.setVisibility(View.INVISIBLE);
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == DRAG_MODE_MSG) {
isDragMode = true;
prepareDrag(itemView);
}
}
};
private void init(MotionEvent ev){
downX = (int) ev.getX();
downY = (int) ev.getY();
startPosition = dragPosition = dropPosition = pointToPosition(downX, downY);
if (dragPosition == AdapterView.INVALID_POSITION) {
itemView = null;
return;
}
itemView = getChildAt(dragPosition - getFirstVisiblePosition());
// 得到当前点在item内部的偏移量 即相对于item左上角的坐标
dragPointX = downX - itemView.getLeft();
dragPointY = downY - itemView.getTop();
dragOffsetX = (int) (ev.getRawX() - downX);
dragOffsetY = (int) (ev.getRawY() - downY);
isMoving = false;
}
private void startDrag(Bitmap bm, int x, int y) {
stopDrag();
windowParams = new WindowManager.LayoutParams();
windowParams.gravity = Gravity.TOP | Gravity.LEFT;// 这个必须加
// 得到preview左上角相对于屏幕的坐标
windowParams.x = x - dragPointX + dragOffsetX - 10;
windowParams.y = y - dragPointY + dragOffsetY - 10;
// 设置宽和高
windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
windowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
windowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
windowParams.format = PixelFormat.TRANSLUCENT;
windowParams.windowAnimations = 0;
ImageView iv = new ImageView(getContext());
iv.setImageBitmap(bm);
windowManager = (WindowManager) getContext().getSystemService(
Context.WINDOW_SERVICE);// "window"
windowManager.addView(iv, windowParams);
dragImageView = iv;
}
private void enterDragMode() {
browserController.exitSelectMode(false);
browserController.enterDragMode();
}
private void onMove(int x, int y) {
final int position = pointToPosition(x, y);
if (position != AdapterView.INVALID_POSITION && position != dragPosition) {
dropPosition = position;
}
dragPosition = startPosition;
int moveNum = dropPosition - dragPosition;
if (moveNum != 0) {
enterDragMode();
int moveNumAbs = Math.abs(moveNum);
float offsetX, offsetY;
for (int i = 0; i < moveNumAbs; i++) {
int holdPosition;
if (moveNum > 0) {
holdPosition = dragPosition + 1;
offsetX = (dragPosition / columns == holdPosition / columns) ? (-1) : (columns - 1);
offsetY = (dragPosition / columns == holdPosition / columns) ? 0 : (-1);
}
else {
holdPosition = dragPosition - 1;
offsetX = (dragPosition / columns == holdPosition / columns) ? 1 : (-(columns - 1));
offsetY = (dragPosition / columns == holdPosition / columns) ? 0 : 1;
}
final ViewGroup moveView = (ViewGroup) getChildViewAt(holdPosition);
Animation animation = getMoveAnimation(offsetX, offsetY);
moveView.startAnimation(animation);
dragPosition = holdPosition;
if (dragPosition == dropPosition) {
lastAnimationID = animation.toString();
}
final BrowserGridAdapter adapter = (BrowserGridAdapter)getAdapter();
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
isMoving = true;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
isMoved = true;
isDataChanged = true;
String animationId = animation.toString();
if (animationId.equalsIgnoreCase(lastAnimationID)) {
adapter.exchangePages(startPosition, dropPosition);
startPosition = dropPosition;
isMoving = false;
}
moveView.clearAnimation();
}
});
}
}
}
private int getVisibleItemIndex(int dragPosition) {
int firstVisiblePosition = getFirstVisiblePosition();
int index = Math.abs(dragPosition - firstVisiblePosition);
int visibleCount = getLastVisiblePosition() - firstVisiblePosition;
if (index > visibleCount) {
index = visibleCount - 1;
}
return index;
}
private void onDrop() {
stopDrag();
final BrowserGridAdapter adapter = (BrowserGridAdapter) this.getAdapter();
adapter.showDropItem(true);
adapter.notifyDataSetChanged();
if (isMoved) {
browserController.setSelectedPosition(dropPosition);
adapter.draggedChangeData(dropPosition);
isMoved = false;
}
}
private void onDrag(int x, int y,int rawY) {
if (dragImageView != null) {
windowParams.alpha = 0.6f;
windowParams.x = x - dragPointX + dragOffsetX;
windowParams.y = y - dragPointY + dragOffsetY;
windowManager.updateViewLayout(dragImageView, windowParams);
}
// 滚动
int scrollHeight = 0;
if (rawY < UP_SCROLL_BOUNCE) {
scrollHeight = -150;
}
else if (rawY > DOWN_SCROLL_BOUNCE) {
scrollHeight = 150;
}
if (scrollHeight != 0) {
smoothScrollBy(scrollHeight,0);
}
}
private void stopDrag() {
if (dragImageView != null) {
windowManager.removeView(dragImageView);
dragImageView = null;
}
}
private Animation getMoveAnimation(float x, float y) {
TranslateAnimation go = new TranslateAnimation(
Animation.RELATIVE_TO_SELF,
0,
Animation.RELATIVE_TO_SELF,
x,
Animation.RELATIVE_TO_SELF,
0,
Animation.RELATIVE_TO_SELF,
y
);
go.setFillAfter(true);
go.setDuration(150);
return go;
}
private void setDropItemVisible(boolean isVisible) {
final BrowserGridAdapter adapter = (BrowserGridAdapter) this.getAdapter();
adapter.showDropItem(isVisible);
}
private BrowserController browserController;
private View itemView;
private boolean isDataChanged;
private boolean isDragMode;
private int columns;
private int dragPosition;// 开始拖拽的位置
private int dropPosition;// 结束拖拽的位置
private int dragPointX; // 相对于item的x坐标
private int dragPointY; // 相对于item的y坐标
private int dragOffsetX;
private int dragOffsetY;
private ImageView dragImageView; // 拖动item的preview
private WindowManager windowManager;
private WindowManager.LayoutParams windowParams;
private int startPosition;
private int downX,downY;
private String lastAnimationID;
private boolean isMoved;
private boolean isMoving;
}