首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSTextAttachment图像不是动态的(光/暗模式)

NSTextAttachment图像不是动态的(光/暗模式)
EN

Stack Overflow用户
提问于 2022-02-06 15:16:06
回答 2查看 439关注 0票数 1

我有一个图像,是动态的光/暗模式。如果我将此图像放置在UIImageView中,则动态工作:当用户从光模式切换到黑暗模式并返回时,图像会改变显示的自身版本。但是,如果我在NSAttributedString中放置与NSTextAttachment相同的图像,并将字符串显示在标签中,则动态无法工作:当用户从光模式切换到黑暗模式时,图像不会改变。

若要查看实际问题,请将此代码粘贴到viewDidLoad中。

代码语言:javascript
复制
    let size = CGSize(width: 20, height: 20)
    let renderer = UIGraphicsImageRenderer(size: size)
    let image1 = renderer.image {
        UIColor.red.setFill()
        $0.fill(.init(origin: .zero, size: size))
    }
    let image2 = renderer.image {
        UIColor.green.setFill()
        $0.fill(.init(origin: .zero, size: size))
    }
    let asset = UIImageAsset()
    asset.register(image1, with: .init(userInterfaceStyle: .light))
    asset.register(image2, with: .init(userInterfaceStyle: .dark))

    let iv = UIImageView(image: image1)
    iv.frame.origin = .init(x: 100, y: 100)
    self.view.addSubview(iv)

    let text = NSMutableAttributedString(string: "Howdy ", attributes: [
        .foregroundColor: UIColor(dynamicProvider: { traits in
            switch traits.userInterfaceStyle {
            case .light: return .red
            case .dark: return .green
            default: return .red
            }
        })
    ])
    let attachment = NSTextAttachment(image: image1)
    let attachmentCharacter = NSAttributedString(attachment: attachment)
    text.append(attachmentCharacter)

    let label = UILabel()
    label.attributedText = text
    label.sizeToFit()
    label.frame.origin = .init(x: 100, y: 150)
    self.view.addSubview(label)

我故意使文本字体颜色动态,这样您就可以看到,一般说来,颜色动态在属性化字符串中确实有效。但不是在属性化字符串的文本附件中!

所以:这真的是iOS的行为方式吗,还是我在配置文本附件时犯了一些错误?如果这是iOS的行为方式,那么您是如何解决这个问题的?

请注意,我不能使用iOS 15附件视图提供程序,因为我必须与iOS 13和14兼容。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-02-07 14:52:28

我认为这是很不幸的正常行为,但我认为这是一个被苹果遗忘的非开发功能。

我目前得到的唯一方法是听func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)来检测模式的变化。

然后,您可以重构您的NSAttributedString,或者在需要时对其进行枚举和更新。

使用枚举,即只更新所需的内容,而不是重新生成整个NSAttributedString

在你最初的依恋创造中:

代码语言:javascript
复制
let attachment = NSTextAttachment(image: asset.image(with: traitCollection))
let attachmentCharacter = NSAttributedString(attachment: attachment)

附带注意:我使用asset.image(with: traitCollection)而不是image1,否则当开始使用黑暗模式时,您的图像将是光模式。因此,这应该设置正确的图像。

然后,我会用以下方式更新:

代码语言:javascript
复制
func switchAttachment(for attr: NSAttributedString?) -> NSAttributedString? {
    guard let attr = attr else { return nil }
    let mutable = NSMutableAttributedString(attributedString: attr)
    mutable.enumerateAttribute(.attachment, in: NSRange(location: 0, length: mutable.length), options: []) { attachment, range, stop in
        guard let attachment = attachment as? NSTextAttachment else { return }
        guard let asset = attachment.image?.imageAsset else { return }
        attachment.image = asset.image(with: .current)
        mutable.replaceCharacters(in: range, with: NSAttributedString(attachment: attachment))
    }
    return mutable
}

并在下列情况下更新:

代码语言:javascript
复制
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)        
    label.attributedText = switchAttachment(for: label.attributedText)
}
票数 2
EN

Stack Overflow用户

发布于 2022-02-07 16:22:07

为了记录在案,这是我对Larme建议的改写。我在UILabel上做了一个扩展:

代码语言:javascript
复制
extension UILabel {
    func updateAttachments() {
        guard let attributedString = attributedText else { return }
        let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
        attributedString.enumerateAttribute(.attachment, in: .init(location: 0, length: attributedString.string.utf16.count), options: []) { value, range, stop in
            guard let attachment = value as? NSTextAttachment else { return }
            guard let image = attachment.image else { return }
            guard let asset = image.imageAsset else { return }
            attachment.image = asset.image(with: .current)
            mutableAttributedString.setAttributes([.attachment: attachment], range: range)
        }
        attributedText = mutableAttributedString
    }
}

现在,假设我引用了一个麻烦的UILabel:

代码语言:javascript
复制
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
    guard let previousTraitCollection = previousTraitCollection else { return }
    if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
        label.updateAttachments()
    }
}

将该覆盖注入到所有UILabels中非常好,这样他们就可以自己更新,但不幸的是,扩展不能这样工作,而且我不能将我的应用程序中的所有UILabels转换为UILabel子类。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71008562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档