Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Spec] DragGestureRecognizer DropGestureRecognizer #10778

Closed
PureWeen opened this issue May 19, 2020 · 9 comments
Closed

[Spec] DragGestureRecognizer DropGestureRecognizer #10778

PureWeen opened this issue May 19, 2020 · 9 comments

Comments

@PureWeen
Copy link
Contributor

PureWeen commented May 19, 2020

DragGestureRecognizer

  • Allow users to activate a view for dragging

DropGestureRecognizer

  • Allow users to react to a view being dragged over it and then react

API

VisualStates associated with target drop

<VisualStateGroup x:Name="DragAndDropStates">
            <VisualState x:Name="IsDragging">
            </VisualState>
            <VisualState x:Name="DragOver">
            </VisualState>
</VisualStateGroup>

DropGestureRecognizer

public class DropGestureRecognizer
{
     public bool AllowDrop;
     public DragEventArgs DragOver;
     public DropEventArgs Drop;
}

Properties

API Description
AllowDrop This sets up a view to be receiver of a view that's being dropped.

Events

API Description
DragOver This fires when a dragged view is over the receiver view. This fires on the target view
Drop This fires on the target when the user let's go of the view being dragged

DragGestureRecognizer

public class DragGestureRecognizer
{
     public bool CanDrag;
     public DropCompletedEventArgs DropCompleted;
     public DragItemsStartingEventArgs DragStarting;
}

Properties

API Description
CanDrag This indicates that this view will be the draggable one.

Events

API Description
DropCompleted This fire once the drop operation has completed
DragStarting This fires once it's detected that the user wants to initiate a drag operation.

DragState

public enum DragState
{
     Started, Dragging, Completed, Cancelled
}

DragItemsStartingEventArgs

public class DragItemsStartingEventArgs
{
     bool Cancel;
     DataPackage Data;
}

Properties

API Description
Cancel Don't activate the drag operation.
DataPackage Setup the data package to be dragged. If user doesn't specify anything then we just try our best to infer what it should be based on the source

DataPackageOperation

public enum DataPackageOperation
{
     None, Copy, Move
}

DragEventArgs

public class DragEventArgs
{
     DataPackage Data;
     DragState State;
     DataPackageOperation AcceptedOperation
}

Properties

API Description
Data This is the data package associated with the view being dragged. If someone drags an image to an image we'll just load the image into the target. If someone drags a label the data will be text and we'll apply the text. If it's just a view then the data will be a reference to that view and users can then just do something with it
State This will indicate the state of the drag operation
AcceptedOperation Indicates the types of actions this element will accept for the given data package. This is how you indicate that a given view will accept the given item.

DropCompletedEventArgs

public class DropCompletedEventArgs
{
     DataPackageOperation DropResult { get; }
}

Properties

API Description
DataPackageOperation Indicates the type of operation and whether or not it was successful. None means unsuccessful

DropEventArgs

public class DropEventArgs
{
     DataPackageView Data;
     bool Handled;
}

Properties

API Description
Data Readonly view of the data dropped on the target view
Handled Set this to true if you've handled the data in the handler otherwise Forms will try to process the data itself based on the source/target combination

DataPackage

This is used to setup the data for transfer

public class DataPackage
{
     public void SetImage(ImageSource source);
     public void SetText(string value);
     public void SetUri(Uri value);
     public DataPackageView GetView()
}

DataPackageView

This is a read-only copy of the DataPackage object.
This is all the user gets on the drop event to retrieve the data. They can't modify the package

public class DataPackageView
{
     public ImageSource GetImageAsync();
     public string GetTextAsync();
     public Uri GetUriAsynci();
}

Examples

Basic Xaml Example

<StackLayout>
        <Image
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand">
            <Image.GestureRecognizers>
                <DragGestureRecognizer CanDrag="{Binding EnableDragging}"></DragAndDropGestureRecognizer>
            </Image.GestureRecognizers>
        </Image>
         <StackLayout
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand">
            <StackLayout.GestureRecognizers>
                <DropGestureRecognizer DragOver="DragOverStackLayout"  AllowDrop="true"></DropGestureRecognizer>
            </StackLayout.GestureRecognizers>
        </StackLayout>
        <Image
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand">
            <Image.GestureRecognizers>
                <DropGestureRecognizer DragOver="DragOver" Drop="FiresWhenDropped"  AllowDrop="{Binding EnableDrop}"></DropGestureRecognizer>
            </Image.GestureRecognizers>
        </Image>
    </StackLayout>

Workflow

  • User LongPresses on the drag target
  • DragStarting event fires and the user doesn't do anything
    • Because the user doesn't do anything the ImageSource on the image is set on the data package
  • user drags image over the StackLayout but inside DragOverStackLayout the user doesn't do anything so the SL won't receive the element if the user drops it herre
  • once the finger is over the image DragOver fires and the user sets the accepted operation to something other than None
  • Once the user lifts up their finger FiresWhenDropped fires
    • At this point if the user doesn't do anything than forms will set the ImageSource on the target
    • If they set Handled to True then forms does nothing

