Jay Jay - 15 days ago 4x
Objective-C Question

UIView in UIScrollview. frame.origin not changing on scrolling, can't detect collision

I have a screen containing:

  • UIView A

  • UIScrollView, which contains UIView B

The UIScrollView overlaps with UIView A (up until about halfway through it), allowing me to "drag" UIView B and make it overlap it with UIView A. This is so that when I let go of it, UIView B bounces nicely back into its original position (I don't want to be able to drag it all around the screen, just from its starting point onto UIView A)

Now, I'm trying to detect a collision when the UIViews overlap. However, none is ever detected. I am using convertRect:toView: to get coordinates on the same system, but from tracing UIView B's coordinates in its touchesMoved I see that "dragging" (scrolling the UIScrollView, really) doesn't affect its frame's origin coordinates. They are the same in touchedBegan as they are every time touchedMoved fires.

I'm assuming this is because UIView B isn't really moving anywhere, UIScrollView is, meaning that the UIView's origin point is always the same, even if its absolute coordinates aren't. Any suggestion on how to handle this?


There will be overlap when scrollView.frame.origin.x + viewB.frame.size.width + scrollView.contentOffset.x >= viewA.frame.origin.x

After Edit:

I couldn't get the scroll view to work so I tried it another way that worked pretty well. Instead of a scroll view, I just used a rectangular view with a background color, and added the blue square to it. I gave the blue square a set width and height in IB, centered it in the long skinny view (in the y direction), and had one other constraint to the left side of that long view. The IBOutlet leftCon is connected to that constraint. I then used this code to drag it, and have it go back when I let go:

#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>

@interface ViewController ()
@property (strong,nonatomic) UIPanGestureRecognizer *panner;
@property (strong,nonatomic) IBOutlet NSLayoutConstraint *leftCon;
@property (strong,nonatomic) CADisplayLink *displayLink;

@implementation ViewController {
    IBOutlet UIView *blueSquare;

-(void)viewDidLoad {
    self.panner = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
    [blueSquare addGestureRecognizer:self.panner];

- (void)handlePanGesture:(UIPanGestureRecognizer *)sender {
    CGPoint translate = [sender translationInView:self.view];
    if (self.leftCon.constant <160)
        if (self.leftCon.constant > 100) NSLog(@"Bang! We have a collision");
        self.leftCon.constant = translate.x;
    if (sender.state == UIGestureRecognizerStateEnded){
        [self startDisplayLink];

-(void)startDisplayLink {
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(bounceBack:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

- (void)stopDisplayLink {
    [self.displayLink invalidate];
    self.displayLink = nil;

-(void)bounceBack:(CADisplayLink *) link {
    self.leftCon.constant -= 12;
    if (self.leftCon.constant < 2) {
        [self stopDisplayLink];
        self.leftCon.constant = 2;

The numbers in the translate code (160 and 100) were determined empirically by logging. The 160 number keeps it from going off the right edge of the long view, and the 100 number is where it starts to overlap the black box.