iOS (iPad) 在 UISplitViewController 中拖放

Posted

技术标签:

【中文标题】iOS (iPad) 在 UISplitViewController 中拖放【英文标题】:iOS (iPad) Drag & Drop in a UISplitViewController 【发布时间】:2012-01-04 06:32:38 【问题描述】:

我正在 UISplitViewController(基于 Xcode 模板项目)中进行 D&D,从 MasterViewController 到 DetailViewController。

基本上,我正在做的是创建一个 UILongPressGestureRecognizer 并将其放置在 MasterViewController 的 self.tableview 属性上。

下面是我的手势识别器。

- (void)gestureHandler:(UIGestureRecognizer*)gesture

    CGPoint location;
    NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:[gesture locationInView:self.tableView]];
    if (gesture.state == UIGestureRecognizerStateBegan) 
        // Create draggable view
        NSString* imageCanvasName = [self imageNameByIndexPath:indexPath isDetail:YES];
        UIImage* imageCanvas = [UIImage imageNamed:imageCanvasName];
        _draggedView = [[UIImageView alloc] initWithImage:imageCanvas];

        // Create drag-feedback window, add the drag-view and make the drag-window visible
        CGRect windowFrame = self.view.window.frame;
        _dragFeedbackWindow = [[UIWindow alloc] initWithFrame:windowFrame];
        location = [gesture locationInView:gesture.view.window];
        [_draggedView setCenter:location];
        [_dragFeedbackWindow addSubview:_draggedView];
        [_dragFeedbackWindow setHidden:NO];     
    
    else if (gesture.state == UIGestureRecognizerStateChanged) 
        // Update drag-view location
        location = [gesture locationInView:gesture.view.window];
        [_draggedView setCenter:location];
    
    else if (gesture.state == UIGestureRecognizerStateEnded)
    
        // Disconnect drag-view and hide drag-feedback window
        [_draggedView removeFromSuperview];     
        [_dragFeedbackWindow setHidden:YES];

        // If drop is in a valid location...
        if ([self.tableView pointInside:_draggedView.center withEvent:nil] == NO)
        
            // Get final location in detailViewController coordinates
            location = [gesture locationInView:self.detailViewController.view];
            [_draggedView setCenter:location];
            [self.detailViewController.view addSubview:_draggedView];
        
    
    else 
        NSLog(@"%s unrecognized gesture %d", __FUNCTION__, gesture.state);
    

当 iPad 处于纵向模式时,一切都非常好 - 拖放 - 工作正常。

如果 iPad 旋转,我的问题就开始了…… 在这种情况下,我的 _draggedView 会出现“反向旋转”——它会“反映”iPad 的旋转——直到掉落。

就像我必须对 _dragFeedbackWindow 应用一些旋转 - 但我尝试了很多东西,但都失败了......

有什么想法吗?

谢谢!

【问题讨论】:

【参考方案1】:

好的 - 我想出了“为什么”会发生这种情况,以及“如何”进行修复(并将附加处理程序代码以正确执行此操作,如下所示。

这是代码...“只需”将其添加到您的 MAsterViewController 中(如果 - 像我一样 - 您想从 master 拖到 detail...)

// A simple UIView extension to rotate it to a given orientation
@interface UIView(oriented)
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation;
@end

@implementation UIView(oriented)
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation 
    CGFloat angle = 0.0;    
    switch (orientation)  
        case UIInterfaceOrientationPortraitUpsideDown:
            angle = M_PI; 
            break;
        case UIInterfaceOrientationLandscapeLeft:
            angle = - M_PI / 2.0f;
            break;
        case UIInterfaceOrientationLandscapeRight:
            angle = M_PI / 2.0f;
            break;
        default: // as UIInterfaceOrientationPortrait
            angle = 0.0;
            break;
     

    self.transform = CGAffineTransformMakeRotation(angle);

现在,LongPress 手势处理程序...

- (void)gestureHandler:(UIGestureRecognizer*)gesture

    CGPoint location;
    UIWindow* dragFeedback = [UIApplication sharedApplication].delegate.window;
    if (gesture.state == UIGestureRecognizerStateBegan) 
        // Create draggable view
        _draggedView = [[UIImageView alloc] initWithImage:@"someImage.png"];

        // Required to adapt orientation... WORKS, BUT WHY NEEDED???
        [_draggedView rotateToOrientation:[[UIApplication sharedApplication] statusBarOrientation]];

        // Create drag-feedback window, add the drag-view and make the drag-window visible
        location = [gesture locationInView:dragFeedback];
        [_draggedView setCenter:location];
        [dragFeedback addSubview:_draggedView];
    
    else if (gesture.state == UIGestureRecognizerStateChanged) 
        // Update drag-view location
        location = [gesture locationInView:dragFeedback];
        [_draggedView setCenter:location];
    
    else if (gesture.state == UIGestureRecognizerStateEnded)
    
        // Disconnect drag-view and hide drag-feedback window
        [_draggedView removeFromSuperview];     

        // Get final location in detailViewController coordinates
        location = [gesture locationInView:self.detailViewController.view];
        [_draggedView setCenter:location];
        // "Noramlize" orientation... WORKS, BUT WHY NEEDED???
        [_draggedView rotateToOrientation:UIInterfaceOrientationPortrait];
        [self.detailViewController.view addSubview:_draggedView];
    
    else 
        NSLog(@"%s unrecognized gesture %d", __FUNCTION__, gesture.state);
    

这就像一个魅力 - 让我知道它是如何为你工作的(如果你需要一个示例项目,请告诉我......)

【讨论】:

嗨鲁文,我也有同样的要求。能否请您分享一个示例项目。谢谢。 当然。我需要一天的时间来清理。 非常感谢。让我看看。 嗨鲁文,它正在工作。触摸图像后,我不得不将手指放在图像上多一点时间!非常感谢你。这是一个了不起的例子! @AppleDeveloper,基本上,这个示例展示了从 Drag-Zone 拖动一个对象(其中一个)。到目前为止,你还好 - 这在你需要的范围内。下一部分是决定(在“放下”被拖动对象的拖动期间)Drop-Zone(我的示例中的 self.detailViewController)是否“愿意”接受“被拖动”对象。一个足够简单的解决方案是在 self.detailViewController 中添加一个方法“canAcceptObject:draggedObject”,测试它是否“愿意”接受拖动(意思是“它是否是特定问题的正确答案”)。有意义吗?【参考方案2】:

感谢您的解决方案!你让我走了 90% 的路。在付款时,我会给你最后的 10% :)