CollectionView considerations

First implementation won't have tight integration with CV

@PureWeen PureWeen changed the title [Spec] DragAndDropGestureRecognizer [Spec] DragGestureRecognizer DropGestureRecognizer Jul 17, 2020
@dersia
Copy link

dersia commented Jul 18, 2020

What about additional commands to the events?

I really like the specs, just would like to have commands as well as events.

@PureWeen
Copy link
Contributor Author

@dersia

https://github.com/xamarin/Xamarin.Forms/pull/11537/files#diff-eaca5f8f9dd0e23a11bddbe989c5badaR15

I added commands for all the events

Thank you for the reminder 👍

@samhouts samhouts added a/DragAndDrop a/gestures 🖖 proposal-accepted API-change Heads-up to reviewers that this PR may contain an API change and removed proposal-open labels Jul 27, 2020
@IgorKravchenko10
Copy link

Thanks for useful things.
Can we see any samples?

@AswinPG
Copy link

AswinPG commented Aug 5, 2020

Does this support ColletionView ? I saw that first implementations won't have tight integrations with collectionView.. Anyways it was a much needed one and thanks for doing it.

@IgorKravchenko10
Copy link

Just tried. Works great.
But that isn't obviously that CanDrag and AllowDrop properties are false by default. Took a little time to figure out that you need to set true for gestures to work. Also, these properties sound differently. I think for most users it is obvious to sound the same like AllowDrag-AllowDrop or CanDrag-CanDrop.
Thanks.

@IgorKravchenko10
Copy link

IgorKravchenko10 commented Aug 5, 2020

Does this support ColletionView ? I saw that first implementations won't have tight integrations with collectionView.. Anyways it was a much needed one and thanks for doing it.

Works for any view and for items in CollectionView too. But these are simple gestures, they don't know anything about collections. So, scrolling and another interactivity cannot work if you move views in collections.

@PureWeen
Copy link
Contributor Author

PureWeen commented Aug 5, 2020

@IgorKravchenko10

Also, these properties sound differently. I think for most users it is obvious to sound the same like AllowDrag-AllowDrop or CanDrag-CanDrop.

Yea, I've gone around in my head a few times about the naming here. The current naming is basically just a copy paste from the UWP APIs but I'm also not convinced on the current names. One of my thoughts was to just change them both to "Enabled" since our implementation here split these out to separate recognizers.

But that isn't obviously that CanDrag and AllowDrop properties are false by default. Took a little time to figure out that you need to set true for gestures to work.

I've had this thought as well :-) There's a lot of stuff you have to enable at the platform level to even make drag and drop work. For example you have to handle the drag/drop events and then opt in. I setup the implementation to just opt in by default because I'd rather people have to turn things off and just make it all work with minimal API. I feel like defaulting these to true would be a good idea.

Works for any view and for items in CollectionView too. But these are simple gestures, they don't know anything about collections. So, scrolling and another interactivity cannot work if you move views in collections.

Hey that's cool!! I haven't really tested it with CV I just know each native platform has very specific APIs for doing drag and drop with collections and I haven't wired into those yet. I was kind of figuring you could make it work as is but the intention is to have the final implementation tie into the native drag and drop apis related to collections

Thank you for the feedback!!!

I've created an issue here where we can track changes we'd like to make before releasing
#11663

@IgorKravchenko10
Copy link

Hey that's cool!! I haven't really tested it with CV I just know each native platform has very specific APIs for doing drag and drop with collections and I haven't wired into those yet. I was kind of figuring you could make it work as is but the intention is to have the final implementation tie into the native drag and drop apis related to collections

I have to say that DropGestureRecognizer works on DataTemplate level but not for whole CollectionView.

OnDrop doesn't raise:

<CollectionView ItemsSource="{Binding GroupedItems, Mode=OneWay}">
                        <CollectionView.GestureRecognizers>
                            <DropGestureRecognizer AllowDrop="True" Drop="OnDrop"/>
                        </CollectionView.GestureRecognizers>
                        <CollectionView.ItemTemplate>...</CollectionView.ItemTemplate>
</CollectionView>

OnDrop does raise:

<CollectionView ItemsSource="{Binding GroupedItems, Mode=OneWay}">
                        <CollectionView.ItemTemplate>
                              <DataTemplate>
                                    <Grid>
                                          <Grid.GestureRecognizers>
                                               <DragGestureRecognizer CanDrag="True"/>
                                               <DropGestureRecognizer AllowDrop="True" Drop="OnDrop"/>
                                          </Grid.GestureRecognizers>
                                    </Grid>
                              </DataTemplate>
                        </CollectionView.ItemTemplate>
</CollectionView>

@PureWeen
Copy link
Contributor Author

PureWeen commented Aug 5, 2020

@IgorKravchenko10 yea all the platforms have different delegates and events very specific to lists you have to use to make this all work.
i.e. https://developer.apple.com/documentation/uikit/uicollectionviewdragdelegate

So, I'll need to tie into those :-)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants