Programmatically Scroll a Uiscrollview

Programmatically scroll a UIScrollView

You can scroll to some point in a scroll view with one of the following statements in Objective-C

[scrollView setContentOffset:CGPointMake(x, y) animated:YES];

or Swift

scrollView.setContentOffset(CGPoint(x: x, y: y), animated: true)

See the guide "Scrolling the Scroll View Content" from Apple as well.

To do slideshows with UIScrollView, you arrange all images in the scroll view, set up a repeated timer, then -setContentOffset:animated: when the timer fires.

But a more efficient approach is to use 2 image views and swap them using transitions or simply switching places when the timer fires. See iPhone Image slideshow for details.

Programmatically scroll a UIScrollView to the top of a child UIView (subview) in Swift

Here's an extension I ended up writing.

Usage:

Called from my viewController, self.scrollView is an outlet to the UIScrollView and self.commentsHeader is a view within it, near the bottom:

self.scrollView.scrollToView(self.commentsHeader, animated: true)

Code:

You only need the scrollToView method, but leaving in scrollToBottom / scrollToTop methods too as you'll probably need those too, but feel free to delete them.

extension UIScrollView {

// Scroll to a specific view so that it's top is at the top our scrollview
func scrollToView(view:UIView, animated: Bool) {
if let origin = view.superview {
// Get the Y position of your child view
let childStartPoint = origin.convertPoint(view.frame.origin, toView: self)
// Scroll to a rectangle starting at the Y of your subview, with a height of the scrollview
self.scrollRectToVisible(CGRect(x:0, y:childStartPoint.y,width: 1,height: self.frame.height), animated: animated)
}
}

// Bonus: Scroll to top
func scrollToTop(animated: Bool) {
let topOffset = CGPoint(x: 0, y: -contentInset.top)
setContentOffset(topOffset, animated: animated)
}

// Bonus: Scroll to bottom
func scrollToBottom() {
let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
if(bottomOffset.y > 0) {
setContentOffset(bottomOffset, animated: true)
}
}

}

How to scroll UIScrollVIew programmatically

Try it and set a new position manually.

Objective-c

  float width = CGRectGetWidth(scrollView.frame);
float height = CGRectGetHeight(scrollView.frame);
float newPosition = scrollView.contentOffset.x+width;
CGRect toVisible = CGRectMake(newPosition, 0, width, height);

[scrollView scrollRectToVisible:toVisible animated:YES];

Swift 4

let scrollView = UIScrollView()
let width: CGFloat = scrollView.frame.size.width
let height: CGFloat = scrollView.frame.size.height
let newPosition: CGFloat = scrollView.contentOffset.x + width
let toVisible: CGRect = CGRect(x: newPosition, y: 0, width: width, height: height)

scrollView.scrollRectToVisible(toVisible, animated: true)

scrolling a scrollview to its bottom programmatically

The offset setting doesn't works because you tried in calling early in the life cycle.

You could try updating the contentOffset at viewDidLayoutSubviews or viewDidAppear

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: true)

Using ScrollView Programmatically in Swift 3

It is easy to use constraints to define the scroll content size - so you don't have to do any manual calculations.

Just remember:

  1. The content elements of your scroll view must have left / top / width / height values. In the case of objects such as labels, they have intrinsic sizes, so you only have to define the left & top.
  2. The content elements of your scroll view also define the bounds of the scrollable area - the contentSize - but they do so with the bottom & right constraints.
  3. Combining those two concepts, you see that you need a "continuous chain" with at least one element defining the top / left / bottom / right extents.

Here is a simple example, that will run directly in a Playground page:

import UIKit
import PlaygroundSupport

class TestViewController : UIViewController {

let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .red
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()

let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()

let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()


override func viewDidLoad() {
super.viewDidLoad()

// add the scroll view to self.view
self.view.addSubview(scrollView)

// constrain the scroll view to 8-pts on each side
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true

// add labelOne to the scroll view
scrollView.addSubview(labelOne)

// constrain labelOne to left & top with 16-pts padding
// this also defines the left & top of the scroll content
labelOne.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 16.0).isActive = true
labelOne.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 16.0).isActive = true

