能够缩短 UIDragInteraction 的长按时间
Ability to shorten UIDragInteraction's long press timing
我目前正在使用 UIDragInteraction
和 UIDropInteraction
在 iOS 11 中可用来制作简单的拖放功能,用户可以将 UIImageView 拖到 UIView 上。
我意识到一个不直观的因素是 UIDragInteraction
需要长按至少一秒钟才能工作。我想知道是否有办法缩短长按时间? docs on Apple 似乎没有强调这一点。
谢谢!
下面粘贴的实现以供参考:
class ViewController: UIViewController {
@IBOutlet var imageView: UIImageView!
@IBOutlet var dropArea: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let dragInteraction = UIDragInteraction(delegate: self)
imageView.addInteraction(dragInteraction)
dragInteraction.isEnabled = true
let dropInteraction = UIDropInteraction(delegate: self)
dropArea.addInteraction(dropInteraction)
}
}
extension ViewController: UIDragInteractionDelegate {
func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
guard let image = imageView.image
else { return [] }
let itemProvider = NSItemProvider(object: image)
return [UIDragItem(itemProvider: itemProvider)]
}
}
extension ViewController: UIDropInteractionDelegate {
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
return UIDropProposal(operation: .copy)
}
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
guard let itemProvider = session.items.first?.itemProvider,
itemProvider.canLoadObject(ofClass: UIImage.self)
else { return }
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] loadedItem, error in
guard let image = loadedItem as? UIImage
else { return }
DispatchQueue.main.async {
self?.dropArea.image = image
}
}
}
}
没有明显的方法可以做到这一点,但我只是遇到了同样的问题并查看了 dragInteraction 附加到的视图的手势识别器。它是 _UIDragLiftGestureRecognizer
,它不是 public API 的一部分,但事实证明这只是 UILongPressGestureRecognizer
.
的子类
因此,在将您的 UIDragInteraction
添加到您的视图之后,将该视图添加到视图层次结构之后(因为我使用的是自定义 UIView 子类,所以我只是将它添加到 didMoveToSuperview()
),你可以这样做:
if let longPressRecognizer = gestureRecognizers?.compactMap({ [=10=] as? UILongPressGestureRecognizer}).first {
longPressRecognizer.minimumPressDuration = 0.1 // your custom value
}
我试图从 Xamarin.iOS 在实现 IUIDragInteractionDelegate
接口的 UIView
中执行此操作。在它的构造函数中,我创建了一个 SetupDragNDrop
方法,允许在没有默认 delay/latency 的情况下拖动视图来捕捉视图。我将代码留在下面,以防它对其他人有用:
#region Private Fields
private UIDragInteraction _UIDragInteraction;
#endregion
void Initialize()
{
SetupDragNDrop();
}
private void SetupDragNDrop()
{
UserInteractionEnabled = true;
_UIDragInteraction = new UIDragInteraction(this);
AddInteraction(_UIDragInteraction);
// On iPad, this defaults to true. On iPhone, this defaults to
// false. Since this app should work on the iPhone, enable the the
// drag interaction.
_UIDragInteraction.Enabled = true;
SetupDragDelay();
}
private void SetupDragDelay()
{
UILongPressGestureRecognizer longPressGesture = new UILongPressGestureRecognizer();
GestureRecognizers?.ToList().ForEach(gesture =>
{
var x = gesture as UILongPressGestureRecognizer;
if (x != null)
{
longPressGesture = x;
}
});
longPressGesture.MinimumPressDuration = 0.0;
}
您可以使用这段代码来避免影响其他手势:
let gestureRecognizers = self.view.gestureRecognizers?.compactMap({ [=10=] as? UILongPressGestureRecognizer })
let liftGesture = gestureRecognizers?.filter({ String(describing: type(of: [=10=])) == "_UIDragLiftGestureRecognizer" }).first
liftGesture?.minimumPressDuration = minimumPressDuration//use custom value
此外,这可以帮助自定义 SwiftUI onDrag
:
extension View {
public func customizeOnDrag(minimumPressDuration: TimeInterval) -> some View {
overlay(CustomizeOnDrag(minimumPressDuration: minimumPressDuration).frame(width: 0, height: 0))
}
}
private struct CustomizeOnDrag: UIViewControllerRepresentable {
private let minimumPressDuration: TimeInterval
init(minimumPressDuration: TimeInterval) {
self.minimumPressDuration = minimumPressDuration
}
func makeUIViewController(context: Context) -> UIViewControllerType {
return UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
DispatchQueue.main.async {
let gestureRecognizers = uiViewController.parent?.view.gestureRecognizers?.compactMap({ [=11=] as? UILongPressGestureRecognizer })
let liftGesture = gestureRecognizers?.filter({ String(describing: type(of: [=11=])) == "_UIDragLiftGestureRecognizer" }).first
liftGesture?.minimumPressDuration = minimumPressDuration
}
}
}
我目前正在使用 UIDragInteraction
和 UIDropInteraction
在 iOS 11 中可用来制作简单的拖放功能,用户可以将 UIImageView 拖到 UIView 上。
我意识到一个不直观的因素是 UIDragInteraction
需要长按至少一秒钟才能工作。我想知道是否有办法缩短长按时间? docs on Apple 似乎没有强调这一点。
谢谢!
下面粘贴的实现以供参考:
class ViewController: UIViewController {
@IBOutlet var imageView: UIImageView!
@IBOutlet var dropArea: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let dragInteraction = UIDragInteraction(delegate: self)
imageView.addInteraction(dragInteraction)
dragInteraction.isEnabled = true
let dropInteraction = UIDropInteraction(delegate: self)
dropArea.addInteraction(dropInteraction)
}
}
extension ViewController: UIDragInteractionDelegate {
func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
guard let image = imageView.image
else { return [] }
let itemProvider = NSItemProvider(object: image)
return [UIDragItem(itemProvider: itemProvider)]
}
}
extension ViewController: UIDropInteractionDelegate {
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
return UIDropProposal(operation: .copy)
}
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
guard let itemProvider = session.items.first?.itemProvider,
itemProvider.canLoadObject(ofClass: UIImage.self)
else { return }
itemProvider.loadObject(ofClass: UIImage.self) { [weak self] loadedItem, error in
guard let image = loadedItem as? UIImage
else { return }
DispatchQueue.main.async {
self?.dropArea.image = image
}
}
}
}
没有明显的方法可以做到这一点,但我只是遇到了同样的问题并查看了 dragInteraction 附加到的视图的手势识别器。它是 _UIDragLiftGestureRecognizer
,它不是 public API 的一部分,但事实证明这只是 UILongPressGestureRecognizer
.
因此,在将您的 UIDragInteraction
添加到您的视图之后,将该视图添加到视图层次结构之后(因为我使用的是自定义 UIView 子类,所以我只是将它添加到 didMoveToSuperview()
),你可以这样做:
if let longPressRecognizer = gestureRecognizers?.compactMap({ [=10=] as? UILongPressGestureRecognizer}).first {
longPressRecognizer.minimumPressDuration = 0.1 // your custom value
}
我试图从 Xamarin.iOS 在实现 IUIDragInteractionDelegate
接口的 UIView
中执行此操作。在它的构造函数中,我创建了一个 SetupDragNDrop
方法,允许在没有默认 delay/latency 的情况下拖动视图来捕捉视图。我将代码留在下面,以防它对其他人有用:
#region Private Fields
private UIDragInteraction _UIDragInteraction;
#endregion
void Initialize()
{
SetupDragNDrop();
}
private void SetupDragNDrop()
{
UserInteractionEnabled = true;
_UIDragInteraction = new UIDragInteraction(this);
AddInteraction(_UIDragInteraction);
// On iPad, this defaults to true. On iPhone, this defaults to
// false. Since this app should work on the iPhone, enable the the
// drag interaction.
_UIDragInteraction.Enabled = true;
SetupDragDelay();
}
private void SetupDragDelay()
{
UILongPressGestureRecognizer longPressGesture = new UILongPressGestureRecognizer();
GestureRecognizers?.ToList().ForEach(gesture =>
{
var x = gesture as UILongPressGestureRecognizer;
if (x != null)
{
longPressGesture = x;
}
});
longPressGesture.MinimumPressDuration = 0.0;
}
您可以使用这段代码来避免影响其他手势:
let gestureRecognizers = self.view.gestureRecognizers?.compactMap({ [=10=] as? UILongPressGestureRecognizer })
let liftGesture = gestureRecognizers?.filter({ String(describing: type(of: [=10=])) == "_UIDragLiftGestureRecognizer" }).first
liftGesture?.minimumPressDuration = minimumPressDuration//use custom value
此外,这可以帮助自定义 SwiftUI onDrag
:
extension View {
public func customizeOnDrag(minimumPressDuration: TimeInterval) -> some View {
overlay(CustomizeOnDrag(minimumPressDuration: minimumPressDuration).frame(width: 0, height: 0))
}
}
private struct CustomizeOnDrag: UIViewControllerRepresentable {
private let minimumPressDuration: TimeInterval
init(minimumPressDuration: TimeInterval) {
self.minimumPressDuration = minimumPressDuration
}
func makeUIViewController(context: Context) -> UIViewControllerType {
return UIViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
DispatchQueue.main.async {
let gestureRecognizers = uiViewController.parent?.view.gestureRecognizers?.compactMap({ [=11=] as? UILongPressGestureRecognizer })
let liftGesture = gestureRecognizers?.filter({ String(describing: type(of: [=11=])) == "_UIDragLiftGestureRecognizer" }).first
liftGesture?.minimumPressDuration = minimumPressDuration
}
}
}