问题似乎在于 UIWindow 永远不会旋转,只有它的子视图会旋转!所以解决方案是使用子视图。

我还添加了一些代码来显示如何查看选择了哪个单元格(假设您的主视图是 UITableViewController)。

- (IBAction)handleGesture:(UIGestureRecognizer *)gesture
    
        CGPoint location;
        UIWindow *window = [UIApplication sharedApplication].delegate.window;

        //The window doesn't seem to rotate, so we'll get the subview, which does!
        UIView *dragFeedback = [window.subviews objectAtIndex:0];
        if (gesture.state == UIGestureRecognizerStateBegan) 
            location = [gesture locationInView:dragFeedback];

            //which cell are we performing the long hold over?
            NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:[gesture locationInView:self.tableView]];
            UITableViewCell *selecteCell = [self.tableView cellForRowAtIndexPath:indexPath];
            NSLog(@"Cell %@", selecteCell);

            // Create draggable view
            _draggedView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImage.png"]];

            // Create drag-feedback window, add the drag-view and make the drag-window visible
            [_draggedView setCenter:location];
            [dragFeedback addSubview:_draggedView];
        
        else if (gesture.state == UIGestureRecognizerStateChanged) 
            // Update drag-view location
            location = [gesture locationInView:dragFeedback];
            [_draggedView setCenter:location];
        
        else if (gesture.state == UIGestureRecognizerStateEnded)
        
            // Disconnect drag-view and hide drag-feedback window
            [_draggedView removeFromSuperview];    

            // Get final location in detailViewController coordinates
            location = [gesture locationInView:self.detailViewController.view];
            [_draggedView setCenter:location];
            [self.detailViewController.view addSubview:_draggedView];
        
        else 
            NSLog(@"%s unrecognized gesture %d", __FUNCTION__, gesture.state);
        
    

【讨论】:

RefuX,虽然您的更改“清除”了手动旋转的需要,但它不再提供拖动菜单“顶部”的视觉反馈...请参阅我发布的示例:box.com/s/p7exfvxcvzgneo97d1of Ahhh.. 我从未在纵向模式下测试过 :) 是的,我认为要超越弹出窗口,您必须在 UIWindow 上绘制。我做了一些更多的研究并确认:“窗口本身实际上并没有改变坐标系,它对其子视图应用了变换来改变它们的坐标系。”所以至少现在一切都说得通了? :) 当然可以。感谢您的确认。

以上是关于iOS (iPad) 在 UISplitViewController 中拖放的主要内容,如果未能解决你的问题,请参考以下文章

iOS (iPad) 在 UISplitViewController 中拖放

Ipad图标大小Ipad设置ios 5-7 29pt 1x 2x - iPad聚光灯ios 7 40 pt - iPad app ios 7 76 pt [关闭]

图像不显示在带有 iOS 9 的 iPad 2 模拟器上

iOS 7 onchange 事件在 iPad 3+Mini 中被破坏 // 需要解决

如何在 iOS 中调整 iPad 的字体大小? (冲突元素)

iOS 关屏 iPad