Mor*_*n J 6 nslayoutmanager nstextview nsattributedstring textkit swift
我正在尝试创建一个自定义NSTextBlock,就像Apple在WWDC 18上(在23分钟内)所做的那样。
好的,所以当我用带有文本块的段落样式编辑和标记段落时,它的效果很好。
但是,当我剪切并粘贴它(或从磁盘归档/取消归档)时,它将丢失。编辑:它实际上将我的TweetTextBlock子类转换为NSTableViewTextBlock,这也说明了边界。
实作
这是完整的Xcode项目。使用Format顶部菜单项触发markTweet功能。
这是我将属性添加到段落的方法
@IBAction func markTweet(_ sender : Any?){
print("now we are marking")
let location = textView.selectedRange().location
guard let nsRange = textView.string.extractRange(by: .byParagraphs, at: location) else { print("Not in a paragraph"); return }
let substring = (textView.string as NSString).substring(with: nsRange)
let tweetParagraph = NSMutableParagraphStyle()
tweetParagraph.textBlocks = [TweetTextBlock()]
let twitterAttributes : [AttKey : Any] = [
AttKey.paragraphStyle : tweetParagraph,
AttKey.font : NSFont(name: "HelveticaNeue", size: 15)
]
textView.textStorage?.addAttributes(twitterAttributes, range: nsRange)
}
Run Code Online (Sandbox Code Playgroud)
这是我的NSTextBlock子类
import Cocoa
class TweetTextBlock: NSTextBlock {
override init() {
super.init()
setWidth(33.0, type: .absoluteValueType, for: .padding)
setWidth(70.0, type: .absoluteValueType, for: .padding, edge: .minX)
setValue(100, type: .absoluteValueType, for: .minimumHeight)
setValue(300, type: .absoluteValueType, for: .width)
setValue(590, type: .absoluteValueType, for: .maximumWidth)
backgroundColor = NSColor(white: 0.97, alpha: 1.0)
}
override func drawBackground(withFrame frameRect: NSRect, in controlView: NSView,
characterRange charRange: NSRange, layoutManager: NSLayoutManager) {
let frame = frameRect
let fo = frameRect.origin
super.drawBackground(withFrame: frame, in: controlView, characterRange:
charRange, layoutManager: layoutManager)
// draw string
let context = NSGraphicsContext.current
context?.shouldAntialias = true
let drawPoint: NSPoint = CGPoint(x: fo.x + 70, y: fo.y + 10)
let nameAttributes = [AttKey.font: NSFont(name: "HelveticaNeue-Bold", size: 15), .foregroundColor: NSColor.black]
var handleAttributes = [AttKey.font: NSFont(name: "HelveticaNeue", size: 15), .foregroundColor: NSColor(red: 0.3936756253, green: 0.4656872749, blue: 0.5323709249, alpha: 1)]
let nameAStr = NSMutableAttributedString(string: "Johanna Appleseed", attributes: nameAttributes)
let handleAStr = NSAttributedString(string: " @johappleseed · 3h", attributes: handleAttributes)
nameAStr.append(handleAStr)
nameAStr.draw(at: drawPoint)
let im = NSImage(named: "profile-twitter")!
im.draw(in: NSRect(x: fo.x + 10, y: fo.y + 10, width: 50, height: 50))
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试了什么
我的想法是可能发生这种情况,因为TextKit不知道如何从自定义块中存档属性。但是我尝试覆盖init:fromCoder和encode。他们不被叫。不可复制,粘贴,存档,取消存档。所以我想不是那样的。这使我认为所有这些自定义绘图逻辑都不能保存在属性字符串中,而这一切都发生在布局管理器中。那讲得通。但是我该如何坚持呢?
更新:我尝试读取属性。它具有一个段落样式,并且该段落样式在textBlocksarray属性中具有一个项目。但是那个文本块NSTextBlock不是我的子类(我试过if block is TweetTextBlock返回false)
更新2:我尝试覆盖诸如的属性classForArchiver,然后使用读取它们print("twb: Class for archiver", block.classForArchiver)。有趣的是,文本块已经变成了NSTextTableBlock!我现在对这种攻击非常了解,以至于我正在寻找一种将className存储在文本块中某处的方法。到目前为止,我唯一能想到的就是该tooltip属性,但是它对于用户是可见的,因此我可能想将其用于其他用途。
更新3:工具提示也没有保留。这很奇怪。我能想到的下一个大技巧是将文本颜色设置为HSB(n,0,0),其中n是NSTextBlock子类的标识符。希望我不必去那里。
更新4。这很可能是由于归档以及将字符串转换为RTF的复制/粘贴操作所引起的。这是public.rtf我的剪贴板
{\rtf1\ansi\ansicpg1252\cocoartf2509
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 HelveticaNeue;}
{\colortbl;\red255\green255\blue255;\red245\green245\blue245;}
{\*\expandedcolortbl;;\csgray\c97000;}
\pard\intbl\itap1\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
\f0\fs30 \cf0 THIS text is in a TweetTextBlock}
Run Code Online (Sandbox Code Playgroud)
小智 0
看来 NSAttributedString 有某种错误。我尝试子类化 NSMutableParagraphStyle 并使用它,但它没有被编码或解码(init)。
可以简单地使用自定义 Attribute.Key 来注释文本运行,指示块内容及其“类型”的描述,然后在粘贴后对 AttributedString 进行后处理。
或者,开箱即用的粘贴板类型可能不支持和存档 NSAttributedString。相反,(我猜测)最高保真度的文本类型可能是 RTF,这可能解释了根本不调用 TextBlock NSCoding 方法的事实。
看看NSPasteboard.PasteboardType我的投票是选项 2。
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |