package com.bigfat.linearlayoutdragdemo; import android.animation.ObjectAnimator; import android.view.DragEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; /** * Created by yueban on 10/9/15. */ public class DragUtil { public static void setupDragSort(View view) { view.setOnDragListener(new View.OnDragListener() { @Override public boolean onDrag(final View view, DragEvent event) { ViewGroup viewGroup = (ViewGroup) view.getParent(); DragState dragState = (DragState) event.getLocalState(); switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: if (view == dragState.view) { view.setVisibility(View.INVISIBLE); } break; case DragEvent.ACTION_DRAG_LOCATION: if (view == dragState.view) { break; } int index = viewGroup.indexOfChild(view); if ((index > dragState.index && event.getY() > view.getHeight() / 2) || (index < dragState.index && event.getY() < view.getHeight() / 2)) { swapViews(viewGroup, view, index, dragState); } break; case DragEvent.ACTION_DROP: if (view != dragState.view) { swapViewGroupChildren(viewGroup, view, dragState.view); } break; case DragEvent.ACTION_DRAG_ENDED: if (view == dragState.view) { view.setVisibility(View.VISIBLE); } break; } return true; } }); view.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { view.startDrag(null, new View.DragShadowBuilder(view), new DragState(view), 0); return true; } }); } private static void swapViewsBetweenIfNeeded(ViewGroup viewGroup, int index, DragState dragState) { if (index - dragState.index > 1) { int indexAbove = index - 1; swapViews(viewGroup, viewGroup.getChildAt(indexAbove), indexAbove, dragState); } else if (dragState.index - index > 1) { int indexBelow = index + 1; swapViews(viewGroup, viewGroup.getChildAt(indexBelow), indexBelow, dragState); } } private static void swapViews(ViewGroup viewGroup, final View view, int index, DragState dragState) { swapViewsBetweenIfNeeded(viewGroup, index, dragState); final float viewY = view.getY(); swapViewGroupChildren(viewGroup, view, dragState.view); dragState.index = index; postOnPreDraw(view, new Runnable() { @Override public void run() { ObjectAnimator .ofFloat(view, View.Y, viewY, view.getTop()) .setDuration(200) .start(); } }); } private static void postOnPreDraw(View view, final Runnable runnable) { final ViewTreeObserver observer = view.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { if (observer.isAlive()) { observer.removeOnPreDrawListener(this); } runnable.run(); return true; } }); } private static void swapViewGroupChildren(ViewGroup viewGroup, View firstView, View secondView) { int firstIndex = viewGroup.indexOfChild(firstView); int secondIndex = viewGroup.indexOfChild(secondView); if (firstIndex < secondIndex) { viewGroup.removeViewAt(secondIndex); viewGroup.removeViewAt(firstIndex); viewGroup.addView(secondView, firstIndex); viewGroup.addView(firstView, secondIndex); } else { viewGroup.removeViewAt(firstIndex); viewGroup.removeViewAt(secondIndex); viewGroup.addView(firstView, secondIndex); viewGroup.addView(secondView, firstIndex); } } private static class DragState { public View view; public int index; private DragState(View view) { this.view = view; index = ((ViewGroup) view.getParent()).indexOfChild(view); } } }