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

如果你根据标题来到这个问题上,但是对蒙古人不感兴趣,你可能会在寻找这个问答:

  • Swift:如何为UIButton和UILabel旋转文本?

我一直在学习Swift,以便为传统的蒙古语开发iOS应用程序。 问题是传统的蒙古文是从上到下,从左到右的垂直书写。 我的问题是如何垂直显示文本,仍然有线包装工作?

如果你留在我身边一会儿,我会试着更清楚地解释这个问题。 下面是我想要实现的那种文本视图的图像。 如果外文脚本丢掉了,我已经包含了遵循相同模式的英文文本。 事实上,如果应用程序有任何英文文本显示,这是它应该看起来。

在这里输入图像说明

对于一个简单的单线UILabel,90度顺时针旋转将起作用。 但是,对于多行UITextView,我需要处理换行。 如果我只是做一个简单的90度旋转,写的第一件事就会落在最后一行。

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

  1. 制作所有字母垂直镜像的自定义字体。
  2. 顺时针旋转文本视图90度。
  3. 水平镜像文本视图。

在这里输入图像说明

这应该照顾文本换行。

我可以做镜像字体。 但是,我不知道如何做UITextView的旋转和镜像的Swift编码。 我发现下面的链接似乎给解决scheme的一部分提示,但是它们都在Objective C中,而不是在Swift中。

  • 如何旋转他们自己的中心周围的子视图?
  • 围绕其中心旋转UIView保持其大小
  • iOS:在屏幕上镜像内容
  • 镜像UIView

在app store里有传统的蒙古应用程序(比如这个和这个 ),但是我还没有find任何人分享他们的源代码,所以我不知道他们在幕后做了什么来显示文本。 我打算让自己的代码是开源的,这样对于其他人来说,为了阅读传统蒙古语的数百万人开发应用程序并不难。 任何援助,你可以给这个努力,将不胜感激,不仅由我,而且蒙古人民。 即使你不了解自己,提出这个问题,使其更明显将有所帮助。

更新

@ sangonz的答案仍然是一个很好的答案,但是我暂时没有把它作为被接受的答案,因为我不能让所有的东西都起作用。 特别:

  • 启用滚动(通过在滚动视图中embedded自定义视图或通过inheritanceUIScrollView )。 在github项目中,@sangonz说这应该很容易,但这不适合我。
  • 根据方向更改获得重新布局(而不是拉伸)字线。 我觉得这应该不是太难以解决多一点研究。
  • 为什么文本行不能一直走到视图的边缘呢? 底部有一个很大的差距。
  • 如何从另一个UITextView中断开自定义垂直视图的NSTextStorage。 (看这个问题 )

到目前为止, 我一直在使用我上面提出的原始方法 ,但是我真正想要的是像@sangonz提出的那样工作。

我现在也在考虑类似的替代方法

  • 使用核心文本 ,缺点:感觉就像重新发明轮子
  • 使用WebKit ,缺点:Apple不再为他们的UITextView使用WebKit

编辑:这是我终于做到了。

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

没有什么幻想,但它的作品。 最后,我不得不混合TextKit和image processing。 看看代码。 它涉及:

  1. NSTextContainer以获得正确的文本维度。
  2. 创build一个自定义的UIView来渲染文本应用仿射变换到每一行和使用NSLayoutManager呈现保持所有的TextKitfunction。

TextKit的方式

保持所有本地文本优点(例如突出显示,select…)的正确方法是使用标准的TextKit API。 你提出的方法会打破所有这些或可能导致奇怪的行为。

但是,iOS中的TextKit看起来并不支持垂直方向的开箱即用,但它已经做好了准备。 作为一个侧面说明,在OS X中它有点支持,你可以调用textView.setLayoutOrientation(.Vertical) ,但是它仍然有一些限制。

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

来源: UIKit> NSTextLayoutOrientationProvider于iOS的NSTextLayoutOrientationProvider协议参考

总之 ,你应该开始NSTextContainer ,你将不得不处理NSLayoutManagerNSTextContainer


自定义image processing方式

另一方面,如果您决定遵循您的自定义文本呈现,我build议采用以下方法。

  1. 使用普通字体将正常文本渲染到隐藏层。 给它的边界框正确的大小。
  2. 获取文本属性 ,主要是文本高度和行距。
  3. 如下图所示,按照从下到上的顺序逐行处理图像。 结果你应该得到一个新的CGImage
  4. 旋转图像创build一个UIImage并设置正确的UIImageOrientation值。
  5. 将该图像插入仅允许水平滚动的UIScrollView

要小心这个方法呈现整个文本,所以不要用它很长的文本。 如果你需要这样做,你将需要考虑平铺的方法。 观看WWDC 2013> 217 – 探索iOS 7上的滚动视图 。

这个图片

祝你好运!

更新:(从github项目的图像)

在这里输入图像说明

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

你应该能够设置标签/ textview的transform属性:

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

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

好消息是手势和水龙头在像素的同时被转换,所以控件继续以你期望的方式工作。