Я пытаюсь создать собственный 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)
}
И это мой 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)
}
}
Что я пробовал
Я думаю, что это может произойти, потому что TextKit не знает, как архивировать атрибуты из пользовательского блока. Но я попытался переопределить init:fromCoder
и encode
. Им не звонят. Не копировать, вставлять, архивировать, разархивировать. Так что я полагаю, что это было не так. Это заставляет меня думать, что всю эту пользовательскую логику рисования нельзя сохранить в атрибутивной строке, и что все это происходит в менеджере макета. Это имеет смысл. Но как мне сохранить блок, тогда?
ОБНОВЛЕНИЕ: я попытался прочитать атрибуты. У него есть стиль абзаца, а у этого стиля абзаца есть элемент в свойстве textBlocks
array. Но этот текстовый блок является 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}