简体   繁体   English

iOS:TapGestureRecognizer 问题

[英]iOS: TapGestureRecognizer Issues

So I have an app that behaves like a photo gallery and I'm implementing the ability for the user to delete the images.所以我有一个行为类似于照片库的应用程序,并且我正在实现用户删除图像的功能。 Here is the setup: I have 9 UIImageViews, imageView, imageView2, etc. I also have an "Edit" button, and a tapGesture action method.这是设置:我有 9 个 UIImageView、imageView、imageView2 等。我还有一个“编辑”按钮和一个 tapGesture 操作方法。 I dragged a Tap Gesture Recognizer over onto my view in IB, and attached it to each one of the UIImageViews.我将 Tap Gesture Recognizer 拖到我在 IB 中的视图上,并将其附加到每个 UIImageView。 I also attached the tapGesture action method to each of the UIImageViews.我还将 tapGesture 操作方法附加到每个 UIImageView。 Ideally, I would like the method to only become active when the "Edit" button is pressed.理想情况下,我希望该方法仅在按下“编辑”按钮时才激活。 When the user taps Edit, then taps on the picture they want to delete, I would like a UIAlertView to appear, asking if they are sure they want to delete it.当用户点击编辑,然后点击他们要删除的图片时,我希望出现一个 UIAlertView,询问他们是否确定要删除它。 Here is the code I'm using:这是我正在使用的代码:

- (IBAction)editButtonPressed:(id)sender {
    editButton.hidden = YES;
    backToGalleryButton.hidden = NO;
    tapToDeleteLabel.hidden = NO;
}

- (IBAction)tapGesture:(UITapGestureRecognizer*)gesture
{

    UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:@"Delete"
                                                              message:@"Are you sure you want to delete this photo?"
                                                             delegate:self
                                                    cancelButtonTitle:@"No"
                                                    otherButtonTitles:@"Yes", nil];
    [deleteAlertView show];

    if (buttonIndex != [alertView cancelButtonIndex]) {

        UIImageView *view = [self.UIImageView];
        if (view) {
            [self.array removeObject:view];
        }


        CGPoint tapLocation = [gesture locationInView: self.view];
        for (UIImageView *imageView in self.view.subviews) {
            if (CGRectContainsPoint(self.UIImageView.frame, tapLocation)) {
                ((UIImageView *)[self.view]).image =nil;
 }

}
        [self.user setObject:self.array forKey:@"images"];
}
}

This code is obviously riddled with errors: "Use of undeclared identifier button index" on this line: if (buttonIndex != [alertView cancelButtonIndex])这段代码显然充满了错误:“使用未声明的标识符按钮索引”这一行: if (buttonIndex != [alertView cancelButtonIndex])

"Property UIImageView not found on object of type PhotoViewController" on this line UIImageView *view = [self.UIImageView]; “属性 UIImageView 在类型 PhotoViewController 的 object 上找不到”这一行UIImageView *view = [self.UIImageView];

And "Expected identifier" on this line ((UIImageView *)[self.view]).image =nil;以及这一行的“预期标识符” ((UIImageView *)[self.view]).image =nil;

I'm very new to programming, and I'm surprised that I even made it this far.我对编程很陌生,我很惊讶我能做到这一点。 So, I'm just trying to figure out how I need to edit my code so that the errors go away, and that it can be used whenever one of the 9 image views is tapped, and also so that this method only fires when the Edit button is pushed first.所以,我只是想弄清楚我需要如何编辑我的代码,以便消除错误 go,并且只要点击 9 个图像视图之一就可以使用它,并且只有在首先按下编辑按钮。 I was using tags earlier, and it worked great, but I save the images via NSData, so I can't use tags anymore.我之前使用过标签,效果很好,但我通过 NSData 保存图像,所以我不能再使用标签了。 Any help is much appreciated, thanks!非常感谢任何帮助,谢谢!

