使用 UITextView 进行动态分页

Dynamic paging with UITextView

我正在尝试使用 UITextView 创建从左到右滚动的动态分页。我已经使用本教程实现了一个代码: http://sketchytech.blogspot.com/2013/11/paging-and-paginating-easy-way-with.html

这是我的代码:

let pageNumber: CGFloat = 4.0

override func viewDidLoad() {

    super.viewDidLoad()
    let scrollingView = UIScrollView(frame: CGRect(x: CGFloat(20), y: CGFloat(20), width: CGFloat(view.bounds.size.width - 20), height: CGFloat(view.bounds.size.height - 20)))
    scrollingView.contentSize = CGSize(width: CGFloat((view.bounds.size.width - 20) * pageNumber), height: CGFloat(view.bounds.size.height - 20))
    scrollingView.isPagingEnabled = true
    view.addSubview(scrollingView)

    let textString = "NOW, what I want is, Facts.  Teach these boys and girls nothing but Facts.  Facts alone are wanted in life.  Plant nothing else, and root out everything else.  You can only form the minds of reasoning animals upon Facts: nothing else will ever be of any service to them.  This is the principle on which I bring up my own children, and this is the principle on which I bring up these children.  Stick to Facts, sir!’ The scene was a plain, bare, monotonous vault of a school-room, and the speaker’s square forefinger emphasized his observations by underscoring every sentence with a line on the schoolmaster’s sleeve.  The emphasis was helped by the speaker’s square wall of a forehead, which had his eyebrows for its base, while his eyes found commodious cellarage in two dark caves, overshadowed by the wall.  The emphasis was helped by the speaker’s mouth, which was wide, thin, and hard set.  The emphasis was helped by the speaker’s voice, which was inflexible, dry, and dictatorial.  The emphasis was helped by the speaker’s hair, which bristled on the skirts of his bald head, a plantation of firs to keep the wind from its shining surface, all covered with knobs, like the crust of a plum pie, as if the head had scarcely warehouse-room for the hard facts stored inside.  The speaker’s obstinate carriage, square coat, square legs, square shoulders,—nay, his very neckcloth, trained to take him by the throat with an unaccommodating grasp, like a stubborn fact, as it was,—all helped the emphasis. ‘In this life, we want nothing but Facts, sir; nothing but Facts!’ The speaker, and the schoolmaster, and the third grown person present, all backed a little, and swept with their eyes the inclined plane of little vessels then and there arranged in order, ready to have imperial gallons of facts poured into them until they were full to the brim."

    let textStorage = NSTextStorage(string: textString)
    let textLayout = NSLayoutManager()
    textStorage.addLayoutManager(textLayout)
    textLayout.delegate = self

    var i: Int = 0
    while i <= 4 {
        let textContainer = NSTextContainer(size: scrollingView.frame.size)
        textLayout.addTextContainer(textContainer)
        let textView = UITextView(frame: CGRect(x: CGFloat(scrollingView.frame.size.width * CGFloat(i)), y: CGFloat(0), width: CGFloat(scrollingView.frame.size.width), height: CGFloat(scrollingView.frame.size.height)), textContainer: textContainer)
        textView.font = .systemFont(ofSize: 25)
        textView.tag = i
        scrollingView.addSubview(textView)
        i += 1
    }
}

func layoutManager(_ layoutManager: NSLayoutManager, didCompleteLayoutFor textContainer: NSTextContainer?, atEnd layoutFinishedFlag: Bool) {

    print("called")
}

唯一的问题是这里的页数或用户定义的静态值是有限的。但是,如果我想将字体大小更改为 30,那么将需要额外的页面。在最后的教程中它说,"In order to add the dynamic element, you need to take advantage of the NSLayoutManager delegate methods." 我阅读了 NSLayoutManger 的文档并发现 layoutManager(_:didCompleteLayoutFor:atEnd:) 非常适合分页,我在我的代码中添加了它但不确定如何使用利用它。谁能告诉我如何通过更改 fontSize 使 textview 动态化,它会自动调整所需的页数?

