如何使用NSTextView实现从右侧起始的可滚动竖排文本?
日语、中文等语言支持竖排书写规则:从页面右上角起始向下书写,写至页面底部后向左换行,再从新行顶部继续向下排布。NSTextView 原生支持该排版模式,可通过如下代码开启:
textView.setLayoutOrientation(.vertical)
同时Storyboard中也提供了对应的配置选项。
单独使用NSTextView时该功能表现正常,文本确实会从文本视图右上角开始排布,但将NSTextView嵌入滚动视图做成可滚动文本视图时就会出现异常。
在Storyboard中添加“Scrollable Text View(可滚动文本视图)”后,NSTextView会莫名无法填满整个滚动视图,如图中白色小方块标注所示:
(注:仅为滚动视图添加了贴合窗口四周边缘的约束)
该表现不符合预期:文本视图本应填满整个滚动视图,让文本从窗口最右侧开始排布,但拖动窗口右侧边缘放大窗口时,文本视图完全不会同步扩张宽度。
文本视图仅在输入更多内容时才会扩张,切换为横排模式则完全不会出现上述异常。
通过代码方式创建文本视图依然会复现相同问题,复现代码如下:
let scrollView = NSTextView.scrollableTextView() view.addSubview(scrollView) scrollView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor), scrollView.leftAnchor.constraint(equalTo: view.leftAnchor), scrollView.rightAnchor.constraint(equalTo: view.rightAnchor), ]) let textView = scrollView.documentView as! NSTextView textView.textStorage?.setAttributedString( NSAttributedString(string: "あいうえおかきくえこ", attributes: [ .font: NSFont.systemFont(ofSize: 25), .foregroundColor: NSColor.textColor ]) ) textView.setLayoutOrientation(.vertical)
修复方案
该异常并非NSTextView不支持滚动场景下的竖排布局,核心原因是竖排模式下作为滚动视图documentView的NSTextView,默认的尺寸自适应规则没有匹配滚动容器的宽度变化,手动修改两项配置即可修复:
- 配置文本视图的自动调整掩码,让其宽度跟随父滚动视图同步变化
- 设置文本视图的最小宽度等于滚动视图的可视区域宽度,避免其收缩到小于容器尺寸
在设置竖排布局的代码后追加如下两行代码即可:
// 宽度跟随滚动视图自动调整 textView.autoresizingMask = [.width] // 最小宽度匹配滚动视图可视区域宽度 textView.minSize = NSSize(width: scrollView.contentSize.width, height: 0)
如果是通过Storyboard创建的可滚动文本视图,直接在NSTextView的尺寸检查器面板中,找到Autoresizing配置项,勾选宽度方向的自适应规则,同时将最小宽度设置为滚动视图的对应宽度即可。
如果需要支持窗口拖拽缩放时文本视图宽度实时同步,监听滚动视图的didEndLiveResize通知,在回调中更新textView.minSize.width为最新的scrollView.contentSize.width即可,避免窗口放大后文本视图宽度不跟进。
配置完成后文本视图会始终填满滚动视图区域,竖排文本默认从视图最右上角开始排布,内容超出高度时可正常滚动,横排/竖排切换也不会出现布局错乱。
内容的提问来源于stack exchange,提问作者Sweeper