First, you don't want to attach the tap gesture to the image views.首先,您不想将点击手势附加到图像视图。 Also, if you are going to have more than 9 images, you may want a scroll view, or handle scrolling separately.此外,如果您要拥有超过 9 张图像,您可能需要滚动视图,或单独处理滚动。 First, remove that gesture recognizer and all its connections.首先,删除该手势识别器及其所有连接。

Next, determine what type of view you will use as your gallery canvas. A simple View, or a ScrollView, or whatever... it doesn't really matter right now, just to get it working.接下来,确定您将使用哪种类型的视图作为您的图库 canvas。一个简单的视图,或一个滚动视图,或任何...现在并不重要,只是让它工作。 You want to ctrl-drag that view into your interface definition, so it drops an IBOutlet for the view (that way you can reference it in code).您想要将该视图按住 trl 并拖动到您的接口定义中,因此它会为该视图删除一个 IBOutlet(这样您就可以在代码中引用它)。

You will place your ImageViews onto the view I just mentioned.您将把您的 ImageView 放到我刚才提到的视图上。

You can have an internal flag for the gesture recognizer, but it also has a property that use can enable/disable it whenever you want.您可以为手势识别器设置一个内部标志,但它也有一个属性,您可以随时启用/禁用它。 Thus, you can have it active/inactive fairly easily.因此,您可以很容易地使其处于活动/非活动状态。

All you want to do is drop a single tap-gesture-recognizer onto your controller, and connect it to the implementation section of the controller. It will generate a stub for handling the recognizer.您要做的就是将单个点击手势识别器放到您的 controller 上,并将其连接到 controller 的实现部分。它将生成一个用于处理识别器的存根。 It will interpret taps "generally" for the controller, and call your code whenever a tap is made on the view.它将“一般”解释 controller 的点击,并在视图上进行点击时调用您的代码。

Some more code...一些更多的代码...

Creates a frame for the "new" image in the scroll view.在滚动视图中为“新”图像创建一个框架。

- (CGRect)frameForData:(MyData*)data atIndex:(NSUInteger)idx
{
    CGPoint topLeft;
    int row = idx / 4;
    int col = idx % 4;
    topLeft.x = (col+1)*HORIZ_SPACING + THUMBNAIL_WIDTH * (col);
    topLeft.y = (row+1)*VERT_SPACING + THUMBNAIL_HEIGHT * (row);
    return CGRectMake(topLeft.x, topLeft.y, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
}

Creates an image view for each piece of metadata, and a small border.为每个元数据和一个小边框创建一个图像视图。

- (UIImageView*)createImageViewFor:(MetaData*)metadata
{
    UIImageView *imageView = [[UIImageView alloc] initWithImage:metadata.lastImage];
    imageView.frame = CGRectMake(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);;
    imageView.layer.borderColor = [[UIColor blackColor] CGColor];
    imageView.layer.borderWidth = 2.0;
    imageView.userInteractionEnabled = YES;
    return imageView;
}

This is where the views are created and added to the parent...这是创建视图并将其添加到父视图的地方...

    imageView = [self createImageViewFor:metadata];
    //[data.imageView sizeToFit];

    // Make sure the scrollView contentSize represents the data
    CGRect lastFrame = [self frameForData:data atIndex:self.data.count-1];
    CGFloat newHeight = lastFrame.origin.y + lastFrame.size.height;
    if (self.bookshelfScrollView.contentSize.height < newHeight) {
        CGSize newSize = self.bookshelfScrollView.contentSize;
        newSize.height = newHeight;
        self.bookshelfScrollView.contentSize = newSize;
    }
    [self.bookshelfScrollView addSubview:data.imageView];

So, you just create each frame, add them to the view, and the only thing you have to do is enable user interaction on them, because otherwise the scroll view does not allow the gesture through.因此,您只需创建每个框架,将它们添加到视图中,您唯一需要做的就是在它们上启用用户交互,否则滚动视图将不允许手势通过。

OK... Looking at the code you posted... since you didn't say what was wrong with it... hard to say... The below is your code... My comments are, well, Comments...好的...查看您发布的代码...因为您没有说它有什么问题...很难说...下面是您的代码...我的评论是,好吧,评论.. .

- (IBAction)editButtonPressed:(id)sender {
    editButton.hidden = YES;
    backToGalleryButton.hidden = NO;
    tapToDeleteLabel.hidden = NO;
}
- (IBAction)tapGesture:(UITapGestureRecognizer*)gesture
{
    // I don't think I'd do this here, but it shouldn't cause "problems."
    UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:@"Delete"
                                                              message:@"Are you sure you want to delete this photo?"
                                                             delegate:self
                                                    cancelButtonTitle:@"No"
                                                    otherButtonTitles:@"Yes", nil];
    [deleteAlertView show];

    // In your controller, you have the main view, which is the view
    // on which you added your UIViews.  You need that view.  Add it as an IBOutlet
    // You should know how to do that...  ctrl-drag to the class INTERFACE source.
    // Assuming you name it "galleryView"

    // Take the tap location from the gesture, and make sure it is in the
    // coordinate space of the view.  Loop through all the imageViews and
    // find the one that contains the point where the finger was taped.
    // Then, "remove" that one from its superview...
    CGPoint tapLocation = [gesture locationInView: self.galleryView];
    for (UIImageView *imageView in self.galleryView.subviews) {
        if (CGRectContainsPoint(imageView.frame, tapLocation)) {
            [imageView removeFromSuperview];
        }
    }
}

