NightNight in Swift to change themes, problem with attributedText












0















I am currently experimenting with NightNight, an easy-to-use library to add light and dark themes to an app. I recommend looking into it if you are interested in adding two themes to your app.



That being said, it works like a charm. It is not fully supported yet, e.g. I am missing the ability to set the shadowImage of a UITabBarController to change the "top border" or separator, but I guess I can add this later by diving into the source.



One problem I am facing now, is that I am unable to change the color of attributedText of a UITextView. I definitely need to use the attributedText property because I want to add lineHeightMultiple. I got everything to work, but the color does not change when I switch between themes.



The UITextView is part of a UICollectionViewCell, so it is reused. Whenever I restart the app or start scrolling in the UICollectionView, the text is updated (sometimes - because of the reuse, it sometimes does not update when the cell remains visible on screen). It feels to me like I need to update or reload something else in order to get this library to work as I need.



Currently I set up my TextView like this:



let customTextViewStyle = NSMutableParagraphStyle()
customTextViewStyle.lineHeightMultiple = 1.2

let attributedString = NSMutableAttributedString(string: "This is the text that will be shown inside the TextView")

attributedString.setMixedAttributes([NNForegroundColorAttributeName: MixedColor(normal: lightCustomTextViewFontColor, night: darkCustomTextViewFontColor)], range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: customTextViewStyle, range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: normalFontSize), range: NSRange(location: 0, length: attributedString.length))

customTextView.attributedText = attributedString


Below is a fragment of the source file from NightNight, which is called NSMutableAttributedString, where an observer is added:



public extension NSMutableAttributedString {
fileprivate struct AssociatedKeys {
static var mixedAttrsKey = "mixedAttrs"
}

fileprivate var mixedAttrs: [String: [NSRange: MixedColor]] {
get {
if let dict = objc_getAssociatedObject(self, &AssociatedKeys.mixedAttrsKey) as? [String : [NSRange : MixedColor]] {
return dict
}
self.mixedAttrs = [:]

MixedColorAttributeNames.forEach { (mixed) in
self.mixedAttrs[mixed] = [:]
}

return self.mixedAttrs
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.mixedAttrsKey, newValue as AnyObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

addNightObserver(#selector(_updateTitleAttributes))
}
}
}


Then _updateTitleAttributes looks like this:



@objc func _updateTitleAttributes() {

MixedColorAttributeNamesDictionary.forEach { (mixed, normal) in
if let foregroundColorDictionary = mixedAttrs[mixed] {
foregroundColorDictionary.forEach({ (range, mixedColor) in
self.addAttribute(normal, value: mixedColor.unfold(), range: range)
})
}

}
}


I would highly appreciate a solution to this issue, as I myself am unable to figure it out. Does it have something to do with the source - e.g. does it not update properly? Does it have something to do with my UICollectionViewCell?



Thanks in advance!










share|improve this question























  • Make sure you only use attributedText property on your textView and not mixing usage of text and attributedText. If that's not an issue try to reset text in your cell class in prepareForReuse method. myTextView.attributedText = nil

    – inokey
    Nov 15 '18 at 15:23













  • Both don't work. However, I will continue using prepareForReuse on my UITextView as well, so thanks for the heads up on that. I have a working solution right now but it's not as neat as I would want it to be: I add an observer for the notification that changes the theme (NightNightThemeChangeNotification). Next, in the function paired to it, I get all .visibleCells, run them in a for loop and add the attributes again. This works, but it is probably not the best solution. If nothing better comes up, I'll add this solution as an answer so others can learn from it.