// add labelTwo to the scroll view
scrollView.addSubview(labelTwo)

// constrain labelTwo at 400-pts from the left
labelTwo.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 400.0).isActive = true

// constrain labelTwo at 1000-pts from the top
labelTwo.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 1000).isActive = true

// constrain labelTwo to right & bottom with 16-pts padding
labelTwo.rightAnchor.constraint(equalTo: scrollView.rightAnchor, constant: -16.0).isActive = true
labelTwo.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -16.0).isActive = true

}

}


let vc = TestViewController()
vc.view.backgroundColor = .yellow
PlaygroundPage.current.liveView = vc

Edit - since this answer still gets occasional attention, I've updated the code to use more modern syntax, to respect the safe-area, and to use the scroll view's .contentLayoutGuide:

class TestViewController : UIViewController {

let labelOne: UILabel = {
let label = UILabel()
label.text = "Scroll Top"
label.backgroundColor = .yellow
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()

let labelTwo: UILabel = {
let label = UILabel()
label.text = "Scroll Bottom"
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()

let scrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .cyan
return v
}()


override func viewDidLoad() {
super.viewDidLoad()

// add the scroll view to self.view
self.view.addSubview(scrollView)

// add labelOne to the scroll view
scrollView.addSubview(labelOne)

// add labelTwo to the scroll view
scrollView.addSubview(labelTwo)

// always a good idea to respect safe area
let safeG = view.safeAreaLayoutGuide

// we want to constrain subviews to the scroll view's Content Layout Guide
let contentG = scrollView.contentLayoutGuide

NSLayoutConstraint.activate([

// constrain the scroll view to safe area with 8-pts on each side
scrollView.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 8.0),
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 8.0),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -8.0),
scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: -8.0),

// constrain labelOne to leading & top of Content Layout Guide with 16-pts padding
// this also defines the left & top of the scroll content
labelOne.topAnchor.constraint(equalTo: contentG.topAnchor, constant: 16.0),
labelOne.leadingAnchor.constraint(equalTo: contentG.leadingAnchor, constant: 16.0),

// constrain labelTwo leading at 400-pts from labelOne trailing
labelTwo.leadingAnchor.constraint(equalTo: labelOne.trailingAnchor, constant: 400.0),

// constrain labelTwo top at 1000-pts from the labelOne bottom
labelTwo.topAnchor.constraint(equalTo: labelOne.bottomAnchor, constant: 1000),

// constrain labelTwo to trailing & bottom of Content Layout Guide with 16-pts padding
// this also defines the right & bottom of the scroll content
labelTwo.trailingAnchor.constraint(equalTo: contentG.trailingAnchor, constant: -16.0),
labelTwo.bottomAnchor.constraint(equalTo: contentG.bottomAnchor, constant: -16.0),

])

}

}

Vertical UIScrollView programmatically

You need to set the height of the content for the UIScrollView in the viewWillLayoutSubviews:

override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.scrollView.contentSize.height = self.view.frame.height + 1000
}

And remove this line: scrollView.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height + 1000)

UIScrollView scroll to bottom programmatically

You can use the UIScrollView's setContentOffset:animated: function to scroll to any part of the content view. Here's some code that would scroll to the bottom, assuming your scrollView is self.scrollView:

Objective-C:

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];

Swift:

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)

Hope that helps!

Programmatically scroll uiscrollview to bottom as uilabel grows in height

Again, the first thing you need to do is layout your subviews after updating the text so your computations are based on the new text.

Rather than jumping through a lot of hoops and trying to compute the contentOffset I would suggest using scrollToRectVisible(_:animated:).

    view.layoutIfNeeded()

let rect = CGRect(
x: 0,
y: transcriptionLabel.frame.maxY - 1,
width: 1,
height: 1)

transcriptionScrollView.scrollRectToVisible(rect, animated: true)

That should scroll you to the bottom of the label, assuming that your label is a subview of your scrollView. If not, you will need to convert the label's frame to the scrollView coordinate space.

Remember to call view.layoutIfNeeded() after updating the text in your label and before scrolling.



Related Topics



Leave a reply



Submit