9

NSTextStorageリンクの強調表示を行うためにサブクラス化を行っており、このトピックについてできる 限り多くのことを読みました。絵文字を入力するまで、すべて正常に動作します。

私のサブクラス:

private let ims = NSMutableAttributedString()

override var string: String {
    return ims.string
}

override func attributesAtIndex(location: Int, effectiveRange range: NSRangePointer) -> [String : AnyObject] {
    return ims.attributesAtIndex(location, effectiveRange: range)
}

override func replaceCharactersInRange(range: NSRange, withString str: String) {
    ims.replaceCharactersInRange(range, withString: str)
    self.edited(.EditedCharacters, range: range, changeInLength:(str as NSString).length - range.length)
}

override func setAttributes(attrs: [String : AnyObject]?, range: NSRange) {
    ims.setAttributes(attrs, range: range)
    self.edited(.EditedAttributes, range: range, changeInLength: 0)
}

複雑なことは何もありません。次に、悪名高い文字を入力すると、何らかのランダムな理由で Courier New に切り替わります。

Courier New以外は何でも!

今、私はキャラクターを選んでいます.この狂気を引き起こす他の人もいます. 入力時にフォントを照会しましたが、System > Apple Emoji > Courier New から取得できます。

processEditing()また、セミが問題を解決するフォントを設定しようとしました。これにより、余分なスペースが追加されます(シミュレーターではありません)。そして、値をハードコーディングしています == 悪い。

究極の質問:

私は何を間違っていますか?開発者が NSTextStorage をサブクラス化したと確信している他の人の実装では、この問題は見られません。

注: objc.io のデモ アプリでも同じ問題が発生していることを確認できます。

4

3 に答える 3

3

これが私の素人の理解です。ほとんどの絵文字は、Apple の AppleColorEmoji フォントにのみ存在します。絵文字を入力すると、NSTextStorage が を呼び出しprocessEditing、それが を呼び出しますfixAttributesInRange。この方法により、文字列内の不足している文字が、それらをサポートするフォントに置き換えられます。文字列に絵文字が含まれている場合、絵文字を含むすべての範囲が AppleColorEmoji フォント属性を取得します。

残念ながら、この新しいフォント属性がその後に入力された文字に「感染」することを止めるものは何もありません。AppleColorEmoji には通常の ASCII セットが含まれていないように見えるため、それらの後続の文字はモノスペース フォントで「固定」されます。

それについて何をすべきか?私のプログラムでは、コピー アンド ペーストしたテキストで新しいスタイルをテキストに追加したくないので、テキスト ストレージの属性を手動で管理したいと考えています。これは、これを簡単に実行できることを意味します。

override func setAttributes(attrs: [String : AnyObject]?, range: NSRange) {
    if self.isFixingAttributes {
        self.attributedString.setAttributes(attrs, range: range)
        self.edited(NSTextStorageEditActions.EditedAttributes, range: range, changeInLength: 0)
    }
}

override func fixAttributesInRange(range: NSRange) {
    self.isFixingAttributes = true
    super.fixAttributesInRange(range)
    self.isFixingAttributes = false
}

override func processEditing() {
    // not really fixing -- just need to make sure setAttributes follows orders
    self.isFixingAttributes = true
    self.setAttributes(nil, range: self.editedRange)
    self.setAttributes(self.dynamicType.defaultAttributes(), range: self.editedRange)
    self.isFixingAttributes = false

    super.processEditing()
}

新しいテキストが入力されるたびに、その属性をクリアし (以前に修正された範囲のいずれかが「感染」した場合)、デフォルトの属性に置き換えます。その後、その処理をsuper.processEditing()実行し、その範囲内の新しい欠落文字を修正します (存在する場合)。

一方、スタイル付きテキストをテキスト ビューに貼り付けたい場合は、 の前後を比較して固定範囲を追跡し、fixAttributesInRangeそれらのスタイルが新しく入力されたテキストに転送されないようにする必要があります。でprocessEditing

于 2016-09-12T18:09:30.597 に答える
1

私はこの問題を何時間も調査しました。したがって、結論として、絵文字文字を挿入 (入力または貼り付け) するか、絵文字文字の後にカーソルを置く (例: ☺️) と、入力フォントが「AppleColorEmoji」に変更され、最終的に「Courier New」にフォールバックしていました。絵文字が挿入されます。これは、サブクラスが使用されている場合にのみ発生NSTextStorageします。それ以外の場合、入力フォントが「AppleColorEmoji」に変更されることはありません。そのため、入力フォントを AppleColorEmoji から開発者が設定したデフォルトのフォントにリセットすることで修正します。修正は前後に適用されますテキストの挿入。前者は絵文字の後にカーソルを置くことによるタイピングフォントの変更を修正し、後者は絵文字の挿入によるタイピングフォントの変更を修正します(タイピングフォントの変更はUITextView.fontパラメータに何らかの形で反映されます)。

https://github.com/CosmicMind/Material/pull/1117を参照してください。

class EmojiFixedTextView: UITextView {
    private var _font: UIFont?

    override var font: UIFont? {
        didSet {
            _font = font
        }
    }

    override func insertText(_ text: String) {
        fixTypingFont()
        super.insertText(text)
        fixTypingFont()
    }

    override func paste(_ sender: Any?) {
        fixTypingFont()
        super.paste(sender)
        fixTypingFont()
    }

    private func fixTypingFont() {
        let fontAttribute = NSAttributedStringKey.font.rawValue
        guard (typingAttributes[fontAttribute] as? UIFont)?.fontName == "AppleColorEmoji" else {
            return
        }

        typingAttributes[fontAttribute] = _font
    }
}
于 2018-07-18T21:03:10.717 に答える