Personally, in my little photo gallery, I bypassed all of the gesture recognizer stuff by replacing the UIImageView controls with UIButton controls, setting the image property for the button like you would for the UIImageView .就个人而言,在我的小照片库中,我通过将UIImageView控件替换为UIButton控件来绕过所有手势识别器,像为UIImageView一样设置按钮的图像属性。 It looks identical, but then you get the functionality of tapping on a thumbnail for free, with no gestures needed at all.它看起来一模一样,但是你可以免费获得点击缩略图的功能,根本不需要任何手势。

So, my view just has a UIScrollView , which which I programmatically add my images as buttons with the image set for the button control, eg:因此,我的视图只有一个UIScrollView ,我以编程方式将我的图像添加为按钮,并为按钮控件设置图像,例如:

- (void)loadImages
{
    listOfImages = [ImageData newArrayOfImagesForGallery:nil];

    // some variables to control where I put my thumbnails (which happen to be 76 x 76px)

    int const imageWidth = 76;
    int const imageHeight = imageWidth;
    NSInteger imagesPerRow;
    NSInteger imagePadding;
    NSInteger cellWidth;
    NSInteger cellHeight;

    // some variables to keep track of where I am as I load in my images

    int row = 0;
    int column = 0;
    int index = 0;

    // add images to navigation bar

    for (ImageData *item in listOfImages)
    {
        // figure out what row and column I'm on

        imagesPerRow = self.view.frame.size.width / (imageWidth + 2);
        imagePadding = (self.view.frame.size.width - imageWidth*imagesPerRow) / (imagesPerRow + 1);
        cellWidth = imageWidth + imagePadding;
        cellHeight = imageHeight + imagePadding;

        // this is how I happen to grab my UIImage ... this will vary by implementation

        UIImage *thumb = [item imageThumbnail];

        // assuming I found it...

        if (thumb)
        {
            // create my button and put my thumbnail image in it

            UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
            button.frame = CGRectMake(column * cellWidth  + imagePadding, 
                                      row    * cellHeight + imagePadding, 
                                      imageWidth, 
                                      imageHeight);
            [button setImage:thumb forState:UIControlStateNormal];
            [button addTarget:self
                       action:@selector(buttonClicked:)
             forControlEvents:UIControlEventTouchUpInside];
            button.tag = index++;
            [[button imageView] setContentMode:UIViewContentModeScaleAspectFit];

            // add it to my view

            [scrollView addSubview:button];

            // increment my column (and if necessary row) counters, making my scrollview larger if I need to)

            if (++column == imagesPerRow) 
            {
                column = 0;
                row++;
                [scrollView setContentSize:CGSizeMake(self.view.frame.size.width, (row+1) * cellHeight + imagePadding)];
            }
        }
    }
}

