3
votes

Hoping you could give me some direction here. I have a scrollview setup with vertically paging. My problem is the views are larger than the screen (vertically). My desired effect is to have the view scroll to the bottom and then page to the next page. Like my image below is trying to depict.

I have tried setting the size of the scrollview and the content size to the size of the view which does offset the views correctly. I just can't scroll to see the bottom of the view, It just pages to the next view.

Thanks for any advice.

Layout Design

class ViewController: UIViewController {

let scrollView = UIScrollView() // Create the scrollView

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    //Set up and add scrollView to view
    scrollView.frame = self.view.frame
    self.scrollView.pagingEnabled = true
    self.view.addSubview(scrollView)

    //An array of UIColors to add to the views
    let x : [UIColor] = [UIColor.blueColor(),UIColor.redColor(),UIColor.yellowColor()]

    //For each UIColor add a view that is 100px larger then the height of the scrollView
    for index in 0...x.count-1{
        //
        let subView = UIView(frame: CGRectMake(
            0, //x offset
            (self.scrollView.frame.height + 100) * CGFloat(index), //y offset
            self.scrollView.frame.width, // width
            (self.scrollView.frame.height + 100))) // height
        subView.backgroundColor = x[index] //background Color
        scrollView.addSubview(subView) // Add View

    }

    //
    let c = (self.scrollView.frame.size.height + 100) * CGFloat(x.count)
    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width, c)

    //Background Color
    self.view.backgroundColor = UIColor.greenColor()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}
3
You mean vertically, right?rdelmar
Facepalm. yes I mean vertically. fixedUser4
size always needs to keep screen size and you need to set contentSize based on number of images,if both frame and contents are same then how it'l scrolling.Balu
Thanks @Sunny, I still have the problem that it will only page and not scroll. I'll put my code up if that's any help.User4

3 Answers

4
votes

The best way I've found to do it is to use a nested scrollview for the content. Here is what my code ended up looking like.

class ViewController: UIViewController, UIScrollViewDelegate {

let scrollView = ScrollView() // Create the scrollView

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.


    //Set up and add scrollView to view
    scrollView.frame = self.view.frame
    self.scrollView.pagingEnabled = true
    self.view.addSubview(scrollView)
    self.scrollView.delegate = self

    //An array of UIColors to add to the views
    let x : [UIColor] = [UIColor.blueColor(),UIColor.redColor(),UIColor.yellowColor()]

    //For each UIColor add a view that is 100px larger then the height of the scrollView
    for index in 0...x.count-1{
        //
        let subView = UIScrollView(frame: CGRectMake(
            0, //x offset
            (self.scrollView.frame.height * CGFloat(index)), //y offset
            self.scrollView.frame.width, // width
            (self.scrollView.frame.height))) // height

//Set the size of the content view
        let contentView = UIView(frame: CGRectMake(0, 0, self.view.frame.width, 1000))

        subView.contentSize = CGSizeMake(self.view.frame.width, contentView.frame.height)
        contentView.backgroundColor = x[index]
        subView.addSubview(contentView)
        scrollView.addSubview(subView) // Add View

    }

    //
    let c = (self.scrollView.frame.size.height) * CGFloat(x.count)
    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width, c)

    //Background Color
    self.view.backgroundColor = UIColor.greenColor()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}
3
votes

User4's answer, in objective-c:

UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.frame;
scrollView.pagingEnabled = YES;
scrollView.backgroundColor = [UIColor yellowColor];
[self.view addSubview:scrollView];
scrollView.delegate = self;
NSArray *x = @[[UIColor blueColor], [UIColor redColor]];
for (int i = 0; i < x.count; i++) {
    UIView *subView = [[UIView alloc] initWithFrame:
                       CGRectMake(0,
                                  (scrollView.frame.size.height) * i,
                                  scrollView.frame.size.width,
                                  scrollView.frame.size.height)
                       ];
    UISwitch *switchCtrl = [[UISwitch alloc] initWithFrame:CGRectMake(5, 5, 20, 20)];
    subView.backgroundColor = x[i];
    [subView addSubview:switchCtrl];
    [scrollView addSubview:subView];
}
float c = (scrollView.frame.size.height) * x.count;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, c);
self.view.backgroundColor = [UIColor greenColor];
0
votes

A great tutorial by RayWenderlich.com does horizontal page scrolling. I've modified that code to allow for vertical page scrolling by adding a variable called "horizontalDirection". First follow his tutorial here: http://www.raywenderlich.com/76436/use-uiscrollview-scroll-zoom-content-swift

After you have completed the section "Viewing Previous/Next Pages" replace your view controller with this: (You may need to tweak the size of your scrollview)

@IBOutlet var scrollView: UIScrollView!
@IBOutlet var pageControl: UIPageControl!

var pageImages: [UIImage] = []
var pageViews: [UIImageView?] = []
let horizontalDirection = false

override func viewDidLoad() {
    super.viewDidLoad()

    // Set up the image you want to scroll & zoom and add it to the scroll view
    pageImages = [UIImage(named: "photo1.png")!,
        UIImage(named: "photo2.png")!,
        UIImage(named: "photo3.png")!,
        UIImage(named: "photo4.png")!,
        UIImage(named: "photo5.png")!]

    let pageCount = pageImages.count

    // Set up the page control
    pageControl.currentPage = 0
    pageControl.numberOfPages = pageCount

    // Set up the array to hold the views for each page
    for _ in 0..<pageCount {
        pageViews.append(nil)
    }

    // Set up the content size of the scroll view
    let pagesScrollViewSize = scrollView.frame.size
    if horizontalDirection {
        scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * CGFloat(pageImages.count), pagesScrollViewSize.height)
    } else {
        scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width, CGFloat(pageImages.count) * pagesScrollViewSize.height)
    }
    // Load the initial set of pages that are on screen
    loadVisiblePages()
}
func loadVisiblePages() {
    // First, determine which page is currently visible
    var pageSide = scrollView.frame.size.width
    var page = Int(floor((scrollView.contentOffset.x * 2.0 + pageSide) / (pageSide * 2.0)))
    if !horizontalDirection {
        pageSide = scrollView.frame.size.height
        page = Int(floor((scrollView.contentOffset.y * 2.0 + pageSide) / (pageSide * 2.0)))
    }

    // 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 index in firstPage...lastPage {
        loadPage(index)
    }

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

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
    }

    // Load an individual page, first checking if you've already loaded it
    if let pageView = pageViews[page] {
        // Do nothing. The view is already loaded.
    } else {
        var frame = scrollView.bounds
        if horizontalDirection {
            frame.origin.x = frame.size.width * CGFloat(page)
            frame.origin.y = 0.0
            frame = CGRectInset(frame, 10.0, 0.0)
        } else {
            frame.origin.x = 0.0
            frame.origin.y = frame.size.height * CGFloat(page)
        }

        let newPageView = UIImageView(image: pageImages[page])
        newPageView.contentMode = .ScaleAspectFit
        newPageView.frame = frame
        scrollView.addSubview(newPageView)
        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 scrollViewDidScroll(scrollView: UIScrollView!) {
    // Load the pages that are now on screen
    loadVisiblePages()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}