package com.example.aspros.draggridview.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.os.Vibrator; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.GridView; import com.example.aspros.draggridview.LogUtil; import com.example.aspros.draggridview.R; import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.AnimatorSet; import com.nineoldandroids.animation.ObjectAnimator; import com.nineoldandroids.animation.TypeEvaluator; import com.nineoldandroids.animation.ValueAnimator; import java.util.ArrayList; import java.util.List; /** * Created by aspros on 16/3/18. */ public class DragGridView extends GridView { private static final int MOVE_DURATION = 300; private static final int SCROLL_SPEED = 60; private static final int EXTEND_LENGTH = 20; private Vibrator vibrator; private int lastX = -1; private int lastY = -1; /** * 拖动时的图像 和 它的位置 */ private BitmapDrawable hoverCell; private Rect currentRect; /** * 要拖动的view */ private View selectView; private int originPosition = INVALID_POSITION; private int currentPosition = INVALID_POSITION; private boolean isEdit; private boolean isDrag; private boolean isSwap; private DragCallback dragCallback; public DragGridView(Context context) { this(context, null); } public DragGridView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragGridView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); } public DragAdapterInterface getInterface() { return (DragAdapterInterface) getAdapter(); } public void setDragCallback(DragCallback dragCallback) { this.dragCallback=dragCallback; } @Override public boolean onTouchEvent(MotionEvent ev) { int x = (int) ev.getX(); int y = (int) ev.getY(); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: lastX = x; lastY = y; break; case MotionEvent.ACTION_MOVE: if (isDrag) { int offsetX = x - lastX; int offsetY = y - lastY; lastX = x; lastY = y; currentRect.offset(offsetX, offsetY); hoverCell.setBounds(currentRect); invalidate(); if (!isSwap) { swapItems(x, y); } handleScroll(); return false; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (isDrag) { endDrag(); } break; default: } return super.onTouchEvent(ev); } public void clicked(int position) { if(isEdit) { isEdit=false; return; } resumeView(); LogUtil.i("点击 Item " + position); } private void resumeView() { if (selectView != null) { selectView.findViewById(R.id.delete_img).setVisibility(INVISIBLE); selectView.findViewById(R.id.item_container).setVisibility(VISIBLE); selectView.findViewById(R.id.item_container).setBackgroundColor(Color.WHITE); } } public void startDrag(int position) { if (position == INVALID_POSITION) { return; } //恢复之前的图像,改变背景,去除删除按钮 resumeView(); selectView = getChildAt(position - getFirstVisiblePosition()); if (selectView != null) { isDrag = true; isEdit = true; /** * 移动的图像背景要有区别,并显示删除按钮 */ selectView.findViewById(R.id.item_container).setBackgroundColor(Color.parseColor("#f0f0f0")); selectView.findViewById(R.id.delete_img).setVisibility(VISIBLE); originPosition = position; currentPosition = position; vibrator.vibrate(60); //获取图像 hoverCell = getHoverCell(selectView); selectView.findViewById(R.id.item_container).setVisibility(INVISIBLE); if(dragCallback!=null) { dragCallback.startDrag(position); } } } private void swapItems(int x, int y) { int endPosition = pointToPosition(x, y); if (endPosition != INVALID_POSITION && endPosition != currentPosition) { isSwap = true; isEdit = false; resumeView(); //交换数据内容 getInterface().reOrder(currentPosition, endPosition); selectView=getChildAt(endPosition-getFirstVisiblePosition()); selectView.findViewById(R.id.item_container).setVisibility(INVISIBLE); selectView.findViewById(R.id.item_container).setBackgroundColor(Color.parseColor("#f0f0f0")); selectView.findViewById(R.id.delete_img).setVisibility(VISIBLE); //动画显示交换过程 animateSwap(endPosition); } } private void animateSwap(int endPosition) { List<Animator> animators=new ArrayList<>(); if(endPosition<currentPosition) { for(int i=endPosition+1;i<=currentPosition;i++) { View view=getChildAt(i-getFirstVisiblePosition()); if(i%getNumColumns()==0) { animators.add(createTranslationAnimations(view,view.getWidth()*(getNumColumns()-1),0,-view.getHeight(),0)); } else { animators.add(createTranslationAnimations(view,-view.getWidth(),0,0,0)); } } } else { for(int i=currentPosition;i<endPosition;i++) { View view=getChildAt(i-getFirstVisiblePosition()); if((i+1)%getNumColumns()==0) { animators.add(createTranslationAnimations(view,-view.getWidth()*(getNumColumns()-1),0,view.getHeight(),0)); } else { animators.add(createTranslationAnimations(view,view.getWidth(),0,0,0)); } } } currentPosition=endPosition; AnimatorSet animatorSet=new AnimatorSet(); animatorSet.playTogether(animators); animatorSet.setDuration(MOVE_DURATION); animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); animatorSet.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { isSwap = false; } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); animatorSet.start(); } private Animator createTranslationAnimations(View view, float startX, float endX, float startY, float endY) { ObjectAnimator animX = ObjectAnimator.ofFloat(view, "translationX", startX, endX); ObjectAnimator animY = ObjectAnimator.ofFloat(view, "translationY", startY, endY); AnimatorSet animSetXY = new AnimatorSet(); animSetXY.playTogether(animX, animY); return animSetXY; } private void endDrag() { currentRect.set(selectView.getLeft(), selectView.getTop(), selectView.getRight(), selectView.getBottom()); animateBound(); } private void animateBound() { TypeEvaluator<Rect> evaluator = new TypeEvaluator<Rect>() { @Override public Rect evaluate(float fraction, Rect startValue, Rect endValue) { return new Rect(interpolate(startValue.left, endValue.left, fraction), interpolate(startValue.top, endValue.top, fraction), interpolate(startValue.right, endValue.right, fraction), interpolate(startValue.bottom, endValue.bottom, fraction)); } public int interpolate(int start, int end, float fraction) { return (int) (start + fraction * (end - start)); } }; ObjectAnimator animator = ObjectAnimator.ofObject(hoverCell, "bounds", evaluator, currentRect); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { invalidate(); } }); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { isDrag = false; if (currentPosition != originPosition) { resumeView(); originPosition = currentPosition; } hoverCell = null; selectView.findViewById(R.id.item_container).setVisibility(VISIBLE); if (dragCallback != null) { dragCallback.endDrag(currentPosition); } } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); animator.start(); } private BitmapDrawable getHoverCell(View view) { int left = view.getLeft(); int top = view.getTop(); int w = view.getWidth(); int h = view.getHeight(); Bitmap bitmap = getBitmapFromView(view); BitmapDrawable drawable = new BitmapDrawable(getResources(), bitmap); currentRect = new Rect(left - EXTEND_LENGTH, top - EXTEND_LENGTH, left + w + EXTEND_LENGTH, top + h + EXTEND_LENGTH); drawable.setBounds(currentRect); return drawable; } private Bitmap getBitmapFromView(View v) { Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); v.draw(canvas); return bitmap; } private void handleScroll() { int offset=computeVerticalScrollOffset(); int height=getHeight(); int extent=computeVerticalScrollExtent(); int range=computeHorizontalScrollRange(); if(currentRect.top<=0 && offset>0) { smoothScrollBy(-SCROLL_SPEED,0); } else if(currentRect.bottom>=height && (offset+extent)<range) { smoothScrollBy(SCROLL_SPEED,0); } } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if (hoverCell != null) { hoverCell.draw(canvas); } } }