iPhone/iOS:如何为 Scrollview 的子视图实现拖放?

Posted

技术标签:

【中文标题】iPhone/iOS:如何为 Scrollview 的子视图实现拖放?【英文标题】:iPhone/iOS: How to implement Drag and Drop for subviews of a Scrollview? 【发布时间】:2012-03-31 17:11:16 【问题描述】:

我在UIViewController 中有一个水平滚动视图,其中有许多小尺寸的图像。我将图像保留在滚动视图中,因为图像更多,因此用户可以水平滚动并选择图像。但是,问题是,我必须选择一个图像并拖放到该UIViewController 视图。但是,由于图像在滚动视图中,将图像拖放到UIViewcontroller 的视图中不起作用,也没有检测到触摸事件。 请注意:如果我没有滚动视图,但只是将图像也保留在UIViewcontroller 的视图中,将图像拖放到同一屏幕上,效果很好。

当我需要滚动视图和拖放图像时,我该如何解决这个问题,请提供任何建议/帮助?

【问题讨论】:

试试我的答案,我已经完全按照你的要求实现了。 【参考方案1】:

嗨,盖西,

我不会直接向您提供代码,但会告诉您如何管理它。

您可以通过这种方式进行管理,当您当时在 scrollView 中触摸您的对象时,或者当您通过拖动来移动该对象时,通过 myScroll.scrollEnabled = NO; 禁用滚动 然后当在 endTouch 上时,您可以通过 myScroll.scrollEnabled = YES; 启用滚动,因此您可以管理您的对象在滚动中移动,希望您有逻辑。

这里是演示代码:Drag and Drop with ScrollView。与Disabling touchesMoved: 上的滚动视图和Enabling touchesEnded: 上的滚动视图具有相同的逻辑。

【讨论】:

【参考方案2】:

我之前确实在没有任何子类化的情况下实现了该行为。

我使用了canCancelContentTouches = NO 中的canCancelContentTouches = NO 来确保子视图自己处理那里的触摸。如果触摸了子视图(在您的情况下为图像),我将视图从滚动视图移到超级视图上并开始跟踪它的拖动。 (您必须在新的超级视图中计算正确的坐标,使其保持原位)。

拖动完成后,我检查是否到达目标区域,否则我将其移回滚动视图。如果这还不够详细,我可以发布一些代码。

这是我的示例代码:Github: JDDroppableView

【讨论】:

我添加了示例代码,如何实现在滚动视图内拖出。 您的示例链接无效,您可以在我的邮件 ID 上发送此代码吗?我的邮件 ID 是 mohit27bisht@gmail.com【参考方案3】:

盖西,

尝试拖放对象的代码:

-(void)dragAndDropWithGesture 

UILongPressGestureRecognizer *downwardGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(dragGestureChanged:)];
[scrollViewAlfabeto addGestureRecognizer:downwardGesture];
    for (UIGestureRecognizer *gestureRecognizer in myscrollView.gestureRecognizers)
    
       [gestureRecognizer requireGestureRecognizerToFail:downwardGesture];
    


- (void) dragGestureChanged:(UIPanGestureRecognizer*)gesture

CGPoint point = [gesture locationInView:scrollViewAlfabeto];

if (gesture.state == UIGestureRecognizerStateBegan) 


    [imageViewToMove removeFromSuperview];
    [self.view addSubview:imageViewToMove];

    UIView *draggedView = [myscrollView hitTest:point withEvent:nil];
    if ([draggedView isKindOfClass:[UIImageView class]])
    
        imageViewToMove = (UIImageView*)draggedView;
    

else if (gesture.state == UIGestureRecognizerStateChanged)

    imageToMove.center = point;

else if (gesture.state == UIGestureRecognizerStateEnded     ||
         gesture.state == UIGestureRecognizerStateCancelled ||
         gesture.state == UIGestureRecognizerStateFailed)

    // Determine if dragged view is in an OK drop zone
    // If so, then do the drop action, if not, return it to original location

    NSLog(@"point.x final:%f", point.x);
    NSLog(@"point.y final:%f", point.y);

    if (CGRectContainsPoint(goal.frame, point))
        imageToMove.frame = CGRectMake(167, 159, 100, 100);
    

    else

        [imageToMove removeFromSuperview];
        [myscrollView addSubview:imageToMove];
        [imageToMove setFrame:CGRectMake(12, 38, 100, 100)];
        imageToMove = nil;



    



希望这段代码能帮到你。

【讨论】:

你为什么使用 UILongPressGestureRecognizer 而不是 UIPanGestureRecognizer ?【参考方案4】:

对于类似的问题,我创建了 UIScrollView 子类,如下所示:PoliteScrollView 在确定它们正在被拖动时将触摸消息传递给它的子视图。

@interface PoliteScrollView : UIScrollView

// number of pixels perpendicular to the scroll views orientation to make a drag start counting as a subview drag
// defaults to 1/10 of the scroll view's width or height, whichever is smaller
@property(nonatomic,assign) CGFloat subviewDraggingThreshold;
// yes when a subview is being dragged
@property(nonatomic,assign) BOOL isDraggingSubview;
// the subview being dragged
@property(nonatomic,strong) UIView *draggingSubview;

@end

@protocol PoliteScrollViewDelegate <NSObject>
@optional
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesBegan:(NSSet *)touches;
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesMoved:(NSSet *)touches;
- (void)scrollView:(PoliteScrollView *)scrollView subviewTouchesEnded:(NSSet *)touches;
@end

关键的设计理念是在滚动视图中拖动是不明确的。用户是滚动还是拖动子视图? PoliteScroll 视图通过提供两件事来处理这个问题:(1) 方向的概念(如果它长于宽度,则为水平,否则为垂直),以及 (2) 在垂直于它的方向的方向上构成拖动的阈值距离。 (默认为宽度或高度的 1/10)。

我把这个和其他几个文件粘贴在paste bin 中,包含以下内容:

PoliteScrollView .h 和 .m DraggableImageView.h 和 .m - 当它收到触摸消息时会改变它的位置。 ViewController.m - 演示两者的结合。

要将这些组合到项目中,请将粘贴箱粘贴到适当命名的文件中,添加带有 PoliteScrollView 的故事板(确保将其设置为委托),添加一些图像(ViewController 尝试将uppuppy0.jpeg 添加到puppy4. JPEG。

【讨论】:

【参考方案5】:

我创建了一个示例来说明如何在两个或多个视图之间拖放: http://www.ancientprogramming.com/2012/04/05/drag-and-drop-between-multiple-uiviews-in-ios/

我发现将手势识别器注册到与被拖动的实际视图不同的视图是一个好主意。这将确保即使拖动的视图更改其“父”视图,手势也会继续。

或许能给点灵感

【讨论】:

以上是关于iPhone/iOS:如何为 Scrollview 的子视图实现拖放?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 ScrollView 设置图像而不是淡化边缘?

如何为 UIScrollView 启用方向锁定?

当设备旋转时,如何为视图设置正确的边界?

iPhone iOS如何在启用缩放时使UIScrollView与UIRotationGestureRecognizer一起工作?

iPhone iOS8:从 iOS7.1 sdk 构建并在 8.0 及更高版本的设备上运行时,UIAlertView 倒置旋转无法正常工作

iPhone iOS在呈现图表时如何处理Core Data中的时间间隔?