lostInTransit
lostInTransit

Reputation: 70997

Maintain contentOffset of UITextView on orientation change

Is it possible to change the content offset of a UITextView so when the user moves from portrait to landscape (or vice versa), the text which is visible to them remains the same?

So if the user was at (in portrait mode)

....some text....
....some text2....
....I'm here.... //this is the visible area
....more text....

moves to landscape, it should be

....some text....some text2....
....I'm here....more text.... //this is the visible area
.....

The UITextView is non-editable but scrollable.

Upvotes: 4

Views: 821

Answers (1)

Losiowaty
Losiowaty

Reputation: 8006

Here you have a short, self contained, compilable example :

import UIKit

class ViewController: UIViewController {

    var textView: UITextView!
    var percentOfScroll:CGFloat = 0

    override func viewDidLoad() {

        self.textView = UITextView(frame: CGRectZero)

        self.textView.layer.borderColor = UIColor.blackColor().CGColor
        self.textView.layer.borderWidth = 1
        self.textView.editable = false

        self.textView.text = "Lorem ipsum... some longish text"

        self.view.addSubview(self.textView)

        let leftConstraint = NSLayoutConstraint(item: self.textView, attribute: .Leading, relatedBy: .Equal, toItem: self.view, attribute: .Leading, multiplier: 1, constant: 10)
        let rightConstraint = NSLayoutConstraint(item: self.textView, attribute: .Trailing, relatedBy: .Equal, toItem: self.view, attribute: .Trailing, multiplier: 1, constant: -10)
        let topConstraint = NSLayoutConstraint(item: self.textView, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1, constant: 44)
        let centerConstraint = NSLayoutConstraint(item: self.textView, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .CenterY, multiplier: 1, constant: 0)

        self.textView.translatesAutoresizingMaskIntoConstraints = false
        self.view.addConstraints([leftConstraint, rightConstraint, topConstraint, centerConstraint])
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        let contentSize = self.textView.contentSize
        let newOffset = contentSize.height * percentOfScroll

        self.textView.contentOffset = CGPoint(x: 0, y: newOffset)
    }

    override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {

        super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

        let contentSize = self.textView.contentSize
        let contentOffset = self.textView.contentOffset

        self.percentOfScroll = contentOffset.y / contentSize.height
    }

}

The idea is to get the amount of scrolled content in relation to its height before rotation (viewWillTransitionToSize) and using it calculate new contentOffset after (viewDidLayoutSubviews is also called after size change).

Bear in mind that this doesn't give a 100% precise result, but I haven't been able to come up with anything better , and maybe this will be enough for you.

Upvotes: 4

Related Questions