diff --git a/src/content/cookbook/effects/drag-a-widget.md b/src/content/cookbook/effects/drag-a-widget.md index c34da22cc0..82d0523023 100644 --- a/src/content/cookbook/effects/drag-a-widget.md +++ b/src/content/cookbook/effects/drag-a-widget.md @@ -2,6 +2,7 @@ # title: Drag a UI element title: 创建一个可拖放的 UI 组件 description: How to implement a draggable UI element. +description: 如何实现一个可拖放的 UI 组件 js: - defer: true url: /assets/js/inject_dartpad.js @@ -19,8 +20,18 @@ where the user long presses on a choice of food, and then drags that food to the picture of the customer who is paying for it. +拖放是移动应用程序中的一种常见交互。 +当用户长按(有时称为“触摸并按住”)某个 widget 时, +另一个 widget 会出现在用户的手指下方, +用户可以将该 widget 拖动到最终位置并释放。 +在这个示例中,你将构建一个拖放交互, +用户可以长按一个食物选项, +然后将该食物拖动到正在为其付款的顾客图片上。 + The following animation shows the app's behavior: +下面的动画展示了应用程序的行为: + ![Ordering the food by dragging it to the person](/assets/images/docs/cookbook/effects/DragAUIElement.gif){:.site-mobile-screenshot} This recipe begins with a prebuilt list of menu items and @@ -28,8 +39,13 @@ a row of customers. The first step is to recognize a long press and display a draggable photo of a menu item. +本示例从一个预先构建的菜单项列表和一排顾客开始。 +第一步是识别长按操作并显示一个可拖动的菜单项图片。 + ## Press and drag +## 按压和拖动 + Flutter provides a widget called [`LongPressDraggable`][] that provides the exact behavior that you need to begin a drag-and-drop interaction. A `LongPressDraggable` @@ -39,9 +55,18 @@ As the user drags, the widget follows the user's finger. `LongPressDraggable` gives you full control over the widget that the user drags. +Flutter 提供了一个名为 [`LongPressDraggable`][] 的 widget, +它提供了开始拖放交互所需的确切行为。 +`LongPressDraggable` widget 能够识别长按操作, +然后在用户手指附近显示一个新 widget。 +当用户拖动时,该 widget 会跟随用户的手指移动。 +`LongPressDraggable` 让你完全控制用户拖动的 widget。 + Each menu list item is displayed with a custom `MenuListItem` widget. +每个菜单列表项都通过一个自定义的 `MenuListItem` widget 来显示。 + ```dart MenuListItem( @@ -53,6 +78,8 @@ MenuListItem( Wrap the `MenuListItem` widget with a `LongPressDraggable` widget. +用 `LongPressDraggable` widget 包裹 `MenuLIstItem` widget。 + ```dart LongPressDraggable( @@ -77,6 +104,10 @@ This `DraggingListItem` displays a photo of the selected food item, centered beneath the user's finger. +在这种情况下,当用户长按 `MenuListItem` widget 时, +`LongPressDraggable` widget 会显示一个 `DraggingListItem`。 +这个 `DraggingListItem` 会在用户手指下方居中显示所选的食物图片。 + The `dragAnchorStrategy` property is set to [`pointerDragAnchorStrategy`][]. This property value instructs `LongPressDraggable` @@ -84,6 +115,11 @@ to base the `DraggableListItem`'s position on the user's finger. As the user moves a finger, the `DraggableListItem` moves with it. +`dragAnchorStrategy` 属性设置为 [`pointerDragAnchorStrategy`][]。 +这个属性的值指示 `LongPressDraggable` +将 `DraggableListItem` 的位置基于用户的手指来定位。 +当用户移动手指时,`DraggableListItem` 也会跟随移动。 + Dragging and dropping is of little use if no information is transmitted when the item is dropped. For this reason, `LongPressDraggable` takes a `data` parameter. @@ -91,22 +127,42 @@ In this case, the type of `data` is `Item`, which holds information about the food menu item that the user pressed on. +如果拖放操作在释放时没有传递任何信息,那么它几乎没有什么用处。 +为此,`LongPressDraggable` 提供了一个 `data` 参数。 +在这种情况下,`data` 的类型是 `Item`, +它包含了用户按下的菜单项的食物信息。 + The `data` associated with a `LongPressDraggable` is sent to a special widget called `DragTarget`, where the user releases the drag gesture. You'll implement the drop behavior next. +与 `LongPressDraggable` 相关联的 `data` +会被传递到一个名为 `DragTarget` 的特殊 widget 上, +用户在此释放拖动手势。接下来你将实现拖放行为。 + ## Drop the draggable +## 放下可拖动组件 + The user can drop a `LongPressDraggable` wherever they choose, but dropping the draggable has no effect unless it's dropped on top of a `DragTarget`. When the user drops a draggable on top of a `DragTarget` widget, the `DragTarget` widget can either accept or reject the data from the draggable. +用户可以将 `LongPressDraggable` 放在任意位置, +但除非将其放在 `DragTarget` 之上, +否则拖放操作不会有任何效果。 +当用户将可拖动 widget 放在 `DragTarget` widget 上时, +`DragTarget` 可以选择接受或拒绝来自可拖动 widget 的数据。 + In this recipe, the user should drop a menu item on a `CustomerCart` widget to add the menu item to the user's cart. +在本示例中,用户应将菜单项拖放到 `CustomerCart` widget 上, +以将菜单项添加到用户的购物车中。 + ```dart CustomerCart( @@ -118,6 +174,8 @@ CustomerCart( Wrap the `CustomerCart` widget with a `DragTarget` widget. +用 `DragTarget` widget 包裹 `CustomCart` widget。 + ```dart DragTarget( @@ -143,6 +201,11 @@ when the user drags a draggable on top of the `DragTarget`. The `DragTarget` also recognizes when the user drops a draggable on top of the `DragTarget` widget. +`DragTarget` 显示你现有的 widget, +并与 `LongPressDraggable` 协调, +识别用户何时将可拖动的 widget 拖动到 `DragTarget` 之上。 +同时,`DragTarget` 也能识别用户何时在其上方放下一个可拖动 widget。 + When the user drags a draggable on the `DragTarget` widget, `candidateItems` contains the data items that the user is dragging. This draggable allows you to change what your widget looks @@ -151,6 +214,12 @@ the `Customer` widget turns red whenever any items are dragged above the `DragTarget` widget. The red visual appearance is configured with the `highlighted` property within the `CustomerCart` widget. +当用户将可拖动 widget 拖动到 `DragTarget` widget 上时, +`candidateItems` 包含用户正在拖动的数据项。 +你可以根据用户拖动的情况更改 widget 的外观。 +在本例中,`Customer` widget 在有项目拖动到 `DragTarget` widget 上方时会变成红色。 +这个红色的外观是通过 `CustomerCart` widget 中的 `highlighted` 属性配置的。 + When the user drops a draggable on the `DragTarget` widget, the `onAcceptWithDetails` callback is invoked. This is when you get to decide whether or not to accept the data that was dropped. @@ -158,23 +227,40 @@ In this case, the item is always accepted and processed. You might choose to inspect the incoming item to make a different decision. +当用户将可拖动 widget 放在 `DragTarget` widget 上时, +会调用 `onAcceptWithDetails` 回调。这时你可以决定是否接受拖放的数据。 +在示例中,项目总是会被接受和处理。 +你也可以选择检查传入的项目以做出不同的决定。 + Notice that the type of item dropped on `DragTarget` must match the type of the item dragged from `LongPressDraggable`. If the types are not compatible, then the `onAcceptWithDetails` method isn't invoked. +注意,拖放到 `DragTarget` 上的项目类型必须与从 `LongPressDraggable` 拖出的项目类型匹配。 +如果类型不兼容,`onAcceptWithDetails` 方法将不会被调用。 + With a `DragTarget` widget configured to accept your desired data, you can now transmit data from one part of your UI to another by dragging and dropping. +通过配置 `DragTarget` widget 来接受你所需的数据, +现在你可以通过拖放在 UI 的不同部分之间传递数据。 + In the next step, you update the customer's cart with the dropped menu item. +在下一步中,你将更新顾客的购物车,将放下的菜单项添加进去。 + ## Add a menu item to a cart +## 添加一个菜单项到购物车 + Each customer is represented by a `Customer` object, which maintains a cart of items and a price total. +每位顾客由一个 `Customer` 对象表示,该对象维护一个物品购物车和总价格。 + ```dart class Customer { @@ -199,9 +285,13 @@ class Customer { The `CustomerCart` widget displays the customer's photo, name, total, and item count based on a `Customer` instance. +`CustomerCart` widget 根据一个 `Customer` 实例显示顾客的照片、姓名、总价和物品数量。 + To update a customer's cart when a menu item is dropped, add the dropped item to the associated `Customer` object. +要在菜单项被拖放时更新顾客的购物车,需要将放下的物品添加到关联的 `Customer` 对象中。 + ```dart void _itemDroppedOnCustomerCart({ @@ -221,19 +311,40 @@ The `_itemDroppedOnCustomerCart` method is invoked in layout update, the UI refreshes with the new customer's price total and item count. +当用户将菜单项拖放到 `CustomerCart` widget 上时, +`onAcceptWithDetails()` 中会调用 `_itemDroppedOnCustomerCart` 方法。 +通过将放下的物品添加到 `customer` 对象中, +并调用 `setState()` 来触发布局更新, +UI 将会刷新,显示新的顾客总价和物品数量。 + Congratulations! You have a drag-and-drop interaction that adds food items to a customer's shopping cart. +恭喜!你现在已经实现了一个将食物项添加到顾客购物车的拖放交互。 + ## Interactive example +## 交互示例 + Run the app: +运行应用程序 + * Scroll through the food items. + + 浏览食物项列表。 + * Press and hold on one with your finger or click and hold with the mouse. + + 用手指长安其中一个食物项,或用鼠标点击并按住。 + * While holding, the food item's image will appear above the list. + + 按住时,食物项的图片将出现在列表上方。 + * Drag the image and drop it on one of the people at the bottom of the screen. The text under the image updates to @@ -241,6 +352,10 @@ Run the app: You can continue to add food items and watch the charges accumulate. + 将图片拖动并放到屏幕底部的某个人身上。 +图片下方的文本会更新,显示该人的费用。 +你可以继续添加食物项,观察费用的累积情况。 +