我试图在NSAttributedString
(在iOS7 + / TextKit上)添加虚线下划线样式。当然,我尝试了内置的NSUnderlinePatternDot
:
NSString *string = self.label.text;
NSRange underlineRange = [string rangeOfString:@"consetetur sadipscing elitr"];
NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:string];
[attString addAttributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle | NSUnderlinePatternDot)} range:underlineRange];
self.label.attributedText = attString;
然而,由此产生的风格实际上是虚线而不是虚线:
我是否遗漏了一些明显的东西(NSUnderlinePatternReallyDotted
?;))或者是否有办法自定义线点图案?
答案 0 :(得分:2)
我花了一点时间玩Text Kit来让这个和其他类似的场景一起工作。此问题的实际Text Kit解决方案是子类NSLayoutManager
并覆盖drawUnderline(forGlyphRange:underlineType:baselineOffset:lineFragmentRect:lineFragmentGlyphRange:containerOrigin:)
这是被调用以实际绘制NSTextStorage
中的属性所请求的下划线的方法。以下是传入参数的说明:
glyphRange
第一个字形的索引和要加下划线的后续字形数underlineType
NSUnderlineStyle
属性的NSUnderlineAttributeName
值baselineOffset
边界框底部与所提供范围内字形的基线偏移之间的距离lineFragmentRect
包含 glyphRange
lineFragmentGlyphRange
构成包含 glyphRange
containerOrigin
容器在其所属的文本视图中的偏移量绘制下划线的步骤:
NSTextContainer
glyphRange
的{{1}}
NSLayoutManager.textContainer(forGlyphAt:effectiveRange:)
glyphRange
的边界矩形
NSLayoutManager.boundingRect(forGlyphRange:in:)
CGRect.offsetBy(dx:dy:)
确定)答案 1 :(得分:1)
根据Eiko&Dave的回答i made an example like this
我已经尝试通过使用UILabel而不是UITextView来完成此操作,但是从stackoverflow或其他网站搜索后找不到解决方案。因此,我使用UITextView来做到这一点。
let storage = NSTextStorage()
let layout = UnderlineLayout()
storage.addLayoutManager(layout)
let container = NSTextContainer()
container.widthTracksTextView = true
container.lineFragmentPadding = 0
container.maximumNumberOfLines = 2
container.lineBreakMode = .byTruncatingTail
layout.addTextContainer(container)
let textView = UITextView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width-40, height: 50), textContainer: container)
textView.isUserInteractionEnabled = true
textView.isEditable = false
textView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
textView.text = "1sadasdasdasdasdsadasdfdsf"
textView.backgroundColor = UIColor.white
let rg = NSString(string: textView.text!).range(of: textView.text!)
let attributes = [NSAttributedString.Key.underlineStyle.rawValue: 0x11,
NSAttributedString.Key.underlineColor: UIColor.blue.withAlphaComponent(0.2),
NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17),
NSAttributedString.Key.baselineOffset:10] as! [NSAttributedString.Key : Any]
storage.addAttributes(attributes, range: rg)
view.addSubview(textView)
覆盖LayoutManage方法
class UnderlineLayout: NSLayoutManager {
override func drawUnderline(forGlyphRange glyphRange: NSRange, underlineType underlineVal: NSUnderlineStyle, baselineOffset: CGFloat, lineFragmentRect lineRect: CGRect, lineFragmentGlyphRange lineGlyphRange: NSRange, containerOrigin: CGPoint) {
if let container = textContainer(forGlyphAt: glyphRange.location, effectiveRange: nil) {
let boundingRect = self.boundingRect(forGlyphRange: glyphRange, in: container)
let offsetRect = boundingRect.offsetBy(dx: containerOrigin.x, dy: containerOrigin.y)
let left = offsetRect.minX
let bottom = offsetRect.maxY-15
let width = offsetRect.width
let path = UIBezierPath()
path.lineWidth = 3
path.move(to: CGPoint(x: left, y: bottom))
path.addLine(to: CGPoint(x: left + width, y: bottom))
path.stroke()
}
}
在我的解决方案中,我必须通过使用NSAttributedString属性NSMutableParagraphStyle()。lineSpacing扩展lineSpacing并保留自定义下划线,但似乎没有用,但NSAttributedString.Key.baselineOffset可以使用。希望可以
答案 2 :(得分:0)
我知道这是一个2岁的故事,但也许它会帮助遇到同样问题的人,就像我上周所做的那样。
我的解决方法是子类UITextView
,添加子视图(虚线容器)并使用textView的layoutManager方法enumerateLineFragmentsForGlyphRange
来获取行数及其帧数。
知道了线的框架,我计算了y
我想要的点。所以我创建了一个视图(lineView,其中我绘制了点),将clipsToBounds
设置为YES
,宽度为textView的宽度,然后
在y
的linesContainer中添加为子视图。
之后,我将lineView的width
设置为enumerateLineFragmentsForGlyphRange
返回的值。
对于多行,使用相同的方法:根据enumerateLineFragmentsForGlyphRange
返回的内容更新帧,添加新行或删除。
每次文本更新后,都会在textViewDidChange
中调用此方法。
这是获取行数组及其帧的代码
NSLayoutManager *layoutManager = [self layoutManager];
[layoutManager enumerateLineFragmentsForGlyphRange:NSMakeRange(0, [layoutManager numberOfGlyphs])
usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer *textContainer, NSRange glyphRange, BOOL *stop) {
[linesFramesArray addObject:NSStringFromCGRect(usedRect)];
}
];