    – PennyWise
    Nov 15 '18 at 15:31
















0















I am currently experimenting with NightNight, an easy-to-use library to add light and dark themes to an app. I recommend looking into it if you are interested in adding two themes to your app.



That being said, it works like a charm. It is not fully supported yet, e.g. I am missing the ability to set the shadowImage of a UITabBarController to change the "top border" or separator, but I guess I can add this later by diving into the source.



One problem I am facing now, is that I am unable to change the color of attributedText of a UITextView. I definitely need to use the attributedText property because I want to add lineHeightMultiple. I got everything to work, but the color does not change when I switch between themes.



The UITextView is part of a UICollectionViewCell, so it is reused. Whenever I restart the app or start scrolling in the UICollectionView, the text is updated (sometimes - because of the reuse, it sometimes does not update when the cell remains visible on screen). It feels to me like I need to update or reload something else in order to get this library to work as I need.



Currently I set up my TextView like this:



let customTextViewStyle = NSMutableParagraphStyle()
customTextViewStyle.lineHeightMultiple = 1.2

let attributedString = NSMutableAttributedString(string: "This is the text that will be shown inside the TextView")

attributedString.setMixedAttributes([NNForegroundColorAttributeName: MixedColor(normal: lightCustomTextViewFontColor, night: darkCustomTextViewFontColor)], range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: customTextViewStyle, range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: normalFontSize), range: NSRange(location: 0, length: attributedString.length))

customTextView.attributedText = attributedString


Below is a fragment of the source file from NightNight, which is called NSMutableAttributedString, where an observer is added:



public extension NSMutableAttributedString {
fileprivate struct AssociatedKeys {
static var mixedAttrsKey = "mixedAttrs"
}

fileprivate var mixedAttrs: [String: [NSRange: MixedColor]] {
get {
if let dict = objc_getAssociatedObject(self, &AssociatedKeys.mixedAttrsKey) as? [String : [NSRange : MixedColor]] {
return dict
}
self.mixedAttrs = [:]

MixedColorAttributeNames.forEach { (mixed) in
self.mixedAttrs[mixed] = [:]
}

return self.mixedAttrs
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.mixedAttrsKey, newValue as AnyObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

addNightObserver(#selector(_updateTitleAttributes))
}
}
}


Then _updateTitleAttributes looks like this:



@objc func _updateTitleAttributes() {

MixedColorAttributeNamesDictionary.forEach { (mixed, normal) in
if let foregroundColorDictionary = mixedAttrs[mixed] {
foregroundColorDictionary.forEach({ (range, mixedColor) in
self.addAttribute(normal, value: mixedColor.unfold(), range: range)
})
}

}
}


I would highly appreciate a solution to this issue, as I myself am unable to figure it out. Does it have something to do with the source - e.g. does it not update properly? Does it have something to do with my UICollectionViewCell?



Thanks in advance!










share|improve this question























  • Make sure you only use attributedText property on your textView and not mixing usage of text and attributedText. If that's not an issue try to reset text in your cell class in prepareForReuse method. myTextView.attributedText = nil

    – inokey
    Nov 15 '18 at 15:23













  • Both don't work. However, I will continue using prepareForReuse on my UITextView as well, so thanks for the heads up on that. I have a working solution right now but it's not as neat as I would want it to be: I add an observer for the notification that changes the theme (NightNightThemeChangeNotification). Next, in the function paired to it, I get all .visibleCells, run them in a for loop and add the attributes again. This works, but it is probably not the best solution. If nothing better comes up, I'll add this solution as an answer so others can learn from it.

    – PennyWise
    Nov 15 '18 at 15:31














0












0








0








I am currently experimenting with NightNight, an easy-to-use library to add light and dark themes to an app. I recommend looking into it if you are interested in adding two themes to your app.



That being said, it works like a charm. It is not fully supported yet, e.g. I am missing the ability to set the shadowImage of a UITabBarController to change the "top border" or separator, but I guess I can add this later by diving into the source.



One problem I am facing now, is that I am unable to change the color of attributedText of a UITextView. I definitely need to use the attributedText property because I want to add lineHeightMultiple. I got everything to work, but the color does not change when I switch between themes.



The UITextView is part of a UICollectionViewCell, so it is reused. Whenever I restart the app or start scrolling in the UICollectionView, the text is updated (sometimes - because of the reuse, it sometimes does not update when the cell remains visible on screen). It feels to me like I need to update or reload something else in order to get this library to work as I need.



Currently I set up my TextView like this:



let customTextViewStyle = NSMutableParagraphStyle()
customTextViewStyle.lineHeightMultiple = 1.2

let attributedString = NSMutableAttributedString(string: "This is the text that will be shown inside the TextView")

attributedString.setMixedAttributes([NNForegroundColorAttributeName: MixedColor(normal: lightCustomTextViewFontColor, night: darkCustomTextViewFontColor)], range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: customTextViewStyle, range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: normalFontSize), range: NSRange(location: 0, length: attributedString.length))