我想你会发现它比预期的要容易 - 你甚至不需要 NSLayoutManagerDelegate:

override func viewDidLoad() {

    super.viewDidLoad()

    let scrollingView = UIScrollView(frame: CGRect(x: CGFloat(20), y: CGFloat(20), width: CGFloat(view.bounds.size.width - 40), height: CGFloat(view.bounds.size.height - 40)))

    // we will set the contentSize after determining how many pages get filled with text
    //scrollingView.contentSize = CGSize(width: CGFloat((view.bounds.size.width - 20) * pageNumber), height: CGFloat(view.bounds.size.height - 20))

    scrollingView.isPagingEnabled = true
    view.addSubview(scrollingView)

    let textString = "NOW, what I want is, Facts.  Teach these boys and girls nothing but Facts.  Facts alone are wanted in life.  Plant nothing else, and root out everything else.  You can only form the minds of reasoning animals upon Facts: nothing else will ever be of any service to them.  This is the principle on which I bring up my own children, and this is the principle on which I bring up these children.  Stick to Facts, sir!’ The scene was a plain, bare, monotonous vault of a school-room, and the speaker’s square forefinger emphasized his observations by underscoring every sentence with a line on the schoolmaster’s sleeve.  The emphasis was helped by the speaker’s square wall of a forehead, which had his eyebrows for its base, while his eyes found commodious cellarage in two dark caves, overshadowed by the wall.  The emphasis was helped by the speaker’s mouth, which was wide, thin, and hard set.  The emphasis was helped by the speaker’s voice, which was inflexible, dry, and dictatorial.  The emphasis was helped by the speaker’s hair, which bristled on the skirts of his bald head, a plantation of firs to keep the wind from its shining surface, all covered with knobs, like the crust of a plum pie, as if the head had scarcely warehouse-room for the hard facts stored inside.  The speaker’s obstinate carriage, square coat, square legs, square shoulders,—nay, his very neckcloth, trained to take him by the throat with an unaccommodating grasp, like a stubborn fact, as it was,—all helped the emphasis. ‘In this life, we want nothing but Facts, sir; nothing but Facts!’ The speaker, and the schoolmaster, and the third grown person present, all backed a little, and swept with their eyes the inclined plane of little vessels then and there arranged in order, ready to have imperial gallons of facts poured into them until they were full to the brim."

    let textStorage = NSTextStorage(string: textString)
    let textLayout = NSLayoutManager()
    textStorage.addLayoutManager(textLayout)
    textLayout.delegate = self

    var r = CGRect(x: 0, y: 0, width: scrollingView.frame.size.width, height: scrollingView.frame.size.height)

    var i: Int = 0

    // this is what we'll use to track the "progress" of filling the "screens of textviews"
    // each time through, we'll get the last Glyph rendered...
    // if it's equal to the total number of Glyphs, we know we're done
    var lastRenderedGlyph = 0

    while lastRenderedGlyph < textLayout.numberOfGlyphs {

        let textContainer = NSTextContainer(size: scrollingView.frame.size)
        textLayout.addTextContainer(textContainer)

        let textView = UITextView(frame: r, textContainer: textContainer)

        r.origin.x += r.width

        textView.font = .systemFont(ofSize: 25)

        textView.tag = i

        i += 1

        scrollingView.addSubview(textView)

        // get the last Glyph rendered into the current textContainer
        lastRenderedGlyph = NSMaxRange(textLayout.glyphRange(for: textContainer))

    }

    // use the last textView rect to set contentSize
    scrollingView.contentSize = CGSize(width: r.origin.x, height: r.size.height)

    print("Actual number of pages =", i)
}

尝试更改字体大小,并更改实际文本...您应该看到页数自动填充。