NSLayoutManager: How to fill background colors where there are renderable glyphs only
The default layout manager fills in the background color (specified via NSAttributedString .backgroundColor attribute) where there's no text (except for the last line).
I've managed to achieve the effect I want by sublclassing NSLayoutManager and overriding func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
as follows:
override func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
guard let textContainer = textContainers.first, let textStorage = textStorage else fatalError()
// This just takes the color of the first character assuming the entire container has the same background color.
// To support ranges of different colours, you'll need to draw each glyph separately, querying the attributed string for the
// background color attribute for the range of each character.
guard textStorage.length > 0, let backgroundColor = textStorage.attribute(.backgroundColor, at: 0, effectiveRange: nil) as? UIColor else return
var lineRects = [CGRect]()
// create an array of line rects to be drawn.
enumerateLineFragments(forGlyphRange: glyphsToShow) (_, usedRect, _, range, _) in
var usedRect = usedRect
let locationOfLastGlyphInLine = NSMaxRange(range)-1
// Remove the space at the end of each line (except last).
if self.isThereAWhitespace(at: locationOfLastGlyphInLine)
let lastGlyphInLineWidth = self.boundingRect(forGlyphRange: NSRange(location: locationOfLastGlyphInLine, length: 1), in: textContainer).width
usedRect.size.width -= lastGlyphInLineWidth
lineRects.append(usedRect)
lineRects = adjustRectsToContainerHeight(rects: lineRects, containerHeight: textContainer.size.height)
for (lineNumber, lineRect) in lineRects.enumerated()
guard let context = UIGraphicsGetCurrentContext() else return
context.saveGState()
context.setFillColor(backgroundColor.cgColor)
context.fill(lineRect)
context.restoreGState()
private func isThereAWhitespace(at location: Int) -> Bool
return propertyForGlyph(at: location) == NSLayoutManager.GlyphProperty.elastic
However, this doesn't handle the possibility of having multiple colors specified by range in the attributed string. How might I achieve this? I've looked at fillBackgroundRectArray
with little success.
ios core-text textkit nslayoutmanager
add a comment |
The default layout manager fills in the background color (specified via NSAttributedString .backgroundColor attribute) where there's no text (except for the last line).
I've managed to achieve the effect I want by sublclassing NSLayoutManager and overriding func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
as follows:
override func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
guard let textContainer = textContainers.first, let textStorage = textStorage else fatalError()
// This just takes the color of the first character assuming the entire container has the same background color.
// To support ranges of different colours, you'll need to draw each glyph separately, querying the attributed string for the
// background color attribute for the range of each character.
guard textStorage.length > 0, let backgroundColor = textStorage.attribute(.backgroundColor, at: 0, effectiveRange: nil) as? UIColor else return
var lineRects = [CGRect]()
// create an array of line rects to be drawn.
enumerateLineFragments(forGlyphRange: glyphsToShow) (_, usedRect, _, range, _) in
var usedRect = usedRect
let locationOfLastGlyphInLine = NSMaxRange(range)-1
// Remove the space at the end of each line (except last).
if self.isThereAWhitespace(at: locationOfLastGlyphInLine)
let lastGlyphInLineWidth = self.boundingRect(forGlyphRange: NSRange(location: locationOfLastGlyphInLine, length: 1), in: textContainer).width
usedRect.size.width -= lastGlyphInLineWidth
lineRects.append(usedRect)
lineRects = adjustRectsToContainerHeight(rects: lineRects, containerHeight: textContainer.size.height)
for (lineNumber, lineRect) in lineRects.enumerated()
guard let context = UIGraphicsGetCurrentContext() else return
context.saveGState()
context.setFillColor(backgroundColor.cgColor)
context.fill(lineRect)
context.restoreGState()
private func isThereAWhitespace(at location: Int) -> Bool
return propertyForGlyph(at: location) == NSLayoutManager.GlyphProperty.elastic
However, this doesn't handle the possibility of having multiple colors specified by range in the attributed string. How might I achieve this? I've looked at fillBackgroundRectArray
with little success.
ios core-text textkit nslayoutmanager
Have a look at this: github.com/kimikaza/TagFieldDemoPlayground/blob/master/… This way you can have different attribute keys for each color.
– Koen
Dec 31 '18 at 19:03
Koen, thanks for this, it doesn't quite work over multiple lines, however
– Aodh
Jan 4 at 18:53
Yeah - In the end, I moved away from using attributes, and tracked the selected ranges myself, and colored them as appropriate. But I don't have those gaps like you show (after the word when), so it may also not work in your case.
– Koen
Jan 4 at 19:59
add a comment |
The default layout manager fills in the background color (specified via NSAttributedString .backgroundColor attribute) where there's no text (except for the last line).
I've managed to achieve the effect I want by sublclassing NSLayoutManager and overriding func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
as follows:
override func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
guard let textContainer = textContainers.first, let textStorage = textStorage else fatalError()
// This just takes the color of the first character assuming the entire container has the same background color.
// To support ranges of different colours, you'll need to draw each glyph separately, querying the attributed string for the
// background color attribute for the range of each character.
guard textStorage.length > 0, let backgroundColor = textStorage.attribute(.backgroundColor, at: 0, effectiveRange: nil) as? UIColor else return
var lineRects = [CGRect]()
// create an array of line rects to be drawn.
enumerateLineFragments(forGlyphRange: glyphsToShow) (_, usedRect, _, range, _) in
var usedRect = usedRect
let locationOfLastGlyphInLine = NSMaxRange(range)-1
// Remove the space at the end of each line (except last).
if self.isThereAWhitespace(at: locationOfLastGlyphInLine)
let lastGlyphInLineWidth = self.boundingRect(forGlyphRange: NSRange(location: locationOfLastGlyphInLine, length: 1), in: textContainer).width
usedRect.size.width -= lastGlyphInLineWidth
lineRects.append(usedRect)
lineRects = adjustRectsToContainerHeight(rects: lineRects, containerHeight: textContainer.size.height)
for (lineNumber, lineRect) in lineRects.enumerated()
guard let context = UIGraphicsGetCurrentContext() else return
context.saveGState()
context.setFillColor(backgroundColor.cgColor)
context.fill(lineRect)
context.restoreGState()
private func isThereAWhitespace(at location: Int) -> Bool
return propertyForGlyph(at: location) == NSLayoutManager.GlyphProperty.elastic
However, this doesn't handle the possibility of having multiple colors specified by range in the attributed string. How might I achieve this? I've looked at fillBackgroundRectArray
with little success.
ios core-text textkit nslayoutmanager
The default layout manager fills in the background color (specified via NSAttributedString .backgroundColor attribute) where there's no text (except for the last line).
I've managed to achieve the effect I want by sublclassing NSLayoutManager and overriding func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
as follows:
override func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint)
guard let textContainer = textContainers.first, let textStorage = textStorage else fatalError()
// This just takes the color of the first character assuming the entire container has the same background color.
// To support ranges of different colours, you'll need to draw each glyph separately, querying the attributed string for the
// background color attribute for the range of each character.
guard textStorage.length > 0, let backgroundColor = textStorage.attribute(.backgroundColor, at: 0, effectiveRange: nil) as? UIColor else return
var lineRects = [CGRect]()
// create an array of line rects to be drawn.
enumerateLineFragments(forGlyphRange: glyphsToShow) (_, usedRect, _, range, _) in
var usedRect = usedRect
let locationOfLastGlyphInLine = NSMaxRange(range)-1
// Remove the space at the end of each line (except last).
if self.isThereAWhitespace(at: locationOfLastGlyphInLine)
let lastGlyphInLineWidth = self.boundingRect(forGlyphRange: NSRange(location: locationOfLastGlyphInLine, length: 1), in: textContainer).width
usedRect.size.width -= lastGlyphInLineWidth
lineRects.append(usedRect)
lineRects = adjustRectsToContainerHeight(rects: lineRects, containerHeight: textContainer.size.height)
for (lineNumber, lineRect) in lineRects.enumerated()
guard let context = UIGraphicsGetCurrentContext() else return
context.saveGState()
context.setFillColor(backgroundColor.cgColor)
context.fill(lineRect)
context.restoreGState()
private func isThereAWhitespace(at location: Int) -> Bool
return propertyForGlyph(at: location) == NSLayoutManager.GlyphProperty.elastic
However, this doesn't handle the possibility of having multiple colors specified by range in the attributed string. How might I achieve this? I've looked at fillBackgroundRectArray
with little success.
ios core-text textkit nslayoutmanager
ios core-text textkit nslayoutmanager
edited Nov 12 '18 at 13:47
Aodh
asked Nov 12 '18 at 13:39
AodhAodh
405517
405517
Have a look at this: github.com/kimikaza/TagFieldDemoPlayground/blob/master/… This way you can have different attribute keys for each color.
– Koen
Dec 31 '18 at 19:03
Koen, thanks for this, it doesn't quite work over multiple lines, however
– Aodh
Jan 4 at 18:53
Yeah - In the end, I moved away from using attributes, and tracked the selected ranges myself, and colored them as appropriate. But I don't have those gaps like you show (after the word when), so it may also not work in your case.
– Koen
Jan 4 at 19:59
add a comment |
Have a look at this: github.com/kimikaza/TagFieldDemoPlayground/blob/master/… This way you can have different attribute keys for each color.
– Koen
Dec 31 '18 at 19:03
Koen, thanks for this, it doesn't quite work over multiple lines, however
– Aodh
Jan 4 at 18:53
Yeah - In the end, I moved away from using attributes, and tracked the selected ranges myself, and colored them as appropriate. But I don't have those gaps like you show (after the word when), so it may also not work in your case.
– Koen
Jan 4 at 19:59
Have a look at this: github.com/kimikaza/TagFieldDemoPlayground/blob/master/… This way you can have different attribute keys for each color.
– Koen
Dec 31 '18 at 19:03
Have a look at this: github.com/kimikaza/TagFieldDemoPlayground/blob/master/… This way you can have different attribute keys for each color.
– Koen
Dec 31 '18 at 19:03
Koen, thanks for this, it doesn't quite work over multiple lines, however
– Aodh
Jan 4 at 18:53
Koen, thanks for this, it doesn't quite work over multiple lines, however
– Aodh
Jan 4 at 18:53
Yeah - In the end, I moved away from using attributes, and tracked the selected ranges myself, and colored them as appropriate. But I don't have those gaps like you show (after the word when), so it may also not work in your case.
– Koen
Jan 4 at 19:59
Yeah - In the end, I moved away from using attributes, and tracked the selected ranges myself, and colored them as appropriate. But I don't have those gaps like you show (after the word when), so it may also not work in your case.
– Koen
Jan 4 at 19:59
add a comment |
1 Answer
1
active
oldest
votes
Alternatively, you could bypass using the attributes at all, like this:
So first I defined this struct:
struct HighlightBackground
let range: NSRange
let color: NSColor
Then in my NSTextView subclass:
var highlightBackgrounds = [HighlightBackground]()
override func setSelectedRanges(_ ranges: [NSValue], affinity: NSSelectionAffinity, stillSelecting stillSelectingFlag: Bool)
if stillSelectingFlag == false
return
// remove old ranges first
highlightBackgrounds = highlightBackgrounds.filter $0.color != .green
for value in ranges
let range = value.rangeValue
highlightBackgrounds.append(HighlightBackground(range: range, color: .green))
super.setSelectedRanges(ranges, affinity: affinity, stillSelecting: stillSelectingFlag)
And then call this from your draw(_ rect: NSRect)
method:
func showBackgrounds()
guard
let context = NSGraphicsContext.current?.cgContext,
let lm = self.layoutManager
else return
context.saveGState()
// context.translateBy(x: origin.x, y: origin.y)
for bg in highlightBackgrounds
bg.color.setFill()
let glRange = lm.glyphRange(forCharacterRange: bg.range, actualCharacterRange: nil)
for rect in lm.rectsForGlyphRange(glRange)
let path = NSBezierPath(roundedRect: rect, xRadius: selectedTextCornerRadius, yRadius: selectedTextCornerRadius)
path.fill()
context.restoreGState()
Finally, you'll need this in your NSLayoutManager subclass, although you probably could also put it in the NSTextView subclass:
func rectsForGlyphRange(_ glyphsToShow: NSRange) -> [NSRect]
var rects = [NSRect]()
guard
let tc = textContainer(forGlyphAt: glyphsToShow.location, effectiveRange: nil)
else return rects
enumerateLineFragments(forGlyphRange: glyphsToShow) _, _, _, effectiveRange, _ in
let rect = self.boundingRect(forGlyphRange: NSIntersectionRange(glyphsToShow, effectiveRange), in: tc)
rects.append(rect)
return rects
Hopefully, this works also in your case.
add a comment |
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%2f53263409%2fnslayoutmanager-how-to-fill-background-colors-where-there-are-renderable-glyphs%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Alternatively, you could bypass using the attributes at all, like this:
So first I defined this struct:
struct HighlightBackground
let range: NSRange
let color: NSColor
Then in my NSTextView subclass:
var highlightBackgrounds = [HighlightBackground]()
override func setSelectedRanges(_ ranges: [NSValue], affinity: NSSelectionAffinity, stillSelecting stillSelectingFlag: Bool)
if stillSelectingFlag == false
return
// remove old ranges first
highlightBackgrounds = highlightBackgrounds.filter $0.color != .green
for value in ranges
let range = value.rangeValue
highlightBackgrounds.append(HighlightBackground(range: range, color: .green))
super.setSelectedRanges(ranges, affinity: affinity, stillSelecting: stillSelectingFlag)
And then call this from your draw(_ rect: NSRect)
method:
func showBackgrounds()
guard
let context = NSGraphicsContext.current?.cgContext,
let lm = self.layoutManager
else return
context.saveGState()
// context.translateBy(x: origin.x, y: origin.y)
for bg in highlightBackgrounds
bg.color.setFill()
let glRange = lm.glyphRange(forCharacterRange: bg.range, actualCharacterRange: nil)
for rect in lm.rectsForGlyphRange(glRange)
let path = NSBezierPath(roundedRect: rect, xRadius: selectedTextCornerRadius, yRadius: selectedTextCornerRadius)
path.fill()
context.restoreGState()
Finally, you'll need this in your NSLayoutManager subclass, although you probably could also put it in the NSTextView subclass:
func rectsForGlyphRange(_ glyphsToShow: NSRange) -> [NSRect]
var rects = [NSRect]()
guard
let tc = textContainer(forGlyphAt: glyphsToShow.location, effectiveRange: nil)
else return rects
enumerateLineFragments(forGlyphRange: glyphsToShow) _, _, _, effectiveRange, _ in
let rect = self.boundingRect(forGlyphRange: NSIntersectionRange(glyphsToShow, effectiveRange), in: tc)
rects.append(rect)
return rects
Hopefully, this works also in your case.
add a comment |
Alternatively, you could bypass using the attributes at all, like this:
So first I defined this struct:
struct HighlightBackground
let range: NSRange
let color: NSColor
Then in my NSTextView subclass:
var highlightBackgrounds = [HighlightBackground]()
override func setSelectedRanges(_ ranges: [NSValue], affinity: NSSelectionAffinity, stillSelecting stillSelectingFlag: Bool)
if stillSelectingFlag == false
return
// remove old ranges first
highlightBackgrounds = highlightBackgrounds.filter $0.color != .green
for value in ranges
let range = value.rangeValue
highlightBackgrounds.append(HighlightBackground(range: range, color: .green))
super.setSelectedRanges(ranges, affinity: affinity, stillSelecting: stillSelectingFlag)
And then call this from your draw(_ rect: NSRect)
method:
func showBackgrounds()
guard
let context = NSGraphicsContext.current?.cgContext,
let lm = self.layoutManager
else return
context.saveGState()
// context.translateBy(x: origin.x, y: origin.y)
for bg in highlightBackgrounds
bg.color.setFill()
let glRange = lm.glyphRange(forCharacterRange: bg.range, actualCharacterRange: nil)
for rect in lm.rectsForGlyphRange(glRange)
let path = NSBezierPath(roundedRect: rect, xRadius: selectedTextCornerRadius, yRadius: selectedTextCornerRadius)
path.fill()
context.restoreGState()
Finally, you'll need this in your NSLayoutManager subclass, although you probably could also put it in the NSTextView subclass:
func rectsForGlyphRange(_ glyphsToShow: NSRange) -> [NSRect]
var rects = [NSRect]()
guard
let tc = textContainer(forGlyphAt: glyphsToShow.location, effectiveRange: nil)
else return rects
enumerateLineFragments(forGlyphRange: glyphsToShow) _, _, _, effectiveRange, _ in
let rect = self.boundingRect(forGlyphRange: NSIntersectionRange(glyphsToShow, effectiveRange), in: tc)
rects.append(rect)
return rects
Hopefully, this works also in your case.
add a comment |
Alternatively, you could bypass using the attributes at all, like this:
So first I defined this struct:
struct HighlightBackground
let range: NSRange
let color: NSColor
Then in my NSTextView subclass:
var highlightBackgrounds = [HighlightBackground]()
override func setSelectedRanges(_ ranges: [NSValue], affinity: NSSelectionAffinity, stillSelecting stillSelectingFlag: Bool)
if stillSelectingFlag == false
return
// remove old ranges first
highlightBackgrounds = highlightBackgrounds.filter $0.color != .green
for value in ranges
let range = value.rangeValue
highlightBackgrounds.append(HighlightBackground(range: range, color: .green))
super.setSelectedRanges(ranges, affinity: affinity, stillSelecting: stillSelectingFlag)
And then call this from your draw(_ rect: NSRect)
method:
func showBackgrounds()
guard
let context = NSGraphicsContext.current?.cgContext,
let lm = self.layoutManager
else return
context.saveGState()
// context.translateBy(x: origin.x, y: origin.y)
for bg in highlightBackgrounds
bg.color.setFill()
let glRange = lm.glyphRange(forCharacterRange: bg.range, actualCharacterRange: nil)
for rect in lm.rectsForGlyphRange(glRange)
let path = NSBezierPath(roundedRect: rect, xRadius: selectedTextCornerRadius, yRadius: selectedTextCornerRadius)
path.fill()
context.restoreGState()
Finally, you'll need this in your NSLayoutManager subclass, although you probably could also put it in the NSTextView subclass:
func rectsForGlyphRange(_ glyphsToShow: NSRange) -> [NSRect]
var rects = [NSRect]()
guard
let tc = textContainer(forGlyphAt: glyphsToShow.location, effectiveRange: nil)
else return rects
enumerateLineFragments(forGlyphRange: glyphsToShow) _, _, _, effectiveRange, _ in
let rect = self.boundingRect(forGlyphRange: NSIntersectionRange(glyphsToShow, effectiveRange), in: tc)
rects.append(rect)
return rects
Hopefully, this works also in your case.
Alternatively, you could bypass using the attributes at all, like this:
So first I defined this struct:
struct HighlightBackground
let range: NSRange
let color: NSColor
Then in my NSTextView subclass:
var highlightBackgrounds = [HighlightBackground]()
override func setSelectedRanges(_ ranges: [NSValue], affinity: NSSelectionAffinity, stillSelecting stillSelectingFlag: Bool)
if stillSelectingFlag == false
return
// remove old ranges first
highlightBackgrounds = highlightBackgrounds.filter $0.color != .green
for value in ranges
let range = value.rangeValue
highlightBackgrounds.append(HighlightBackground(range: range, color: .green))
super.setSelectedRanges(ranges, affinity: affinity, stillSelecting: stillSelectingFlag)
And then call this from your draw(_ rect: NSRect)
method:
func showBackgrounds()
guard
let context = NSGraphicsContext.current?.cgContext,
let lm = self.layoutManager
else return
context.saveGState()
// context.translateBy(x: origin.x, y: origin.y)
for bg in highlightBackgrounds
bg.color.setFill()
let glRange = lm.glyphRange(forCharacterRange: bg.range, actualCharacterRange: nil)
for rect in lm.rectsForGlyphRange(glRange)
let path = NSBezierPath(roundedRect: rect, xRadius: selectedTextCornerRadius, yRadius: selectedTextCornerRadius)
path.fill()
context.restoreGState()
Finally, you'll need this in your NSLayoutManager subclass, although you probably could also put it in the NSTextView subclass:
func rectsForGlyphRange(_ glyphsToShow: NSRange) -> [NSRect]
var rects = [NSRect]()
guard
let tc = textContainer(forGlyphAt: glyphsToShow.location, effectiveRange: nil)
else return rects
enumerateLineFragments(forGlyphRange: glyphsToShow) _, _, _, effectiveRange, _ in
let rect = self.boundingRect(forGlyphRange: NSIntersectionRange(glyphsToShow, effectiveRange), in: tc)
rects.append(rect)
return rects
Hopefully, this works also in your case.
edited Jan 5 at 19:24
answered Jan 4 at 20:13
KoenKoen
2,16522455
2,16522455
add a comment |
add a comment |
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%2f53263409%2fnslayoutmanager-how-to-fill-background-colors-where-there-are-renderable-glyphs%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
Have a look at this: github.com/kimikaza/TagFieldDemoPlayground/blob/master/… This way you can have different attribute keys for each color.
– Koen
Dec 31 '18 at 19:03
Koen, thanks for this, it doesn't quite work over multiple lines, however
– Aodh
Jan 4 at 18:53
Yeah - In the end, I moved away from using attributes, and tracked the selected ranges myself, and colored them as appropriate. But I don't have those gaps like you show (after the word when), so it may also not work in your case.
– Koen
Jan 4 at 19:59