super9
super9

Reputation: 30131

UIScrollView scrolling area inside a UICollectionViewCell

I have the following UICollectionView Controller

enter image description here

My problem is when I zoom into the image, I am able to "scroll past" the image boundary. It is almost exactly similar to this question Keep zoomable image in center of UIScrollView but the answer didn't solve it for me.

From what I understand, I believe this is because the content size of the scrollView isn't set to the size of the image. However, I'm not sure where to set something like self.scrollView.contentSize = self.imageView.image.size in my subclassed UICollectionViewCell.

Default View

enter image description here

Zoomed and Moved Beyond Image Boundary

enter image description here

My expected behaviour is for the image to sorta bounce back if the user tries to scroll beyond the image.

The relevant code thus far

Imgur Cell Subclass

- (void)awakeFromNib {
    self.scrollView.minimumZoomScale = 1;
    self.scrollView.maximumZoomScale = 3.0;
    self.scrollView.delegate = self;
}

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    return self.imageView;
}

View Controller

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setStyle];
    ImgurCellDetail *cell = (ImgurCellDetail *)[self.collectionView cellForItemAtIndexPath:self.indexPath];
    cell.scrollView.minimumZoomScale = cell.scrollView.frame.size.width / cell.imageView.frame.size.width;
    cell.scrollView.maximumZoomScale = 3.0;
    cell.scrollView.contentSize = cell.imageView.image.size;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self loadSelectedImage];
}

- (void)loadSelectedImage
{
    [self.collectionView scrollToItemAtIndexPath:self.indexPath
                                atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally
                                        animated:NO];

}

- (ImgurCellDetail *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"Cell";
    ImgurCellDetail *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    [self resetImage:cell];
    cell.imageView.image = [UIImage imageWithContentsOfFile:self.imageArray[indexPath.row]];
    [self.collectionView addGestureRecognizer:cell.scrollView.pinchGestureRecognizer];
    [self.collectionView addGestureRecognizer:cell.scrollView.panGestureRecognizer];
    return cell;
}

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout
 sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    // Need this for 3.5"
    return self.collectionView.frame.size;
}

- (void)collectionView:(UICollectionView *)collectionView
  didEndDisplayingCell:(ImgurCellDetail *)cell
    forItemAtIndexPath:(NSIndexPath *)indexPath {

    [self.collectionView removeGestureRecognizer:cell.scrollView.pinchGestureRecognizer];
    [self.collectionView removeGestureRecognizer:cell.scrollView.panGestureRecognizer];
}

- (void)resetImage:(ImgurCellDetail *)cell {
    //reset zoomScale back to 1 so that contentSize can be modified correctly
    cell.scrollView.zoomScale = 1;
}

I should probably mention that I have no issues when the Image View is set to aspect fill but as you can see, it's currently set to aspect fit which is where my troubles begin.

Upvotes: 1

Views: 5271

Answers (2)

super9
super9

Reputation: 30131

I managed to solve my own bug. I adapted the method found here: http://www.raywenderlich.com/10518/how-to-use-uiscrollview-to-scroll-and-zoom-content into my solution.

The changes I had to make were:

  • Generating the image programmatically instead of using the storyboard
  • Adding scrollview min/max zoom init code in my awakeInNib method for my UICollectionView subclass
  • Generating the image in my cellForRowIndexPath

That's about it I think.

Upvotes: 0

E. Rivera
E. Rivera

Reputation: 10938

I think you have to start by setting the contentSize of the scroll view to match the size of the scaled down size of your image (the size shown in your first screenshot) and not to the actual size of the picture.

// Not this
//cell.scrollView.contentSize = cell.imageView.image.size;

// But this
CGSize originalSize = cell.imageView.image.size;
CGSize sizeToFit = cell.scrollView.bounds.size;
CGFloat scaleDownFactor = MIN(sizeToFit.width / originalSize.width,
                              sizeToFit.height / originalSize.height);
CGSize scaledDownSize = CGSizeMake(nearbyintf(originalSize.width * scaleDownFactor),
                                   nearbyintf(originalSize.height * scaleDownFactor));
cell.scrollView.contentSize = scaledDownSize;

// Also use scaledDownSize for the viewForZooming

From there you keep adjusting the content insets as done in the answer you linked.

Finally the scroll view's actual size may not be fully adjusted yet in viewDidLoad!

Upvotes: 1

Related Questions