2

this things that i want to get

I am new in ios development, i want to show edge of next view using scrollview initial i got help from this Link, here is my view hierarchy 1) I added scrollview from story board to view controllers's top view 2) I added a view as container view and collection view programmatically as subviews of scrollview.

I displayed the edge of next view but when i go to next page things are not smoothly, i do not know how to handle this massy thing and also i do not know which approach is best for achieving this particular task. here is my code. I'm really stuck and I really don't know what to do.

func addCollectionViewsInsideScrollView(){

    scrollView?.delegate = self;
    scrollView?.isPagingEnabled=true
    scrollView.indicatorStyle = UIScrollViewIndicatorStyle.white


    for i in 0...2 {
        if i == 0 {

            frame = CGRect(x: scrollWidth * CGFloat (i), y: 0, width: scrollWidth - 45,height: scrollHeight)

            subView1 = UIView(frame: frame)
            subView1.backgroundColor = .white
            scrollView?.backgroundColor = .white
            scrollView?.addSubview(subView1)
            subView1.addSubview(collectionView0)
            collectionView0.frame = CGRect(x: subView1.bounds.origin.x, y: 0, width: subView1.bounds.width,height: subView1.bounds.height)

        }

        if i == 1 {

            frame = CGRect(x: scrollWidth * CGFloat (i) - 20, y: 0, width: scrollWidth - 45,height: scrollHeight)

            subView2 = UIView(frame: frame)
            scrollView?.addSubview(subView2)
            subView2.addSubview(collectionView1)
            collectionView1.frame = CGRect(x: subView2.bounds.origin.x, y: 0, width: subView2.bounds.width,height: subView2.bounds.height)

        }

        if i == 2 {

            frame = CGRect(x: scrollWidth * CGFloat (i) - 40, y: 0, width: scrollWidth - 45,height: scrollHeight)
            subView3 = UIView(frame: frame)
            scrollView?.addSubview(subView3)
            subView3.addSubview(collectionView2)

            collectionView2.frame = CGRect(x: subView3.bounds.origin.x, y: 0, width: subView3.bounds.width,height: subView3.bounds.height)

        }

    }

    scrollView?.contentSize = CGSize(width: (scrollWidth * 3), height: scrollHeight)
}

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    setIndiactorForCurrentPage()
}




func scrollViewDidScroll(_ scrollView: UIScrollView) {


    if myPageNo == 1 {
        frame = CGRect(x: scrollWidth - 20, y: 0, width: scrollWidth - 40,height: scrollHeight)
        let subView = UIView(frame: frame)
        self.scrollView?.addSubview(subView)
        subView.addSubview(collectionView1)
        collectionView1.frame = CGRect(x: subView.bounds.origin.x, y: 0, width: subView.bounds.width,height: subView.bounds.height)
         myPageNo -= 0
    }

    if myPageNo == 2{
        frame = CGRect(x: scrollWidth * 2 - 20, y: 0, width: scrollWidth,height: scrollHeight)
        let subView = UIView(frame: frame)
        self.scrollView.addSubview(subView)
        subView.addSubview(collectionView2)
        collectionView2.frame = CGRect(x: subView.bounds.origin.x, y: 0, width: subView.bounds.width,height: subView.bounds.height)
        myPageNo -= 1
    }
}

func setIndiactorForCurrentPage()  {

    let page = (scrollView?.contentOffset.x)!/scrollWidth
    print(scrollView?.contentOffset.x ?? 0)
    pageControl?.currentPage =  Int(page.rounded())
    myPageNo = Int(page.rounded())

    if  myPageNo == 1 {
       setFrame(pageNo: 1)
    }

    if myPageNo == 2{
        setFrame(pageNo: 2)
    }

}


func setFrame(pageNo: Int){
    if(pageNo == 1){

    frame = CGRect(x: scrollWidth + 2, y: 0, width: scrollWidth - 40,height: scrollHeight)
    let subView = UIView(frame: frame)
    scrollView?.addSubview(subView)
    subView.addSubview(collectionView1)
    collectionView1.frame = CGRect(x: subView.bounds.origin.x, y: 0, width: subView.bounds.width,height: subView.bounds.height)

    }
    else if(pageNo == 2){

        frame = CGRect(x: scrollWidth * 2, y: 0, width: scrollWidth,height: scrollHeight)
        let subView = UIView(frame: frame)
        scrollView?.addSubview(subView)
        subView.addSubview(collectionView2)
        collectionView2.frame = CGRect(x: subView.bounds.origin.x, y: 0, width: subView.bounds.width,height: subView.bounds.height)

    }
}

when I back from last page to previous one, all is good but when I go first page to next view i am unable to handle showing edge of next view.

So far I achieved this thing but this is not what i want. I want to control uiscroll using tap gesture and alse want to show last page with left align `this is my code func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

    var visibleRect = CGRect()
    visibleRect.origin = collectionView.contentOffset
    visibleRect.size = collectionView.bounds.size
    let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
    let visibleIndexPath: IndexPath = collectionView.indexPathForItem(at: visiblePoint)

    collectionView.scrollToItem(at: visibleIndexPath, at: .left, animated: true)
    indexPathArray.removeAll()
}

`

3 Answers3

1

If you have many pages I wouldn't do with scroll view but here is my sample code to show next page in scrollview.

