3

I have a collectionView with multiple images. When tapping on one of them a new view is being opened - UIScrollView.

Now every time UIScrollView starts with the first image of the array from collectionView.

I am passing the index(imageNumber) of the image tapped to UIScrollView but i don't know how to make the first image shown to be the one with the index.

override func viewDidLoad() {
    super.viewDidLoad()

    var numberOfImagesPerALbum = data[albumNumber].count - 1

    for index in 0...numberOfImagesPerALbum {

        pageImages.append(UIImage(named: data[albumNumber][index]["image"]!)!)


    }

    var pageCount = pageImages.count


    // 2
    pageControl.currentPage = imageNumber
    println(imageNumber)

    pageControl.numberOfPages = pageCount

    // 3
    for _ in 0..<pageCount {
        pageViews.append(nil)
    }


}

override func viewDidLayoutSubviews() {
    let pagesScrollViewSize = scrollView.frame.size
    scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * CGFloat(pageImages.count), pagesScrollViewSize.height)

    // 5
    loadVisiblePages()

}


func loadPage(page: Int) {
    if page < 0 || page >= pageImages.count {
        // If it's outside the range of what you have to display, then do nothing
        return
    }

    // 1
    if let pageView = pageViews[page] {
        // Do nothing. The view is already loaded.

    } else {
        // 2
        var frame = scrollView.bounds
        frame.origin.x = frame.size.width * CGFloat(page)
        frame.origin.y = 0.0

         3
        let newPageView = UIImageView(image: pageImages[page])

        newPageView.contentMode = .ScaleAspectFit
        newPageView.frame = frame


        scrollView.addSubview(newPageView)

        // 4
        pageViews[page] = newPageView
    }
}

func purgePage(page: Int) {
    if page < 0 || page >= pageImages.count {
        // If it's outside the range of what you have to display, then do nothing
        return
    }

    // Remove a page from the scroll view and reset the container array
    if let pageView = pageViews[page] {
        pageView.removeFromSuperview()
        pageViews[page] = nil
    }
}

func loadVisiblePages() {
    // First, determine which page is currently visible
    let pageWidth = scrollView.frame.size.width
    let page = Int(floor((scrollView.contentOffset.x * 2.0 + pageWidth) / (pageWidth * 2.0)))
    println("Page is \(page)")

    imageTitleLabel.text = data[albumNumber][page]["title"]

    imageDescriptionLabel.text = data[albumNumber][page]["text"]

    // Update the page control
    pageControl.currentPage = page

    // Work out which pages you want to load
    let firstPage = page - 1
    let lastPage = page + 1

    // Purge anything before the first page
    for var index = 0; index < firstPage; ++index {
        purgePage(index)
    }

    // Load pages in our range
    for var index = firstPage; index <= lastPage; ++index {
        loadPage(index)
    }

    // Purge anything after the last page
    for var index = lastPage+1; index < pageImages.count; ++index {
        purgePage(index)
    }
}

func scrollViewDidScroll(scrollView: UIScrollView) {
    // Load the pages that are now on screen
    loadVisiblePages()
}
alahab
  • 85
  • 1
  • 9
  • Could you clarify what does UIScrollView display? Is it a horizontally scrolling view (with pagination?) with images from album, scrolled to a particular index? Also, think you can get rid of `var numberOfImagesPerAlbum` and use `for index in 0.. – Daniil Korotin May 25 '15 at 14:40
  • @DaniilKorotin You are right, it's a horizontally scrolling view with pagination with images from an album (UICollectionView). As soon as UIscrollView loads it should display an image that was tapped in UIScrollView. For example, you tap on the third image in UiCollectionView, it should be displayed in scrollView and you can scroll backwards and forwards to see the rest of the images. Now every time UIScrollView loads the very first image and you can scroll forwards. – alahab May 25 '15 at 14:58

1 Answers1

1

Consider using UICollectionView with UICollectionViewFlowLayout (set scrollDirection to UICollectionViewScrollDirectionHorizontal) instead of UIScrollView. Also set UICollectionView's pagingEnabled property to true.

This will save you a lot of unnecessary code and you will get the UICollectionView's - scrollToItemAtIndexPath:atScrollPosition:animated: method "for free". This should solve all your problems and make code cleaner. Good luck!

Daniil Korotin
  • 720
  • 3
  • 14
  • Thanks Daniil, i managed to create a UICollectionView as you suggested and load all my images in it. But i can't make scrollToItemAtIndexPath work. `override func viewDidLayoutSubviews() { self.view.layoutIfNeeded() var indexPath = NSIndexPath(forItem: imageNumber, inSection: 0) collectionView?.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredVertically, animated: true) }` (imageNumber is the correct number of the image tapped on the previous ViewController) – alahab May 26 '15 at 07:30
  • @alahab Glad it helped. The thing is you have to call the `- scrollToItemAtIndexPath:atScrollPosition:animated:` method **after** the VC's view is loaded and knows its size (i.e., not in `- viewWillAppear`, but in `- viewDidLoad` or `- viewDidLayoutSubviews`). That can be a huge problem if you want to, for example, display the VC modally with the photo already scrolled to. If that's the case, you can preload the VC's view in some way and display the already set up VC (say, by setting its alpha to 0.0 or something). Feel free to ask for further clarification if needed. – Daniil Korotin May 26 '15 at 09:41
  • Ah, sorry, I didn't notice you already do it in `-viewDidLayoutSubviews`. Could you add some testing button and add an action to it to scroll to the desired position? This will show if the problem is with the time you try to call the `scrollTo...` method or with the method parameters. – Daniil Korotin May 26 '15 at 09:54
  • Thanks for the advice. Just tried it with the button. Unfortunately nothing happens. I can see the proper imageNumber in the console. So in theory it should scroll. I tried all sorts of ways of declaring indexPath also. – alahab May 26 '15 at 10:30
  • Did you try different options for `atScrollPosition` parameter? If I remember correctly, this caused problems in my code a while ago. – Daniil Korotin May 26 '15 at 10:34
  • Thanks a lot! Just tried it, UICollectionViewScrollPosition.CenteredHorizontally worked. Now the first image i see is the one i tapped earlier. But from there i can't scroll anywhere. viewDidLayoutSubviews() is being called every time i am trying to scroll and i am stuck with only one image. – alahab May 26 '15 at 11:05
  • So we're close to it now :D Use `-viewDidLoad` maybe? Or, if it won't work, use a boolean to track if the scrolling happened already? – Daniil Korotin May 26 '15 at 11:26
  • Silly me, viewDidLoad worked. I kept seeing all the posts about "don't put scrollToItemAtIndexPath in ViewDidLoad" and i haven't even tried. Thank you so much for your help Daniil! I know it can be too much but i am desperate to find the solution for this question [http://stackoverflow.com/questions/30458148/resize-images-automatically-in-collectionviewcell-in-collectionview-with-auto-la]. Thanks again! – alahab May 26 '15 at 12:14
  • @DaniilKorotin I have a similar problem in my questione here (http://stackoverflow.com/questions/36174529/swift-how-to-make-a-scrollview-work-with-pagecontrol) ... would you please have a look? I can't make it work – SagittariusA Mar 23 '16 at 16:05