添加拖放手势识别器
借助拖放手势,可以使用连续手势将项及其相关的数据包从屏幕上的一个位置拖放到另一个位置。 拖放手势可以在单个应用程序中进行,也可以在一个应用程序中开始,然后在另一个应用程序中结束。
重要
iOS、Android 和通用 Windows 平台 (UWP) 都支持识别拖放手势。 不过,在 iOS 上,平台版本不得低于 iOS 11。
拖动源(即启动拖动手势的元素)可以通过填充数据包对象来提供要传输的数据。 当拖放源被释放时,就会发生放置。 然后,放置目标(即拖动源下的元素)会处理数据包。
在应用程序中启用拖放的过程如下所示:
- 启用对元素的拖动,具体方法为将
DragGestureRecognizer
对象添加到它的GestureRecognizers
集合中。 有关详细信息,请参阅启用拖动。 - [可选] 生成数据包。 Xamarin.Forms 自动为图像和文本控件填充数据包,但对于其他内容,你需要构造自己的数据包。 有关详细信息,请参阅生成数据包。
- 启用对元素的放置,具体方法为将
DropGestureRecognizer
对象添加到它的GestureRecognizers
集合中。 有关详细信息,请参阅启用放置。 - [可选] 处理
DropGestureRecognizer.DragOver
事件,以指明放置目标允许执行的操作类型。 有关详细信息,请参阅处理 DragOver 事件。 - [可选] 处理数据包,以接收放置的内容。 Xamarin.Forms 自动从数据包中检索图像和文本数据,但对于其他内容,你需要自行处理数据包。 有关详细信息,请参阅处理数据包。
注意
暂不支持将项拖放到 CollectionView
和从中拖动项。
启用拖动
在 Xamarin.Forms 中,拖动手势识别是由 DragGestureRecognizer
类提供的。 此类定义了以下属性:
CanDrag
属于bool
类型,指明手势识别器附加到的元素能否为拖动源。 此属性的默认值为true
。DragStartingCommand
属于ICommand
类型,在第一次识别拖动手势时执行。DragStartingCommandParameter
属于object
类型,是传递给DragStartingCommand
的参数。DropCompletedCommand
属于ICommand
类型,在放置拖动源时执行。DropCompletedCommandParameter
属于object
类型,是传递给DropCompletedCommand
的参数。
这些属性由 BindableProperty
对象提供支持,表示它们可以是数据绑定的目标,并可以设置样式。
DragGestureRecognizer
类还定义了 DragStarting
和 DropCompleted
事件,这些事件会在 CanDrag
属性为 true
时触发。 当检测到拖动手势时,DragGestureRecognizer
对象就会执行 DragStartingCommand
,并调用 DragStarting
事件。 然后,当检测到放置手势完成时,DragGestureRecognizer
对象就会执行 DropCompletedCommand
,并调用 DropCompleted
事件。
DragStarting
事件随附的 DragStartingEventArgs
对象定义了以下属性:
Handled
:类型为bool
,指明是事件处理程序已经处理了事件,还是 Xamarin.Forms 应继续执行自己的处理。Cancel
属于bool
类型,指明是否应取消事件。Data
属于DataPackage
类型,指明拖动源随附的数据包。 这是只读属性。
下面的 XAML 示例展示了附加到 Image
的 DragGestureRecognizer
:
<Image Source="monkeyface.png">
<Image.GestureRecognizers>
<DragGestureRecognizer />
</Image.GestureRecognizers>
</Image>
在此示例中,可以对 Image
启动拖动手势。
提示
在 iOS、Android 和 UWP 上,拖动手势是通过先长按再拖动来启动的。
生成数据包
Xamarin.Forms(在拖动手势启动时)自动为以下控件生成数据包:
- 文本控件。 可以从
CheckBox
、DatePicker
、Editor
、Entry
、Label
、RadioButton
、Switch
和TimePicker
对象中拖动文本值。 - 图像控件。 可以从
Button
、Image
和ImageButton
控件中拖动图像。
下表显示了当对文本控件启动拖动手势时读取的属性和尝试执行的任何转换:
控件 | 属性 | 转换 |
---|---|---|
CheckBox |
IsChecked |
bool 已转换为 string 。 |
DatePicker |
Date |
DateTime 已转换为 string 。 |
Editor |
Text |
|
Entry |
Text |
|
Label |
Text |
|
RadioButton |
IsChecked |
bool 已转换为 string 。 |
Switch |
IsToggled |
bool 已转换为 string 。 |
TimePicker |
Time |
TimeSpan 已转换为 string 。 |
对于除文本和图像以外的内容,你需要自行生成数据包。
数据包由 DataPackage
类表示,此类定义了以下属性:
Properties
属于DataPackagePropertySet
类型,它是组成DataPackage
中所包含数据的属性的集合。 此为只读属性。Image
属于ImageSource
类型,它是DataPackage
中包含的图像。Text
属于string
类型,它是DataPackage
中包含的文本。View
属于DataPackageView
类型,它是DataPackage
的只读版本。
DataPackagePropertySet
类表示存储为 Dictionary<string,object>
的属性包。 若要了解 DataPackageView
类,请参阅处理数据包。
存储图像或文本数据
通过在 DataPackage.Image
或 DataPackage.Text
属性中存储图像或文本数据,可以将这些数据与拖动源关联。 这可以在 DragStarting
事件的处理程序中完成。
下面的 XAML 示例展示了为 DragStarting
事件注册处理程序的 DragGestureRecognizer
:
<Path Stroke="Black"
StrokeThickness="4">
<Path.GestureRecognizers>
<DragGestureRecognizer DragStarting="OnDragStarting" />
</Path.GestureRecognizers>
<Path.Data>
<!-- PathGeometry goes here -->
</Path.Data>
</Path>
在此示例中,DragGestureRecognizer
附加到 Path
对象。 当在 Path
上检测到拖动手势时,就会触发 DragStarting
事件,此事件执行 OnDragStarting
事件处理程序:
void OnDragStarting(object sender, DragStartingEventArgs e)
{
e.Data.Text = "My text data goes here";
}
DragStarting
事件随附的 DragStartingEventArgs
对象有类型为 DataPackage
的 Data
属性。 在此示例中,DataPackage
对象的 Text
属性设置为 string
。 然后,可以在放置时访问 DataPackage
来检索 string
。
将数据存储在属性包中
任何数据(包括图像和文本)都可以通过将数据存储在 DataPackage.Properties
集合中来与拖动源关联。 这可以在 DragStarting
事件的处理程序中完成。
下面的 XAML 示例展示了为 DragStarting
事件注册处理程序的 DragGestureRecognizer
:
<Rectangle Stroke="Red"
Fill="DarkBlue"
StrokeThickness="4"
HeightRequest="200"
WidthRequest="200">
<Rectangle.GestureRecognizers>
<DragGestureRecognizer DragStarting="OnDragStarting" />
</Rectangle.GestureRecognizers>
</Rectangle>
在此示例中,DragGestureRecognizer
附加到 Rectangle
对象。 当在 Rectangle
上检测到拖动手势时,就会触发 DragStarting
事件,此事件执行 OnDragStarting
事件处理程序:
void OnDragStarting(object sender, DragStartingEventArgs e)
{
Shape shape = (sender as Element).Parent as Shape;
e.Data.Properties.Add("Square", new Square(shape.Width, shape.Height));
}
DragStarting
事件随附的 DragStartingEventArgs
对象有类型为 DataPackage
的 Data
属性。 可以通过修改 DataPackage
对象的 Properties
集合(即 Dictionary<string, object>
集合)来存储所需的任何数据。 在此示例中,Properties
字典被修改为根据“Square”键存储表示 Rectangle
大小的 Square
对象。
启用放置
在 Xamarin.Forms 中,放置手势识别是由 DropGestureRecognizer
类提供的。 此类定义了以下属性:
AllowDrop
属于bool
类型,指明手势识别器附加到的元素能否成为放置目标。 此属性的默认值为true
。DragOverCommand
属于ICommand
类型,在拖动源被拖动到放置目标上时执行。DragOverCommandParameter
属于object
类型,是传递给DragOverCommand
的参数。DragLeaveCommand
属于ICommand
类型,在拖动源被拖至放置目标上时执行。DragLeaveCommandParameter
属于object
类型,是传递给DragLeaveCommand
的参数。DropCommand
属于ICommand
类型,在拖动源被放置到放置目标上时执行。DropCommandParameter
属于object
类型,是传递给DropCommand
的参数。
这些属性由 BindableProperty
对象提供支持,表示它们可以是数据绑定的目标,并可以设置样式。
DropGestureRecognizer
类还定义了 DragOver
、DragLeave
和 Drop
事件,这些事件会在 AllowDrop
属性为 true
时触发。 当在放置目标上识别拖动源时,DropGestureRecognizer
就会执行 DragOverCommand
,并调用 DragOver
事件。 然后,如果将拖动源拖至放置目标,DropGestureRecognizer
将执行 DragLeaveCommand
并调用 DragLeave
事件。 最后,当在放置目标上识别放置手势时,DropGestureRecognizer
就会执行 DropCommand
,并调用 Drop
事件。
DragOver
和 DragLeave
事件随附的 DragEventArgs
类定义了以下属性:
Data
属于DataPackage
类型,它包含与拖动源关联的数据。 此属性为只读。AcceptedOperation
属于DataPackageOperation
类型,指定放置目标允许执行的操作。
若要了解 DataPackageOperation
枚举,请参阅处理 DragOver 事件。
Drop
事件随附的 DropEventArgs
类定义了以下属性:
Data
属于DataPackageView
类型,它是数据包的只读版本。Handled
:类型为bool
,指明是事件处理程序已经处理了事件,还是 Xamarin.Forms 应继续执行自己的处理。
下面的 XAML 示例展示了附加到 Image
的 DropGestureRecognizer
:
<Image BackgroundColor="Silver"
HeightRequest="300"
WidthRequest="250">
<Image.GestureRecognizers>
<DropGestureRecognizer />
</Image.GestureRecognizers>
</Image>
在此示例中,当拖动源被放置到 Image
放置目标上时,拖动源就会被复制到放置目标,但前提是拖动源是 ImageSource
。 这是因为 Xamarin.Forms 自动将拖动的图像和文本复制到兼容的放置目标。
处理 DragOver 事件
可以视需要选择处理 DropGestureRecognizer.DragOver
事件,以指明放置目标允许执行的操作类型。 这可以通过设置 DragOver
事件随附的 DragEventArgs
对象的 DataPackageOperation
类型 AcceptedOperation
属性来完成。
DataPackageOperation
枚举定义以下成员:
None
:指明不执行任何操作。Copy
:指明将拖动源内容复制到放置目标。
重要说明
当 DragEventArgs
对象创建时,AcceptedOperation
属性默认为 DataPackageOperation.Copy
。
下面的 XAML 示例展示了为 DragOver
事件注册处理程序的 DropGestureRecognizer
:
<Image BackgroundColor="Silver"
HeightRequest="300"
WidthRequest="250">
<Image.GestureRecognizers>
<DropGestureRecognizer DragOver="OnDragOver" />
</Image.GestureRecognizers>
</Image>
在此示例中,DropGestureRecognizer
附加到 Image
对象。 将拖动源被拖动到放置目标上但尚未放置时,就会触发 DragOver
事件,此事件执行 OnDragOver
事件处理程序:
void OnDragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.None;
}
在此示例中,DragEventArgs
对象的 AcceptedOperation
属性设置为 DataPackageOperation.None
。 这样可确保在拖动源被放置到放置目标上时不执行任何操作。
处理数据包
在放置目标上释放拖动源时,就会触发 Drop
事件。 当发生这种情况时,如果拖动源被放置到以下控件上,Xamarin.Forms 就会自动尝试从数据包中检索数据:
- 文本控件。 可以将文本值放置到
CheckBox
、DatePicker
、Editor
、Entry
、Label
、RadioButton
、Switch
和TimePicker
对象上。 - 图像控件。 可以将图像放置到
Button
、Image
和ImageButton
控件上。
下表显示了当将基于文本的拖动源放置到文本控件上时设置的属性和尝试执行的任何转换:
控制 | 属性 | 转换 |
---|---|---|
CheckBox |
IsChecked |
string 转换为 bool 。 |
DatePicker |
Date |
string 转换为 DateTime 。 |
Editor |
Text |
|
Entry |
Text |
|
Label |
Text |
|
RadioButton |
IsChecked |
string 转换为 bool 。 |
Switch |
IsToggled |
string 转换为 bool 。 |
TimePicker |
Time |
string 转换为 TimeSpan 。 |
对于除文本和图像以外的内容,你需要自行处理数据包。
Drop
事件随附的 DropEventArgs
类定义了类型为 DataPackageView
的 Data
属性。 此属性表示数据包的只读版本。
检索图像或文本数据
使用 DataPackageView
类中定义的方法,可以在 Drop
事件的处理程序中从数据包中检索图像或文本数据。
DataPackageView
类包含 GetImageAsync
和 GetTextAsync
方法。 GetImageAsync
方法从数据包中检索存储在 DataPackage.Image
属性中的图像,并返回 Task<ImageSource>
。 同样,GetTextAsync
方法从数据包中检索存储在 DataPackage.Text
属性中的文本,并返回 Task<string>
。
下面的示例展示了从 Path
的数据包中检索文本的 Drop
事件处理程序:
async void OnDrop(object sender, DropEventArgs e)
{
string text = await e.Data.GetTextAsync();
// Perform logic to take action based on the text value.
}
在此示例中,文本数据是使用 GetTextAsync
方法从数据包中检索的。 然后,可以执行基于文本值的操作。
从属性包中检索数据
通过访问数据包的 Properties
集合,可以在 Drop
事件的处理程序中从数据包中检索任何数据。
DataPackageView
类定义了类型为 DataPackagePropertySetView
的 Properties
属性。 DataPackagePropertySetView
类表示存储为 Dictionary<string, object>
的只读属性包。
下面的示例展示了从 Rectangle
的数据包的属性包中检索数据的 Drop
事件处理程序:
void OnDrop(object sender, DropEventArgs e)
{
Square square = (Square)e.Data.Properties["Square"];
// Perform logic to take action based on retrieved value.
}
在此示例中,Square
对象是通过指定“Square”字典键从数据包的属性包中检索的。 然后,可以执行基于检索到的值的操作。