将文本垂直居中在不规则形状的UITextView中

时间:2016-04-07 10:19:50

标签: ios uitextview vertical-alignment core-text textkit

我正致力于在圆形或椭圆形区域的中心渲染文字。理想情况下,我希望将文本垂直和水平居中,但让它在区域的边界自然流动。

我找到了一种方法,使用UITextViewNSTextContainer排除路径,可以很好地将文本布置在水平居中的给定垂直偏移处(下面的代码)。但是,我不确定如何实现垂直居中。

我已经看过的方法都建议在文本布局后调整文本视图的contentInset并确定最终高度。 (例如,this question)但是,对于形状不规则的区域,文本布局后的文本高度将取决于区域布局的起始位置。

我考虑过的方法是重试布局过程,直到实现令人满意的布局。有没有人用这种方法取得成功?这里的一个挑战是我还没有弄清楚如何确定是否所有文本都已在视图中呈现(即是否有足够的空间来布置所有文本)---是否有办法查询是否所有内容都已呈现'什么时候使用UITextView?

最后:这只是用于显示文本---不需要允许用户编辑视图的内容。在这种情况下CoreText或许会更好吗?

我对iOS开发还是比较陌生的,所以如果我做了一件令人发指的事情,那么知道也会有所帮助!

谢谢!

let boundingRect = CGRect(...)
let textView = UITextView(frame: boundingRect)

textView.editable = false
view.addSubview(textView)

let verticalInset:CGFloat = <some value>

let width = boundingRect.width
let height = boundingRect.height
let textBounds = CGSize(width: width, height:height - 2*verticalInset)
textView.bounds = textBounds

let exclusionRect = CGRect(x:0, y:-verticalInset, width:width, height:height)

let textRegion = UIBezierPath(ovalInRect: exclusionRect)    
let exclusionPath = UIBezierPath(rect:exclusionRect)
exclusionPath.appendPath(textRegion.bezierPathByReversingPath())

textView.textContainer.exclusionPaths = [exclusionPath]

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .Center

let attributes = [NSParagraphStyleAttributeName: paragraphStyle]
let formattedContent = NSAttributedString(string: "....", attributes:attributes)

textView.attributedText(formattedContent)

如果有帮助的话,这里有一张图片可以帮助您看到上述内容: example

2 个答案:

答案 0 :(得分:2)

如果您在矩形区域中布置文本,则可以通过向上或向下移动来轻松地将其垂直居中。如果该区域不是矩形,就像在您的情况下,这是不可能的,因为文本在垂直移动后不一定适合形状。

我认为对此的解决方案始终是一种迭代方法。例如:使用增加的insets渲染形状中的文本,并找到最大的插入,以便文本适合生成的形状。

要使用Core Text执行此操作,您可以为文本布局创建CTFrame,如下所示:

let text:NSAttributedString = ... // The text to render
let path:CGPath = ... // Bounds the shape in which the text is rendered
let framesetter = CTFramesetterCreateWithAttributedString(text)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)

使用此frame,您可以检查是否已呈现整个字符串:

let range = CTFrameGetVisibleStringRange(frame)
if text.length == range.length {
  // Fits
}

并呈现文字:

let ctx:CGContext = ... 
CTFrameDraw(renderFrame, ctx)

如果您需要有关呈现文字的更多详细信息,可以使用CTFrameGetLinesCTLine获取frame。然后,使用CTFrameGetLineOriginsCTLineGetBoundsWithOptions选项UseGlyphPathBoundsUseOpticalBounds,您可以计算单行的光学边界。这允许更精确的垂直调整。 (支持一些线性代数,直接将CoreText与CoreGraphics一起使用所需的坐标系转换可能有点单调乏味。)

答案 1 :(得分:0)

我不能在这里提供一个很棒的答案。

但是,我刚试过YYText。它有一个“YYLabel”,支持垂直文本对齐和排除路径。看一下他们的Demo项目,特别是他们的tableview中的'TextAttributes1'行演示。