// The offset animator's callback will update the `offset` state variable.
offsetAnimator.valueChanged = { newValue in
boxOffset = newValue
}
}
.offset(x: boxOffset.x, y: boxOffset.y)
.gesture(
DragGesture()
.onChanged { value in
// Update the animator's target to the new drag translation.
offsetAnimator.target = CGPoint(x: value.translation.width, y: value.translation.height)
// Don't animate the box's position when we're dragging it.
offsetAnimator.mode = .nonAnimated
offsetAnimator.start()
}
.onEnded { value in
// Animate the box to its original location (i.e. with zero translation).
offsetAnimator.target = .zero
// We want the box to animate to its original location, so use an `animated` mode.
// This is different than the
offsetAnimator.mode = .animated
// Take the velocity of the gesture, and give it to the animator.
// This makes the throw animation feel natural and continuous.
offsetAnimator.velocity = CGPoint(x: value.velocity.width, y: value.velocity.height)
offsetAnimator.start()
}
)`