Search code examples
objective-cios6uilabeluigesturerecognizer

creating a line between two UIlabels using the long press gesture recognizer


i am developing a ER diagram editor, i have a bunch of draggable UILabels but all of them have the same name. i want to be able to create a line between two UIlabels when both are pressed together using the long press gesture recognizer. any help will be most appreciated


Solution

  • You can create your long press gesture on the superview shared by these two labels, e.g.:

    UILongPressGestureRecognizer *twoTouchLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self
                                                                                                    action:@selector(handleLongPress:)];
    twoTouchLongPress.numberOfTouchesRequired = 2;
    [self.view addGestureRecognizer:twoTouchLongPress];
    

    You can then write a gesture handler:

    - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
    {
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            CGPoint location0 = [gesture locationOfTouch:0 inView:gesture.view];
            CGPoint location1 = [gesture locationOfTouch:1 inView:gesture.view];
    
            if ((CGRectContainsPoint(self.label0.frame, location0) && CGRectContainsPoint(self.label1.frame, location1)) ||
                (CGRectContainsPoint(self.label1.frame, location0) && CGRectContainsPoint(self.label0.frame, location1)))
            {
                NSLog(@"success; draw your line");
            }
            else
            {
                NSLog(@"failure; don't draw your line");
            }
        }
    }
    

    In the updated comments, you suggest that you're creating a local UILabel variable, and then adding the resulting label to the view. That's fine, but you really want to maintain a backing model, that captures what you're doing in the view. For simplicity's sake, let me assume that you'll have array of these labels, e.g.:

    @property (nonatomic, strong) NSMutableArray *labels;
    

    Which you then initialize at some point (e.g. viewDidLoad):

    self.labels = [[NSMutableArray alloc] init];
    

    Then as you add labels to your view, add a reference to them in your array:

    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(xVal, yVal, 200.0f, 60.0f)]; 
    label.text = sentence; 
    label.layer.borderColor = [UIColor blueColor].CGColor;
    label.layer.borderWidth = 0.0; 
    label.backgroundColor = [UIColor clearColor]; 
    label.font = [UIFont systemFontOfSize:19.0f];
    [self.view addSubview:label];
    
    [self.labels addObject:label];
    

    Then, your gesture can do something like:

    - (UILabel *)labelForLocation:(CGPoint)location
    {
        for (UILabel *label in self.labels)
        {
            if (CGRectContainsPoint(label.frame, location))
                return label;                                // if found one, return that `UILabel`
        }
        return nil;                                          // if not, return nil
    }
    
    - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
    {
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            CGPoint location0 = [gesture locationOfTouch:0 inView:gesture.view];
            CGPoint location1 = [gesture locationOfTouch:1 inView:gesture.view];
    
            UILabel *label0 = [self labelForLocation:location0];
            UILabel *label1 = [self labelForLocation:location1];
    
            if (label0 != nil && label1 != nil && label0 != label1)
            {
                NSLog(@"success; draw your line");
            }
            else
            {
                NSLog(@"failure; don't draw your line");
            }
        }
    }
    

    Frankly, I'd rather see this backed by a proper model, but that's a more complicated conversation beyond the scope of a simple Stack Overflow answer. But hopefully the above gives you an idea of what it might look like. (BTW, I just typed in the above without assistance of Xcode, so I'll apologize in advance for typos.)