如何在Swift中为iOS创建垂直文本UILabel和UITextView?

时间:2015-02-16 15:24:40

标签: ios swift uilabel uitextview mongolian-vertical-script

如果您根据标题提出这个问题,但对蒙古语不感兴趣,那么您可能正在寻找此Q& A:


为了开发traditional Mongolian的iOS应用,我一直在学习Swift。问题是传统的蒙古语是从上到下,从左到右垂直书写的。我的问题是如何垂直显示文本并仍然有换行功能?

如果你和我待在一起,我会尝试更清楚地解释问题。下面是我想要实现的文本视图的图像。如果外国脚本将你抛弃,我已经包含了遵循相同模式的英文文本。事实上,如果应用程序有任何英文文本要显示,这就应该是它的外观。

enter image description here

对于简单的单线UILabel,顺时针旋转90度就可以了。但是,对于多行UITextView,我需要处理换行。如果我只做一个普通的90度旋转,那么写的第一件事最终会在最后一行。

到目前为止,我已经制定了一个我认为可以解决这个问题的计划:

  1. 制作一个自定义字体,其中所有字母都是垂直镜像的。
  2. 顺时针旋转文本视图90度。
  3. 水平镜像文本视图。
  4. enter image description here

    那应该照顾文字换行。

    我可以使用镜像字体。但是,我不知道如何为UITextView的旋转和镜像执行Swift编码。我发现以下链接似乎给解决方案的某些部分提供了提示,但它们都在Objective C中,而不是在Swift中。

    应用商店中有传统的蒙古应用(例如thisthis),但我还没有找到任何人分享他们的源代码,所以我不会知道他们在幕后做什么来显示文字。我打算让我的代码开源,以便将来的其他人不会为数百万阅读传统蒙古语的人开发应用程序。你可以给予这项努力的任何帮助,不仅是我,也是蒙古人民。即使你不了解自己,提出这个问题以使其更加明显也会有所帮助。

    更新

    @ sangonz的回答仍然是一个很好的答案,但我暂时将其标记为已接受的答案,因为我无法让一切顺利。具体做法是:

    • 启用滚动(通过在滚动视图或subclassing UIScrollView中嵌入自定义视图)。在github项目中,@ sangonz说这应该很简单,但对我来说不是。
    • 在方向更改上获得字线的重新布局(而非拉伸)。我认为通过更多的研究来解决这个问题并不难。
    • 为什么文本行不会一直走到视图的边缘?底部有一个很大的差距。
    • 如何取消自定义垂直视图的NSTextStorage与其他UITextView的链接。(请参阅this question

    到目前为止I have been using the original method我在上面提出过,但我真正想要的是得到@sangonz提议的工作方式。

    我现在也在考虑替代方法,比如

2 个答案:

答案 0 :(得分:19)

编辑:这就是我最终做到的。

这是我的GitHub中的一个非常基本的实现:Vertical-Text-iOS

没什么特别的,但它确实有效。最后我不得不混合TextKit和图像处理。看看代码。它涉及:

  1. NSTextContainer进行子类化以获得正确的文字尺寸。
  2. 创建自定义UIView以呈现对每行应用仿射变换的文本,并使用NSLayoutManager进行渲染以保留所有TextKit功能。

  3. TextKit方式

    保持所有原生文本优势(例如突出显示,选择...)的正确方法是使用标准TextKit API。你提议的方法会破坏所有这些或者可能导致奇怪的行为。

    然而,看起来像iOS中的TextKit还不支持开箱即用的垂直方向,但它已经为此做好了准备。作为旁注,在OS X中它有所支持,您可以调用textView.setLayoutOrientation(.Vertical),但它仍然有一些限制。

      

    NSTextLayoutOrientationProvider协议定义了一个接口   为符合条件的文本提供默认方向   对象,没有明确的NSVerticalGlyphFormAttributeName   属性。唯一实现此接口的UIKit类是   NSTextContainer,其默认实现返回   NSTextLayoutOrientationHorizontal。一个NSTextContainer子类   处理垂直文本可以将此属性设置为   NSTextLayoutOrientationVertical支持自定义布局   定向逻辑。

    来源:UIKit > NSTextLayoutOrientationProvider Protocol Reference for iOS

    总之,您应该开始对NSTextContainer进行子类化,并且您必须经常处理NSLayoutManagerNSTextContainer


    自定义图像处理方式

    另一方面,如果您决定按照自定义文本呈现方式,我建议采用以下方法。

    1. 将普通文字渲染为具有普通字体的隐藏图层。给它的边界框大小正确。
    2. 获取文字属性,主要是文字高度和行间距。
    3. 处理图像从下到上以相反的顺序绘制每一行,如下图所示。你应该得到一个新的CGImage
    4. 旋转图片,创建UIImage并设置正确的UIImageOrientation值。
    5. 将该图片插入只允许水平滚动的UIScrollView
    6. 请注意此方法会呈现整个文本,因此请勿将其用于很长的文本。如果您需要这样做,则需要考虑平铺方法。观看WWDC 2013 > 217 - Exploring Scroll Views on iOS 7

      this image

      祝你好运!

      更新:(来自github项目的图片)

      enter image description here

答案 1 :(得分:3)

如果您要旋转文字,我建议使用从右到左的布局,以便您可以跳过镜像步骤(只需旋转另一种方式)。

您应该只需设置标签/ textview' transform属性:

view.transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(CGFloat(-M_PI_2)), view.bounds.width, view.bounds.height)

旋转后需要翻译,因为视图围绕其原点(左上角)旋转。

好消息是手势和点击在像素同时被转换,因此控件继续以您期望的方式工作。