Skip to content

Instantly share code, notes, and snippets.

@kjeremy
Created April 23, 2015 13:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kjeremy/10500aaae1afd7579ef5 to your computer and use it in GitHub Desktop.
Save kjeremy/10500aaae1afd7579ef5 to your computer and use it in GitHub Desktop.
Drag and drop for an ExpandableListView (MvvmCross)
public class ExpandableListViewGroupDragHelper : IDisposable
{
private class DragState
{
public int PreviousY { get; set; }
public int SelectedGroupPosition { get; set; }
}
public class DragListEventArgs : EventArgs
{
public int PreviousPosition { get; private set; }
public int CurrentPosition { get; private set; }
public DragListEventArgs(int previousPosition, int currentPosition)
{
this.PreviousPosition = previousPosition;
this.CurrentPosition = currentPosition;
}
}
public float DragRatio { get; set; }
private DragState _dragState;
private readonly WeakReference<ExpandableListView> _list;
public event EventHandler<DragListEventArgs> DragListPositionChanged;
private readonly Func<ClipDescription, bool> _acceptsClipData;
protected virtual void OnDragListPositionChanged(DragListEventArgs e)
{
EventHandler<DragListEventArgs> handler = this.DragListPositionChanged;
if (handler != null) handler(this, e);
}
public ExpandableListViewGroupDragHelper(ExpandableListView listView,
Func<ClipDescription, bool> acceptsClipData)
{
this._list = new WeakReference<ExpandableListView>(listView);
this._acceptsClipData = acceptsClipData;
this.DragRatio = 1.0f;
listView.Drag += this.ListOnDrag;
}
~ExpandableListViewGroupDragHelper()
{
this.Dispose(false);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposeManaged)
{
if (disposeManaged)
{
ExpandableListView list;
if (this._list.TryGetTarget(out list))
list.Drag -= this.ListOnDrag;
}
}
private void ListOnDrag(object sender, View.DragEventArgs dragEventArgs)
{
ExpandableListView list;
if (!this._list.TryGetTarget(out list))
return;
var action = dragEventArgs.Event.Action;
switch (action)
{
case DragAction.Started:
if (!this._acceptsClipData(dragEventArgs.Event.ClipDescription))
{
dragEventArgs.Handled = false;
return;
}
long packedPosition = dragEventArgs.Event.LocalState.ToNetObject<long>();
if (ExpandableListView.GetPackedPositionType(packedPosition) == PackedPositionType.Group)
{
var groupPosition = ExpandableListView.GetPackedPositionGroup(packedPosition);
for (int i = 0; i < list.ExpandableListAdapter.GroupCount; i++)
list.CollapseGroup(i);
this._dragState = new DragState();
this._dragState.SelectedGroupPosition = groupPosition;
dragEventArgs.Handled = true;
}
break;
case DragAction.Location:
float y = dragEventArgs.Event.GetY();
int speed = (int)((y - this._dragState.PreviousY) * this.DragRatio);
// Let's try swapping items?
var listPosition = list.PointToPosition((int)dragEventArgs.Event.GetX(), (int)y);
if (listPosition != AdapterView.InvalidPosition &&
listPosition != this._dragState.SelectedGroupPosition)
{
var p1 = this._dragState.SelectedGroupPosition;
var p2 = listPosition;
this.OnDragListPositionChanged(new DragListEventArgs(p1, p2));
this._dragState.SelectedGroupPosition = p2;
}
if (list.LastVisiblePosition < list.Count && speed > 0)
list.SmoothScrollBy(speed, 1);
if (list.FirstVisiblePosition > 0 && speed < 0)
list.SmoothScrollBy(speed, 1);
this._dragState.PreviousY = (int)y;
dragEventArgs.Handled = true;
break;
case DragAction.Ended:
list.SmoothScrollToPositionFromTop(1, 0, 200);
dragEventArgs.Handled = true;
break;
case DragAction.Entered:
case DragAction.Exited:
case DragAction.Drop:
dragEventArgs.Handled = true;
break;
}
}
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// ...
((ExpandableListView)this.List).ItemLongClick += (sender, args) =>
{
View v = (View)sender;
if (ExpandableListView.GetPackedPositionType(args.Id) == PackedPositionType.Group)
{
long packedPos = ((ExpandableListView)args.Parent).GetExpandableListPosition(args.Position);
var pos = this.List.GetFlatListPosition(packedPos);
View groupView = this.List.GetChildAt(pos);
ClipData.Item item = new ClipData.Item(this.ClipId);
ClipData dragData = new ClipData(this.ClipId, new string[] {ClipDescription.MimetypeTextPlain},
item);
v.StartDrag(dragData, new View.DragShadowBuilder(groupView), packedPos.ToJavaObject(), 0);
args.Handled = true;
}
};
// ...
}
public override void OnDestroy()
{
base.OnDestroy();
if (this._dragHelper != null)
{
this._dragHelper.DragListPositionChanged -= this.DragHelperOnDragListPositionChanged;
this._dragHelper.Dispose();
this._dragHelper = null;
}
}
protected override void DragHelperOnDragListPositionChanged(object sender,
ExpandableListViewGroupDragHelper.DragListEventArgs e)
{
LayerSelectionViewModel viewModel = ViewModel as LayerSelectionViewModel;
if (viewModel != null)
viewModel.ReorderItems(viewModel.AreaItems, e.PreviousPosition, e.CurrentPosition); // DO YOUR MAGIC HERE
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment