NightNight in Swift to change themes, problem with attributedText
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
add a comment |
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
Make sure you only useattributedText
property on yourtextView
and not mixing usage oftext
andattributedText
. If that's not an issue try to reset text in your cell class inprepareForReuse
method.myTextView.attributedText = nil
– inokey
Nov 15 '18 at 15:23
Both don't work. However, I will continue using prepareForReuse on myUITextView
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
add a comment |
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
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
ios swift uicollectionview themes uicollectionviewcell
asked Nov 15 '18 at 14:33
PennyWisePennyWise
136111
136111
Make sure you only useattributedText
property on yourtextView
and not mixing usage oftext
andattributedText
. If that's not an issue try to reset text in your cell class inprepareForReuse
method.myTextView.attributedText = nil
– inokey
Nov 15 '18 at 15:23
Both don't work. However, I will continue using prepareForReuse on myUITextView
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
add a comment |
Make sure you only useattributedText
property on yourtextView
and not mixing usage oftext
andattributedText
. If that's not an issue try to reset text in your cell class inprepareForReuse
method.myTextView.attributedText = nil
– inokey
Nov 15 '18 at 15:23
Both don't work. However, I will continue using prepareForReuse on myUITextView
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
Make sure you only use
attributedText
property on yourtextView
and not mixing usage oftext
andattributedText
. If that's not an issue try to reset text in your cell class inprepareForReuse
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