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

iPhone/iOS: How to implement Drag and Drop for subviews of a Scrollview?

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

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


嗨,盖西,

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

您可以通过这种方式进行管理,当您当时在 scrollView 中触摸您的对象时,或者当您通过拖动来移动该对象时,禁用滚动 myScroll.scrollEnabled = NO;

然后当在 endTouch 上时,您可以通过 myScroll.scrollEnabled = YES; 启用滚动,因此您可以管理您的对象在滚动中移动,希望您有逻辑。

这里是演示代码:使用 ScrollView 拖放。与 touchesMoved: 上的 Disabling 滚动视图和 touchesEnded: 上的 Enabling 滚动视图具有相同的逻辑。


我之前确实实现了这种行为,没有任何子类化。

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

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

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


盖西,

尝试拖放对象的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
-(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;



    }
}

}

希望这段代码能帮到你。


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

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

或许能给点灵感


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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)。

我粘贴了这个,其他几个文件在粘贴箱中,包含以下内容:

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

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