customTextView.attributedText = attributedString


Below is a fragment of the source file from NightNight, which is called NSMutableAttributedString, where an observer is added:



public extension NSMutableAttributedString {
fileprivate struct AssociatedKeys {
static var mixedAttrsKey = "mixedAttrs"
}

fileprivate var mixedAttrs: [String: [NSRange: MixedColor]] {
get {
if let dict = objc_getAssociatedObject(self, &AssociatedKeys.mixedAttrsKey) as? [String : [NSRange : MixedColor]] {
return dict
}
self.mixedAttrs = [:]

MixedColorAttributeNames.forEach { (mixed) in
self.mixedAttrs[mixed] = [:]
}

return self.mixedAttrs
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.mixedAttrsKey, newValue as AnyObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

addNightObserver(#selector(_updateTitleAttributes))
}
}
}


Then _updateTitleAttributes looks like this:



@objc func _updateTitleAttributes() {

MixedColorAttributeNamesDictionary.forEach { (mixed, normal) in
if let foregroundColorDictionary = mixedAttrs[mixed] {
foregroundColorDictionary.forEach({ (range, mixedColor) in
self.addAttribute(normal, value: mixedColor.unfold(), range: range)
})
}

}
}


I would highly appreciate a solution to this issue, as I myself am unable to figure it out. Does it have something to do with the source - e.g. does it not update properly? Does it have something to do with my UICollectionViewCell?



Thanks in advance!










share|improve this question














I am currently experimenting with NightNight, an easy-to-use library to add light and dark themes to an app. I recommend looking into it if you are interested in adding two themes to your app.



That being said, it works like a charm. It is not fully supported yet, e.g. I am missing the ability to set the shadowImage of a UITabBarController to change the "top border" or separator, but I guess I can add this later by diving into the source.



One problem I am facing now, is that I am unable to change the color of attributedText of a UITextView. I definitely need to use the attributedText property because I want to add lineHeightMultiple. I got everything to work, but the color does not change when I switch between themes.



The UITextView is part of a UICollectionViewCell, so it is reused. Whenever I restart the app or start scrolling in the UICollectionView, the text is updated (sometimes - because of the reuse, it sometimes does not update when the cell remains visible on screen). It feels to me like I need to update or reload something else in order to get this library to work as I need.



Currently I set up my TextView like this:



let customTextViewStyle = NSMutableParagraphStyle()
customTextViewStyle.lineHeightMultiple = 1.2

let attributedString = NSMutableAttributedString(string: "This is the text that will be shown inside the TextView")

attributedString.setMixedAttributes([NNForegroundColorAttributeName: MixedColor(normal: lightCustomTextViewFontColor, night: darkCustomTextViewFontColor)], range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: customTextViewStyle, range: NSRange(location: 0, length: attributedString.length))
attributedString.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: normalFontSize), range: NSRange(location: 0, length: attributedString.length))

customTextView.attributedText = attributedString


Below is a fragment of the source file from NightNight, which is called NSMutableAttributedString, where an observer is added:



public extension NSMutableAttributedString {
fileprivate struct AssociatedKeys {
static var mixedAttrsKey = "mixedAttrs"
}

fileprivate var mixedAttrs: [String: [NSRange: MixedColor]] {
get {
if let dict = objc_getAssociatedObject(self, &AssociatedKeys.mixedAttrsKey) as? [String : [NSRange : MixedColor]] {
return dict
}
self.mixedAttrs = [:]

MixedColorAttributeNames.forEach { (mixed) in
self.mixedAttrs[mixed] = [:]
}

return self.mixedAttrs
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.mixedAttrsKey, newValue as AnyObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)

addNightObserver(#selector(_updateTitleAttributes))
}
}
}