class ExampleViewController: UIViewController {

var scrollView = UIScrollView()

var container1 = UIView()
var container2 = UIView()
var container3 = UIView()

override func viewDidLoad() {
    super.viewDidLoad()

    scrollView.isPagingEnabled = true
    scrollView.clipsToBounds = false
    view.addSubview(scrollView)

    container1.backgroundColor = .red
    container2.backgroundColor = .blue
    container3.backgroundColor = .yellow

    scrollView.addSubview(container1)
    scrollView.addSubview(container2)
    scrollView.addSubview(container3)
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    scrollView.frame = CGRect(x: 0, y: 0, width: view.bounds.width - peekAmount, height: view.bounds.height)
    scrollView.contentSize = CGSize(width: 3 * scrollView.frame.width, height: scrollView.frame.size.height)
    container1.frame.size = containerSize
    container2.frame.size = containerSize
    container3.frame.size = containerSize
    var xPosition: CGFloat = 0
    container1.frame.origin = CGPoint(x: xPosition, y: 0)
    xPosition = container1.frame.maxX
    container2.frame.origin = CGPoint(x: xPosition, y: 0)
    xPosition = container2.frame.maxX
    container3.frame.origin = CGPoint(x: xPosition, y: 0)
}

var containerSize: CGSize {
    return CGSize(width: scrollView.frame.size.width, height: scrollView.frame.size.height)
}

var peekAmount: CGFloat {
    return 80
}
}

There are many different ways to achieve your needs but this is simple enough to give you an idea. I didn't add the page control since you already have the logic.

HMHero
  • 2,333
  • 19
  • 11
  • I really appreciate your support and please let me ask a little bit more about this, which approach would be the best for getting this thing. Should I really use collection view with three cells (for three pages) and inside each cell can I use another collection view with multiple cells ? – Irfan Ahmed Aug 22 '17 at 21:04
  • @IrfanAhmed Yes. If I were you and implement the design in the link on your question, definitely. You will end up creating a custom UICollectionViewFlowLayout to implement the scroll behavior. – HMHero Aug 22 '17 at 21:16
  • Do you have any piece of code for achieving this task with collection view ? – Irfan Ahmed Aug 22 '17 at 21:20
1

I have been working on several projects where you would have like a peek at the next item you could view. The best solution is probably a UICollectionView as you would not load every UIViewController into view immediately but only when it's almost up. The cell re-use of UICollectionView takes care of that.

Make sure the cell size (which you can calculate depending on the size of your screen) will be something like width - 40px so you just see the edge of the next cell. It's totally possible to have a UIViewController in every cell, in fact you could even do it via Interface Builder nowadays.

UICollectionView already implements UIScrollView so no need to mess with UIScrollView manually. The only thing you need to do is that at the moment somebody stops scrolling you decide which cell you want to scroll to (the next one or stay on the current one) and scroll to that cell animated. For this you need to add a gesture recognizer: Intercepting pan gestures over a UIScrollView breaks scrolling

Then scroll to the cell most visible when the user stops scrolling: https://developer.apple.com/documentation/uikit/uicollectionview/1618046-scrolltoitematindexpath

For this you need to know which cell is most visible at that moment. This calculation can be a bit difficult but the gist is that you need to know which cells are in indexPathsForVisibleItems and then see according to their content- or scrollOffset which one is more into view than the other(s). The indexPath of that one should be the indexPath of the one you want to scroll into view.

This solution scales up to millions of items since you're only loading the cells you actually (are about to) see.

Lucas van Dongen
  • 9,328
  • 7
  • 39
  • 60
  • Thanks for your response:) I really appreciate and i implemented that you suggested above but my collection view inside collection view cell doesn't work properly. First row of collection view is hidden, i set cell and collection view edge insect but nothing get properly behave. – Irfan Ahmed Aug 23 '17 at 11:33
  • Could you add an example of what happens in your case? You can add .gifs for example, perhaps also video. I've noticed that you are not using `indexPathsForVisibleItems` or the method to scroll the cell into view. You would know exactly what page you're on because you've just determined which cell with which indexPath was the one you snapped to. – Lucas van Dongen Aug 23 '17 at 20:32
  • Actually my first collection view's cell has width equal to collection view width - 35 to show edge of the next item and in these three cells i added another collection view with 27 seven items so the first thing is that when i go the next page my first collection view cell is behind the screen a little bit and when i want to get visible cell index I got the index of second collection view items which is sub view of first cell. – Irfan Ahmed Aug 24 '17 at 05:20
  • I can't really visualize it. Did you already take a look at the view hierarchy?: https://stackoverflow.com/questions/5150186/how-do-i-inspect-the-view-hierarchy-in-ios - my hunch is that the VC's you are nesting in the cells still have their original sizes and not width - 35. `layoutSubviews` after you've set them up could help. Are you using constraints or do you size everything manually? – Lucas van Dongen Aug 24 '17 at 17:05
  • I am using constraints – Irfan Ahmed Aug 24 '17 at 17:13
  • I just checked views hierarchy there is everything perfect let me share some gif or video then it will be clear actually what i am facing now – Irfan Ahmed Aug 24 '17 at 17:18
0

I think, you use UICollectionView to show edge of the next view.