// I also have this in case the user changes orientation, so I'll move my images around if I need to

- (void)rearrangeImages
{
    if (!listOfImages)
    {
        [self loadImages];
        return;
    }

    // a few varibles to keep track of where I am

    int const imageWidth = 76;
    int const imagesPerRow = self.view.frame.size.width / (imageWidth + 2);
    int const imageHeight = imageWidth;
    int const imagePadding = (self.view.frame.size.width - imageWidth*imagesPerRow) / (imagesPerRow + 1);
    int const cellWidth = imageWidth + imagePadding;
    int const cellHeight = imageHeight + imagePadding;

    NSArray *buttons = [[NSArray alloc] initWithArray:[scrollView subviews]];

    int row;
    int column;
    int index;

    CGRect newFrame;

    // iterate through the buttons

    for (UIView *button in buttons)
    {
        index = [button tag];

        if ([button isKindOfClass:[UIButton class]] && index < [listOfImages count])
        {
            // figure out where the button should go

            row = floor(index / imagesPerRow);
            column = index % imagesPerRow;
            newFrame = CGRectMake(column * cellWidth  + imagePadding, 
                                  row    * cellHeight + imagePadding, 
                                  imageWidth, 
                                  imageHeight);

            // if we need to move it, then animation the moving

            if (button.frame.origin.x != newFrame.origin.x || button.frame.origin.y != newFrame.origin.y)
            {
                [UIView animateWithDuration:0.33 animations:^{
                    [button setFrame:newFrame];
                }];
            }
        }
    }

    NSInteger numberOfRows = floor(([listOfImages count] - 1) / imagesPerRow) + 1;

    [scrollView setContentSize:CGSizeMake(self.view.frame.size.width, numberOfRows * cellHeight + imagePadding)];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self rearrangeImages];
}

Hopefully this gives you an idea of how you can programmatically add a UIButton to act as an image in a gallery.希望这能让您了解如何以编程方式添加UIButton以充当图库中的图像。 I've tried to edit this on the fly, so I apologize in advance if I introduced any errors in the process, but it should give you a sense of what you could conceivably do... I removed my code to do this in a separate GCD queue (which I do because I have close to 100 images, and doing this on the main queue is too slow.)我试图即时编辑它,所以如果我在这个过程中引入了任何错误,我会提前道歉,但它应该让你了解你可以想象的事情......我删除了我的代码以在单独的 GCD 队列(我这样做是因为我有将近 100 张图像,并且在主队列上这样做太慢了。)

Anyway, you can then create your buttonClicked method to do your display of your UIAlertView .无论如何,您可以创建buttonClicked方法来显示UIAlertView

- (void)buttonClicked:(UIButton *)sender
{
     if (inEditMode)
     {
         // create your UIAlterView using [sender tag] to know which image you tapped on
     }
}

Finally, you have two buttons on your UIAlertView , but you don't seem to check to see what button the user clicked on.最后,您的UIAlertView上有两个按钮,但您似乎没有检查用户单击了哪个按钮。 Your view controller should be a UIAlterViewDelegate , in which you have defined your alertView:clickedButtonAtIndex which will do your actual edit steps.您的视图 controller 应该是一个UIAlterViewDelegate ,您在其中定义了alertView:clickedButtonAtIndex ,它将执行您的实际编辑步骤。

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
     // ok, will do what I need to do with whatever the user tapped in my alertview
}

The easiest thing I can think of off the top of my head is to have the gesture disabled by default, and then have the gesture enabled once the edit button is hit.我能想到的最简单的事情就是默认禁用手势,然后在按下编辑按钮后启用手势。 This way, the picture will only respond to the tap gesture recognizer if it is in "Edit" mode.这样,如果图片处于“编辑”模式,则图片只会响应点击手势识别器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM