Swift 使用背景色向UILabel添加填充
我有一个多行UILabel,它包含一个NSAttributedString,它有一个应用的背景色来提供上述效果 这很好,但我需要在标签内填充,以便在左侧留出一点空间。还有其他关于SO的帖子解决了这个问题,比如通过将UILabel子类化来添加UIEdgeInSet。然而,对我来说,这只是在标签的外面添加了填充物 关于如何将填充添加到此标签有何建议 编辑:如果这让人困惑,我道歉,但最终目标是这样的Swift 使用背景色向UILabel添加填充,swift,uilabel,padding,nsattributedstring,textkit,Swift,Uilabel,Padding,Nsattributedstring,Textkit,我有一个多行UILabel,它包含一个NSAttributedString,它有一个应用的背景色来提供上述效果 这很好,但我需要在标签内填充,以便在左侧留出一点空间。还有其他关于SO的帖子解决了这个问题,比如通过将UILabel子类化来添加UIEdgeInSet。然而,对我来说,这只是在标签的外面添加了填充物 关于如何将填充添加到此标签有何建议 编辑:如果这让人困惑,我道歉,但最终目标是这样的 我用了一种不同的方法。首先,我从UILabel获取所有行,并在每行的起始位置添加额外的空格。要从UIL
我用了一种不同的方法。首先,我从
UILabel
获取所有行,并在每行的起始位置添加额外的空格。要从UILabel
获取所有行,我只需修改此链接()中的代码
最终扩展UILabel
代码:
extension UILabel {
var addWhiteSpace: String {
guard let text = text, let font = font else { return "" }
let ctFont = CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil)
let attStr = NSMutableAttributedString(string: text)
attStr.addAttribute(kCTFontAttributeName as NSAttributedString.Key, value: ctFont, range: NSRange(location: 0, length: attStr.length))
let frameSetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString)
let path = CGMutablePath()
path.addRect(CGRect(x: 0, y: 0, width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude), transform: .identity)
let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil)
guard let lines = CTFrameGetLines(frame) as? [Any] else { return "" }
return lines.map { line in
let lineRef = line as! CTLine
let lineRange: CFRange = CTLineGetStringRange(lineRef)
let range = NSRange(location: lineRange.location, length: lineRange.length)
return " " + (text as NSString).substring(with: range)
}.joined(separator: "\n")
}
}
使用:
编辑:
上面的代码在某种程度上是有效的,但还不够。所以我创建了一个类,添加了填充和一个形状矩形层
class AttributedPaddingLabel: UILabel {
private let leftShapeLayer = CAShapeLayer()
var leftPadding: CGFloat = 5
var attributedTextColor: UIColor = .red
override func awakeFromNib() {
super.awakeFromNib()
self.addLeftSpaceLayer()
self.addAttributed()
}
override func drawText(in rect: CGRect) {
let insets = UIEdgeInsets(top: 0, left: leftPadding, bottom: 0, right: 0)
super.drawText(in: rect.inset(by: insets))
}
override var intrinsicContentSize: CGSize {
let size = super.intrinsicContentSize
return CGSize(width: size.width + leftPadding, height: size.height)
}
override var bounds: CGRect {
didSet {
preferredMaxLayoutWidth = bounds.width - leftPadding
}
}
override func draw(_ rect: CGRect) {
super.draw(rect)
leftShapeLayer.path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: leftPadding, height: rect.height)).cgPath
}
private func addLeftSpaceLayer() {
leftShapeLayer.fillColor = attributedTextColor.cgColor
self.layer.addSublayer(leftShapeLayer)
}
private func addAttributed() {
let lblText = self.text ?? ""
let attributedString = NSMutableAttributedString(string: lblText)
attributedString.addAttribute(NSAttributedString.Key.backgroundColor, value: attributedTextColor, range: NSRange(location: 0, length: lblText.count))
self.attributedText = attributedString
}
}
如何使用:
class ViewController: UIViewController {
@IBOutlet weak var lblText: AttributedPaddingLabel!
override func viewDidLoad() {
super.viewDidLoad()
lblText.attributedTextColor = .green
lblText.leftPadding = 10
}
}
根据此处提供的答案: 只是为了演示(几个硬编码值,理想情况下是动态/计算的): 输出(teal背景显示帧): SwiftUI 这只是SwiftUI中的一个建议。我希望它会有用 步骤1:创建内容
let字符串=
"""
乱数假文
多洛·西特·艾米特,
圣骑士
告别精英。
"""
步骤2:应用属性
let attributed:NSMutableAttributedString=.init(string:string)
attributed.addAttribute(.backgroundColor,值:UIColor.orange,范围:NSRange(位置:0,长度:attributed.length))
attributed.addAttribute(.font,值:UIFont(名称:“Times New Roman”,大小:22)!,范围:NSRange(位置:0,长度:attributed.length))
步骤3:使用UILabel()在SwiftUI中创建AttributedLabel
struct AttributeLabel:UIViewRepresentable{
let attributedString:NSAttributedString
func makeUIView(上下文:context)->UILabel{
let label=UILabel()
label.lineBreakMode=.byClipping
label.numberOfLines=0
退货标签
}
func updateUIView(uiView:UILabel,context:context){
uiView.attributedText=attributedString
}
}
最后一步:使用它并添加.padding()
struct ContentView:View{
var body:一些观点{
AttributedLabel(attributedString:attributed)
.padding()
}
}
结果是:
您尝试过什么吗?“在标签内,在左边留出一点空间”可能使用
NSParagraphStyle
?还是我误解了目标效果?@Larme谢谢。是的,我试过了。使用NSParagraphStyle,我可以调整headIntent,以在第一行之外的其他行上创建填充效果,但随后我还需要使用firstLineHeadIndent来覆盖第一行。令人烦恼的是,这会在第一行增加边距,而不是填充。谢谢。这不太管用,但还是要感谢大家的分享。返回一个空格会得到想要的结果。你在…返回两个空格是有原因的吗。。。返回“”+(文本为NSString)。子字符串(带:range)我试图根据开发人员的要求添加空间。这是一个很好的解决方案,我会记住这一点。唯一的缺点是,有时空间应用不正确。@Stamp我又添加了一个解决方案,请检查更新的答案。
class ViewController: UIViewController {
@IBOutlet weak var lblText: AttributedPaddingLabel!
override func viewDidLoad() {
super.viewDidLoad()
lblText.attributedTextColor = .green
lblText.leftPadding = 10
}
}
class ViewController: UIViewController, NSLayoutManagerDelegate {
var myTextView: UITextView!
let textStorage = MyTextStorage()
let layoutManager = MyLayoutManager()
override func viewDidLoad() {
super.viewDidLoad()
myTextView = UITextView()
myTextView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(myTextView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
myTextView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
myTextView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
myTextView.widthAnchor.constraint(equalToConstant: 248.0),
myTextView.heightAnchor.constraint(equalToConstant: 300.0),
])
self.layoutManager.delegate = self
self.textStorage.addLayoutManager(self.layoutManager)
self.layoutManager.addTextContainer(myTextView.textContainer)
let quote = "This is just some sample text to demonstrate the word wrapping with padding at the beginning (leading) and ending (trailing) of the lines of text."
self.textStorage.replaceCharacters(in: NSRange(location: 0, length: 0), with: quote)
guard let font = UIFont(name: "TimesNewRomanPSMT", size: 24.0) else {
fatalError("Could not instantiate font!")
}
let attributes: [NSAttributedString.Key : Any] = [NSAttributedString.Key.font: font]
self.textStorage.setAttributes(attributes, range: NSRange(location: 0, length: quote.count))
myTextView.isUserInteractionEnabled = false
// so we can see the frame of the textView
myTextView.backgroundColor = .systemTeal
}
func layoutManager(_ layoutManager: NSLayoutManager,
lineSpacingAfterGlyphAt glyphIndex: Int,
withProposedLineFragmentRect rect: CGRect) -> CGFloat { return 14.0 }
func layoutManager(_ layoutManager: NSLayoutManager,
paragraphSpacingAfterGlyphAt glyphIndex: Int,
withProposedLineFragmentRect rect: CGRect) -> CGFloat { return 14.0 }
}
class MyTextStorage: NSTextStorage {
var backingStorage: NSMutableAttributedString
override init() {
backingStorage = NSMutableAttributedString()
super.init()
}
required init?(coder: NSCoder) {
backingStorage = NSMutableAttributedString()
super.init(coder: coder)
}
// Overriden GETTERS
override var string: String {
get { return self.backingStorage.string }
}
override func attributes(at location: Int,
effectiveRange range: NSRangePointer?) -> [NSAttributedString.Key : Any] {
return backingStorage.attributes(at: location, effectiveRange: range)
}
// Overriden SETTERS
override func replaceCharacters(in range: NSRange, with str: String) {
backingStorage.replaceCharacters(in: range, with: str)
self.edited(.editedCharacters,
range: range,
changeInLength: str.count - range.length)
}
override func setAttributes(_ attrs: [NSAttributedString.Key : Any]?, range: NSRange) {
backingStorage.setAttributes(attrs, range: range)
self.edited(.editedAttributes,
range: range,
changeInLength: 0)
}
}
import CoreGraphics //Important to draw the rectangles
class MyLayoutManager: NSLayoutManager {
override init() { super.init() }
required init?(coder: NSCoder) { super.init(coder: coder) }
override func drawBackground(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
super.drawBackground(forGlyphRange: glyphsToShow, at: origin)
self.enumerateLineFragments(forGlyphRange: glyphsToShow) { (rect, usedRect, textContainer, glyphRange, stop) in
var lineRect = usedRect
lineRect.size.height = 41.0
let currentContext = UIGraphicsGetCurrentContext()
currentContext?.saveGState()
// outline rectangles
//currentContext?.setStrokeColor(UIColor.red.cgColor)
//currentContext?.setLineWidth(1.0)
//currentContext?.stroke(lineRect)
// filled rectangles
currentContext?.setFillColor(UIColor.orange.cgColor)
currentContext?.fill(lineRect)
currentContext?.restoreGState()
}
}
}