Then _updateTitleAttributes looks like this:



@objc func _updateTitleAttributes() {

MixedColorAttributeNamesDictionary.forEach { (mixed, normal) in
if let foregroundColorDictionary = mixedAttrs[mixed] {
foregroundColorDictionary.forEach({ (range, mixedColor) in
self.addAttribute(normal, value: mixedColor.unfold(), range: range)
})
}

}
}


I would highly appreciate a solution to this issue, as I myself am unable to figure it out. Does it have something to do with the source - e.g. does it not update properly? Does it have something to do with my UICollectionViewCell?



Thanks in advance!







ios swift uicollectionview themes uicollectionviewcell






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 15 '18 at 14:33









PennyWisePennyWise

136111




136111













  • Make sure you only use attributedText property on your textView and not mixing usage of text and attributedText. If that's not an issue try to reset text in your cell class in prepareForReuse method. myTextView.attributedText = nil

    – inokey
    Nov 15 '18 at 15:23













  • Both don't work. However, I will continue using prepareForReuse on my UITextView as well, so thanks for the heads up on that. I have a working solution right now but it's not as neat as I would want it to be: I add an observer for the notification that changes the theme (NightNightThemeChangeNotification). Next, in the function paired to it, I get all .visibleCells, run them in a for loop and add the attributes again. This works, but it is probably not the best solution. If nothing better comes up, I'll add this solution as an answer so others can learn from it.

    – PennyWise
    Nov 15 '18 at 15:31



















  • Make sure you only use attributedText property on your textView and not mixing usage of text and attributedText. If that's not an issue try to reset text in your cell class in prepareForReuse method. myTextView.attributedText = nil

    – inokey
    Nov 15 '18 at 15:23













  • Both don't work. However, I will continue using prepareForReuse on my UITextView as well, so thanks for the heads up on that. I have a working solution right now but it's not as neat as I would want it to be: I add an observer for the notification that changes the theme (NightNightThemeChangeNotification). Next, in the function paired to it, I get all .visibleCells, run them in a for loop and add the attributes again. This works, but it is probably not the best solution. If nothing better comes up, I'll add this solution as an answer so others can learn from it.

    – PennyWise
    Nov 15 '18 at 15:31

















Make sure you only use attributedText property on your textView and not mixing usage of text and attributedText. If that's not an issue try to reset text in your cell class in prepareForReuse method. myTextView.attributedText = nil

– inokey
Nov 15 '18 at 15:23







Make sure you only use attributedText property on your textView and not mixing usage of text and attributedText. If that's not an issue try to reset text in your cell class in prepareForReuse method. myTextView.attributedText = nil

– inokey
Nov 15 '18 at 15:23















Both don't work. However, I will continue using prepareForReuse on my UITextView as well, so thanks for the heads up on that. I have a working solution right now but it's not as neat as I would want it to be: I add an observer for the notification that changes the theme (NightNightThemeChangeNotification). Next, in the function paired to it, I get all .visibleCells, run them in a for loop and add the attributes again. This works, but it is probably not the best solution. If nothing better comes up, I'll add this solution as an answer so others can learn from it.

– PennyWise
Nov 15 '18 at 15:31





Both don't work. However, I will continue using prepareForReuse on my UITextView as well, so thanks for the heads up on that. I have a working solution right now but it's not as neat as I would want it to be: I add an observer for the notification that changes the theme (NightNightThemeChangeNotification). Next, in the function paired to it, I get all .visibleCells, run them in a for loop and add the attributes again. This works, but it is probably not the best solution. If nothing better comes up, I'll add this solution as an answer so others can learn from it.

– PennyWise
Nov 15 '18 at 15:31












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53321748%2fnightnight-in-swift-to-change-themes-problem-with-attributedtext%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53321748%2fnightnight-in-swift-to-change-themes-problem-with-attributedtext%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Florida Star v. B. J. F.

Danny Elfman

Lugert, Oklahoma