How can I achieve this kind of style in iOS?
I tried using NSAttributedString
and setting NSBackgroundColorAttributeName
as blackColor
but then it doesn't have a clearColor
space between the lines. I also tried to set a lineSpacing
to the NSMutableParagraphStyle
but still, the style looks like one big black block.
I just need a hint in which way to go... thanks!
In other words, not something like this:
"Short answer: you can't. To change the spacing between lines of text, you will have to subclass UILabel and roll your own drawTextInRect, or create multiple labels." This is a really old answer, and other have already addded the new and better way to handle this..
If you have created an UILabel programmatically, replace the UILabel class with the PaddingLabel and add the padding: // Init Label let label = PaddingLabel() label. backgroundColor = . black label.
After some research I found the best solution for what I needed. The solution below is only iOS7+.
First we add this to - (void)drawRect:(CGRect)rect
of your UITextView
subclass.
- (void)drawRect:(CGRect)rect
/// Position each line behind each line.
[self.layoutManager enumerateLineFragmentsForGlyphRange:NSMakeRange(0, self.text.length) usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer *textContainer, NSRange glyphRange, BOOL *stop) {
/// The frame of the rectangle.
UIBezierPath *rectanglePath = [UIBezierPath bezierPathWithRect:CGRectMake(usedRect.origin.x, usedRect.origin.y+3, usedRect.size.width, usedRect.size.height-4)];
/// Set the background color for each line.
[UIColor.blackColor setFill];
/// Build the rectangle.
[rectanglePath fill];
}];
}];
Then we set the line spacing for the UITextView:
- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager lineSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
return 15;
}
The method above is only called if you set the NSLayoutManagerDelegate
. You could do that in your init
, initWithFrame
and initWithCode
methods like this:
self.layoutManager.delegate = self;
Also don't forget to declare that your subclass is a delegate in your .h
file:
@interface YOUR_SUBCLASS_OF_UITEXTVIEW : UITextView <NSLayoutManagerDelegate>
Swift 3 version of @Fabio's solution :
class splitedTextView: UITextView, NSLayoutManagerDelegate {
override func awakeFromNib() {
self.layoutManager.delegate = self
}
override func draw(_ rect: CGRect) {
self.layoutManager.enumerateLineFragments(forGlyphRange: NSMakeRange(0, self.text.characters.count)) { (rect, usedRect, textContainer, glyphRange, Bool) in
let rectanglePath = UIBezierPath(rect: CGRect(x: usedRect.origin.x, y: usedRect.origin.y+3, width: usedRect.size.width, height: usedRect.size.height-4))
UIColor.black.setFill()
rectanglePath.fill()
}
}
func layoutManager(_ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat {
return 15
}
}
You can also create a variable inside your textView
subclass to manage rectangle's color :
var color: UIColor?
And then use it instead of default black in your textView
subclass :
self.color?.setFill()
Also if you do that, don't forget to use setNeedsDisplay()
to redraw your textView
and apply your custom color.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With