如何像电子阅读器一样将UITextView变成“页面”

时间:2018-06-25 21:10:13

标签: swift uitextview

我有一个包含较长段落的文本视图。我不想让用户滚动以继续阅读,而是希望将文本分成页面。

屏幕将占用全部文字,然后用户可以单击下一页或上一页。换句话说,市场上任何电子阅读器的行为。

我真的不确定从哪里开始。我会假设我需要做的几件事:

  1. 获取将在文本视图中显示的字符串的字符数。
  2. 获取用户在其设备上的文本视图的视图宽度和高度
  3. 根据用户的设备尺寸,从字符计数中找出可以在文本视图中显示多少个字符。
  4. 无论我想出什么公式,都可以根据此公式动态选择文本量。

let count = str.count

let userWidth = UIScreen.main.bounds.size.width

let userHeight = UIScreen.main.bounds.size.height

但是,我无法提出任何可行的方法,即使这似乎也不是正确的方法。

关于如何开始创建电子阅读器翻页功能的任何建议?如果可以简化操作,我可以使用UIWebView代替UITextView。

谢谢!

1 个答案:

答案 0 :(得分:2)

您的方向正确,但是您的实现仅适用于等宽字体(Menlo,Courier等),因为比例字体(Helvetica,Times等)的字母宽度因字母而异。另外,您的计划中文字的中间会打断,这可能不是最佳选择。

TextKit提供了一些工具,可以使您更轻松地进行所有操作。如果要进行标准分页,而不是在单词边界处换行,可以使用NSLayoutManager来完成。

一些注意事项:

您不能使用屏幕宽度来准确计算视图的大小,因为您需要考虑安全区域和UITextView的textContainerInset。

我将分页给你。您可以通过从字符串中修剪前一页来计算页面的上一页,或者简单地在范围内前后移动。

func stringThatFitsOnScreen(originalString: String) -> String? {
    // the visible rect area the text will fit into
    let userWidth  = textView.bounds.size.width - textView.textContainerInset.right - textView.textContainerInset.left
    let userHeight = textView.bounds.size.height - textView.textContainerInset.top - textView.textContainerInset.bottom
    let rect = CGRect(x: 0, y: 0, width: userWidth, height: userHeight)

    // we need a new UITextView object to calculate the glyphRange. This is in addition to
    // the UITextView that actually shows the text (probably a IBOutlet)
    let tempTextView = UITextView(frame: self.textView.bounds)
    tempTextView.font = textView.font
    tempTextView.text = originalString

    // get the layout manager and use it to layout the text
    let layoutManager = tempTextView.layoutManager
    layoutManager.ensureLayout(for: tempTextView.textContainer)

    // get the range of text that fits in visible rect
    let rangeThatFits = layoutManager.glyphRange(forBoundingRect: rect, in: tempTextView.textContainer)

    // convert from NSRange to Range
    guard let stringRange = Range(rangeThatFits, in: originalString) else {
        return nil
    }

    // return the text that fits
    let subString = originalString[stringRange]
    return String(subString)
}

有更复杂的方法来混合和匹配文本视图,布局管理器和文本容器。只要掌握了简单的知识,就可以对其进行调查。