Created
April 23, 2015 13:20
-
-
Save kjeremy/10500aaae1afd7579ef5 to your computer and use it in GitHub Desktop.
Drag and drop for an ExpandableListView (MvvmCross)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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