iOS:在UIImageViews之间移动图像

时间:2013-02-19 19:37:17

标签: ios

我有一个视图控制器,其中有一个默认的UIview放置在整个屏幕上。我在这个视图中添加了几个UIImageViews(比如大约20个)。我想支持在这些UIImageViews之间交换图像。我已经使用UITapGestureRecogniser来处理这些UIImageViews上发生的触摸。我可以在这个UITapGestureRecogniser事件本身下处理这些UIImageViews之间的图像拖放吗? (或)我是否需要使用UIPanGestureRecognizer或触摸事件?在这些UIImageViews之间实现图像拖放的最简单,最简单的方法是什么?请指教?

谢谢!

3 个答案:

答案 0 :(得分:3)

一些想法。

  1. 您可以通过点击手势实现此目的(例如,点按第一张图片视图,点按目标图片视图),但这不是很直观。使用UIPanGestureRecognizer进行适当的拖放对您的最终用户来说更为直观。

  2. 从技术上讲,您不是从图像视图中拖动图像,而是实际上是拖动图像视图本身。 (图像本身在没有图像视图的情况下没有可视化表示。)当你放开时,你将动画更改图像视图帧以完成幻觉。


  3. 如果你有imageViews的NSArray,你可以在他们的超级视图中添加一个手势:

    @property (nonatomic, strong) NSMutableArray *imageViews;
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        [self createImageViewArray];
    
        UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self
                                                                                  action:@selector(handlePan:)];
        [self.view addGestureRecognizer:gesture];
    }
    
    - (void)createImageViewArray
    {
        self.imageViews = [NSMutableArray array];
    
        // add your imageviews to the array any way you want
    
        ...
    }
    
    - (void)handlePan:(UIPanGestureRecognizer *)gesture
    {
        static UIImageView *draggedImage = nil;
        static CGRect draggedImageOriginalFrame;
    
        CGPoint location = [gesture locationInView:gesture.view];
    
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            // see if we grabbed an imageview
    
            draggedImage = [self determineImageForLocation:location];
    
            // if so, save its old location for future reference and bring it to the front
    
            if (draggedImage)
            {
                draggedImageOriginalFrame = draggedImage.frame;
                [draggedImage.superview bringSubviewToFront:draggedImage];
            }
        }
        else if (gesture.state == UIGestureRecognizerStateChanged && draggedImage != nil)
        {
            // if we're dragging it, then update its location 
    
            CGPoint translation = [gesture translationInView:gesture.view];
            CGRect frame = draggedImageOriginalFrame;
            frame.origin.x += translation.x;
            frame.origin.y += translation.y;
            draggedImage.frame = frame;
        }
        else if (draggedImage != nil && (gesture.state == UIGestureRecognizerStateEnded ||
                                         gesture.state == UIGestureRecognizerStateCancelled ||
                                         gesture.state == UIGestureRecognizerStateFailed))
        {
            // if we let go, let's see if we dropped it over another image view
    
            UIImageView *droppedOver = nil;
    
            if (gesture.state == UIGestureRecognizerStateEnded)
                droppedOver = [self draggedImageView:draggedImage toLocation:location];
    
            if (droppedOver == nil)
            {
                // fail; animate the restoring of the view back to it's original position
    
                [UIView animateWithDuration:0.25
                                 animations:^{
                                     draggedImage.frame = draggedImageOriginalFrame;
                                 }];
            }
            else
            {
                // succeed; make sure to bring the view we're about to animate to the front
    
                [droppedOver.superview bringSubviewToFront:droppedOver];
    
                // animate the swapping of the views
    
                [UIView animateWithDuration:0.25
                                 animations:^{
                                     draggedImage.frame = droppedOver.frame;
                                     droppedOver.frame = draggedImageOriginalFrame;
                                 }];
            }
        }
    }
    
    // see if we dragged an imageview over one of our imageviews, returning a point
    // to the image view we dropped it over
    
    - (UIImageView *)draggedImageView:(UIImageView *)draggedView toLocation:(CGPoint)location
    {
        for (UIImageView *imageview in self.imageViews)
            if (CGRectContainsPoint(imageview.frame, location) && imageview != draggedView)
                return imageview;
    
        return nil;
    }
    
    // see if we started the gesture over an imageview
    // (turns out that this is the same as "did we drag an image over another",
    // but as we're not dragging an image yet, just pass nil)
    
    - (UIImageView *)determineImageForLocation:(CGPoint)location
    {
        return [self draggedImageView:nil toLocation:location];
    }
    

