【问题标题】:Display partial lines of text on a deliberately truncated UITextView在故意截断的 UITextView 上显示部分文本行
【发布时间】:2020-01-15 11:25:14
【问题描述】:

互联网上有很多问题抱怨UITextView如何过早地切断文本,但我找不到任何关于你实际上想要之前切断文本的相反情况结束 - 但通过一条线。

似乎UITextView 只会渲染 discreet 行文本 - 即,如果它不够大,它不会渲染超出完全适合其中的最后一行。我正在寻找一种方法,让它将部分文本行渲染到底部边界。

即它目前在这里做左边的事情,而我正在寻找一种方法来做右边的事情:

我的UITextView 有一个固定的高度并且滚动被禁用。我正在分配attributedText,它可以有粗体、斜体等,而不是简单的字符串。

【问题讨论】:

    标签: ios uikit uitextview


    【解决方案1】:

    我认为您无法使用 UITextView 的属性来完成此操作。

    不过有一种方法:

    • 将文本视图嵌入“容器”UIView
    • 根据需要限制容器视图的高度
    • 将容器视图的Clips to Bounds设置为TRUE

    这将允许文本视图垂直增长以适应其文本,但容器视图将剪切您不希望看到的部分。

    容器视图背景为黄色,文本视图背景为青色:

    使用调试视图层次结构 - Show Clipped Content:

    这是 3D 视图:


    编辑

    这是另一种方法——可能会也可能不会满足您的要求...

    • UITextView - 设置位置和宽度和高度限制
    • 不可编辑
    • 可以选择
    • 启用滚动 - 这将显示部分行
    • 禁用显示滚动指示器

    现在,将UIPanGestureRecognizer 添加到该文本视图。它不需要做任何事情......但它会(至少看起来)阻止文本视图接收平移手势,从而阻止滚动。

    一个值得注意的问题...如果您有足够多的文本,那么当您开始选择时,您可以将选择手柄向下拖动到下一行并且文本 将向上滚动...可能会在代码中阻止这种情况,或者可能需要在用户复制所选文本后重置滚动。

    【讨论】:

    • 是的,我已经考虑过这一点 - 我无法立即让它工作,但会再试一次。我目前的调查是围绕 NSTextContainer 以及是否可以将大小覆盖为略大于文本视图但仍跟踪其整体大小
    • @andygeers - 我假设您使用的是UITextView,因为用户会与之交互?也就是说,它需要是可编辑和/或可选择的......它使用数据类型检测链接等?
    • 是的,在我的情况下,可选择的功能是呈现的原因 - 另外我可能在未来的某个日期也可以编辑
    • @andygeers - 我用另一种方法编辑了我的答案......可能合适也可能不合适,但也许值得一试。
    • 我发现如果我启用了滚动,那么文本视图将不再自动调整大小以适应内容 - 它只是保持较小
    【解决方案2】:

    好的,所以它很快就变得丑陋了,但我确实做到了......

    我不必使用通过 Interface Builder 创建的标准 UITextView,而是使用自定义 NSTextContainer 手动构建一个:

    let frame = containerView.frame
    
    let textStorage = NSTextStorage(string: "")
    let layoutManager = NSLayoutManager()
    
    let textContainer = CardTextContainer(size: CGSize(width: frame.size.width, height: CGFloat.greatestFiniteMagnitude))
    textContainer.widthTracksTextView = true
    
    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)
    
    let textView = UITextView(frame: frame, textContainer: textContainer)
    textView.isScrollEnabled = false
    
    containerView.addSubview(textView)
    

    然后,我将CardTextContainer 定义为NSTextContainer 的子类,将其行为委托给基类,除非呈现的行与NSTextView 的底部重叠:

    class CardTextContainer : NSTextContainer {
    
        override func lineFragmentRect(forProposedRect proposedRect: CGRect, at characterIndex: Int, writingDirection baseWritingDirection: NSWritingDirection, remaining remainingRect: UnsafeMutablePointer<CGRect>?) -> CGRect {
    
            let fragmentRect = super.lineFragmentRect(forProposedRect: proposedRect, at: characterIndex, writingDirection: baseWritingDirection, remaining: remainingRect)
    
            if ((fragmentRect.size.width > 0) || (fragmentRect.size.height > 0)) {
                // Just rely on the base implementation when it's working well
                return fragmentRect
            } else {
                // See if we could do slightly better than they did
                if (proposedRect.origin.y < self.size.height) {
                    return CGRect(origin: proposedRect.origin, size: CGSize(width: self.size.width, height: proposedRect.size.height))
                } else {
                    // Fall back to the 'I give up' solution
                    return fragmentRect
                }
            }        
        }    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-23
      • 1970-01-01
      • 2013-09-12
      • 1970-01-01
      • 2017-02-02
      • 1970-01-01
      • 2013-05-26
      相关资源
      最近更新 更多