答案 1 :(得分:2)

罗布的答案很棒。我稍微修改了他的handlePan方法以允许热交换图像。

hot swapping

- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
    static UIImageView *draggedImage = nil;
    static CGRect draggedImageLastFrame;

    CGPoint location = [gesture locationInView:gesture.view];

    if (gesture.state == UIGestureRecognizerStateBegan) {

        // see if we grabbed an imageview

        draggedImage = [self determineImageForLocation:location];

        // if so, save its old location for future reference and bring it to the front

        if (draggedImage) {
            draggedImageLastFrame = draggedImage.frame;
            [draggedImage.superview bringSubviewToFront:draggedImage];
            draggedImage.alpha = 0.6f;
        }

    } else if (gesture.state == UIGestureRecognizerStateChanged && draggedImage != nil) {

        // if we're dragging it, then update its horizontal location

        CGPoint translation = [gesture translationInView:gesture.view];
        CGRect frame = draggedImage.frame;
        frame.origin.x += translation.x;
        draggedImage.frame = frame;
        [gesture setTranslation:CGPointZero inView:gesture.view];

        UIImageView *draggedOver = [self draggedImageView:draggedImage toLocation:location];
        if (draggedOver != nil) {

            // animate the draggedOver image to the the draggedImage's last location

            [UIView animateWithDuration:0.25
                             animations:^{
                                 CGRect currentFrame = draggedOver.frame;
                                 draggedOver.frame = draggedImageLastFrame;
                                 draggedImageLastFrame = currentFrame;
                             }];
        }

    } else if (draggedImage != nil && (gesture.state == UIGestureRecognizerStateEnded ||
                                       gesture.state == UIGestureRecognizerStateCancelled ||
                                       gesture.state == UIGestureRecognizerStateFailed)) {

        // finished, animate the draggedImage into place

        [UIView animateWithDuration:0.25
                         animations:^{
                             draggedImage.frame = draggedImageLastFrame;
                             draggedImage.alpha = 1.0f;
                         }];
    }
}

答案 2 :(得分:0)

事实上,根本不要使用轻击手势。

秘诀是使用imageView的超级视图。

你需要3个图像视图......

UIImageView *ImageViewA

UIImageView *ImageViewB

UIImageView *DraggableImageView

假设您单击屏幕并且主机视图获取touchesBegan事件...如果您使用ImageViewA并使用以下方法测试它的rect:

[rect containsPoint:touchPoint];

如果这是真的并且您已成功触摸第一个imageView ...在touchesMoved中开始拖动操作,如下所示:

如果您使用ImageViewA.superview,您将获得视图的主机视图...主机视图应该接收以下命令:

[newDraggableImageView setFrame:ImageViewA.frame];
[newDraggableImageView setImage:ImageViewA.image];
[hostView addSubview:newDraggableImageView];

现在您使用UIResponder方法跟踪主机视图上的触摸事件touchesBegain touchesMoved和touchesEnded

当你浏览touchesMoved:将运动的坐标发送到newDraggableImageView的框架中......

因为它正在拖动...一个touchesEnded方法:

如果图像的帧位于第二个拖动点的帧内,则可以设置最终的图像视图

if ([frame containsRect:anotherFrame])
    ImageViewB.image = draggableImageView.image;

对不起,这是伪代码...希望你理解逻辑流程...将图像添加到主机视图...或应用程序的窗口视图并移动它...一旦移动结束..test对于imageView的位置并适当地设置新的图像视图......

古德纳克!和快乐的编码!