SKLabelNode + NSMutableAttributedString = no shadow - swift

let paragraph = NSMutableParagraphStyle()
paragraph.alignment = NSTextAlignment.right
paragraph.tailIndent = -3
let shadow = NSShadow()
shadow.shadowBlurRadius = 5
shadow.shadowColor = UIColor.gray
shadow.shadowOffset = CGSize(width: 2, height: -2)
let text = NSMutableAttributedString(string: "MY LABEL", attributes:
[NSShadowAttributeName : shadow,
NSStrokeColorAttributeName : UIColor.black,
NSStrokeWidthAttributeName : -3,
NSForegroundColorAttributeName: UIColor.white,
NSFontAttributeName : UIFont(name: "MyFont", size: 24) as Any,
NSParagraphStyleAttributeName : paragraph])
let node = SKLabelNode()
addChild(node)
node.attributedText = attributedString
It works but there is NO shadow. I can use the same NSMutableAttributedString on well-known ASAttributedLabel and it works nice and there IS a shadow, but i want to use SKLabelNode to achieve better performance on IOS11. ASAttributedLabel may lag on dynamic scenes :(

Related

CIAttributedTextImageGenerator filter - text doesn't fit (NSAttributedString)

I use a Core Image filter CIAttributedTextImageGenerator to generate text as a CIImage. However, sometimes the text just doesn't fit into the resulted CIImage as you can see at the picture:
I tried to play with different key-values of NSAttributedString to make some padding around text but with no success:
func generateImageFromText(_ text: String, style: TextStyle) -> CIImage? {
let font = UIFont.init(name: style.fontName, size: style.fontSize)!
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = style.textAlignment
paragraphStyle.headIndent = 5.0
paragraphStyle.tailIndent = -5.0
paragraphStyle.firstLineHeadIndent = 0
let shadow = NSShadow()
if let shadowStyle = style.shadowStyle {
shadow.shadowColor = shadowStyle.color
shadow.shadowOffset = shadowStyle.offset
shadow.shadowBlurRadius = shadowStyle.blurRadius
}
var strokeColor = UIColor.clear
var strokeWidth: CGFloat = 0.0
if let strokeStyle = style.strokeStyle {
strokeColor = strokeStyle.color
strokeWidth = strokeStyle.width
}
let attributes: [NSAttributedString.Key: Any] = [
.baselineOffset: 50,
.font: font,
.foregroundColor: style.color,
.paragraphStyle: paragraphStyle,
.shadow: shadow,
.strokeColor: strokeColor,
.strokeWidth: strokeWidth
]
let attributedQuote = NSAttributedString(string: text, attributes: attributes)
let textGenerationFilter = CIFilter(name: "CIAttributedTextImageGenerator")!
textGenerationFilter.setValue(attributedQuote, forKey: "inputText")
textGenerationFilter.setValue(NSNumber(value: Double(1.0)), forKey: "inputScaleFactor")
guard let textImage = textGenerationFilter.outputImage else {
return nil
}
return textImage
}
Maybe there are some values of NSAttributedString that I miss which can help to fit in the text?

How can I center an image on a textView who is attached to a NSTextAttachment type?

I have a textView (programmatically) and I inserted an image appended to a NSTextAttachment and want it to be aligned to the center of the text view... but I haven't found any solutions yet...I was wondering if that task is possible to be done via code only...
let image = ResizeImage(image: UIImage(named: "logo")!, targetSize: size)
let image1Attachment = NSTextAttachment()
image1Attachment.image = image
let image1Attachments = NSAttributedString(attachment: image1Attachment)
My best approach to the solution on trying to achieve this was this code :
let image = ResizeImage(image: UIImage(named: "telepaint1")!,
targetSize: size)
//let textAttachment = NSTextAttachment()
let textAttachment = NSTextAttachment()
//let imageStyle = NSMutableParagraphStyle()
let imageStyle = NSMutableParagraphStyle()
//imageStyle.alignment = .center
imageStyle.alignment = .center
//textAttachment.image = image
textAttachment.image = image
let imageText = NSAttributedString(attachment:
textAttachment).mutableCopy() as! NSMutableAttributedString
//attempt to center image...
let attributedStringToAppend: NSMutableAttributedString =
NSMutableAttributedString(attributedString:
NSAttributedString(string: "\n\n"))
//attributedStringToAppend.addAttributes(attr, range: range)
let combination2: NSMutableAttributedString =
NSMutableAttributedString(attributedString:
NSAttributedString(string: "\n\n"))
combination2.append(lineBreak)
// combination2.addAttribute(attr, range: NSRange(location: 0,
length: length))
combination2.append(imageText)
//this text will display the "Walktrough" text on image
combination2.append(attributedText)
tv.attributedText = combination2
Answer(worked for me!):
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
attributedText.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: length))
let size = CGSize(width: 100, height: 100)
//Here is an attempt to resize image and center it...
let image = ResizeImage(image: UIImage(named: "logo")!.withRenderingMode(.alwaysTemplate), targetSize: size)
let textAttachment = NSTextAttachment()
let imageStyle = NSMutableParagraphStyle()
imageStyle.alignment = .center
textAttachment.image = image
let imageText = NSAttributedString(attachment: textAttachment).mutableCopy() as! NSMutableAttributedString
let length2 = imageText.length
imageText.addAttribute(NSAttributedString.Key.paragraphStyle, value: imageStyle, range: NSRange(location: 0, length: length2))

Swift: Can I adjust attributed text with dynamic font size?

I'm working with the collectionView
whose each cell has the content like this:
everything works pretty well until I test it on an iphone 5s:
"Ho Chi Minh City" was out of bounds.
Here is my code:
func configureNameLabel() {
nameLabel.numberOfLines = 2
let attributedText = NSMutableAttributedString(string: post?.name ?? "", attributes: [.font: UIFont.boldSystemFont(ofSize: 15)])
attributedText.append(NSAttributedString(string: "\nSaturday, December 1, 2018 ⦁ Ho Chi Minh City ⦁ ", attributes:
[.foregroundColor: UIColor.lightGray, .font: UIFont.preferredFont(forTextStyle: .caption1)]))
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 5
attributedText.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedText.string.count))
let attachment = NSTextAttachment()
attachment.image = UIImage(named: "user-male")
attachment.bounds = CGRect(x: 0, y: -2, width: 12, height: 12)
attributedText.append(NSAttributedString(attachment: attachment))
nameLabel.attributedText = attributedText
}
I think this problem is due to the font size, can anybody fix this ?
Thanks guys, I solved it. "label.numberOfLines = 0" worked. the problem is at my constraints.

CATextLayer is ignoring NSMutableParagraphStyle

I want to use NSMutableAttributedString to draw the text on the CATextLayer with the text. I try set attributes to the like font and fontcolor of the NSMutableAttributedString through the [attrString setAttributes:attributes range:range]; but all attributes in the NSMutableParagraphStyle are ignored.
let str = "I want to use NSMutableAttributedString to draw the text on the CATextLayer with the text. I try set attributes to the like font and fontcolor of the NSMutableAttributedString through the [attrString setAttributes:attributes range:range]; but all attributes in the NSMutableParagraphStyle are ignored."
let att = NSMutableAttributedString(string: str)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 12
att.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, str.characters.count))
let contentLayer = initTextLayer("", andFontSize: 11)
contentLayer.string = att
contentLayer.frame = CGRect(x: 30 * AUTOSIZESCALEX, y: CGRectGetMaxY(titleLayer.frame) + 15 * AUTOSIZESCALEY, width: SCREEN_WIDTH - 60 * AUTOSIZESCALEX, height: 200 * AUTOSIZESCALEY)
self.contentView.layer.addSublayer(contentLayer)
func initTextLayer(title: String, andFontSize size: CGFloat) -> CATextLayer{
let textLayer = CATextLayer()
textLayer.foregroundColor = UIColor(hexString: "333333").CGColor
textLayer.string = title
textLayer.alignmentMode = kCAAlignmentLeft
textLayer.contentsScale = UIScreen.mainScreen().scale
textLayer.shouldRasterize = false
textLayer.wrapped = true
textLayer.fontSize = size * AUTOSIZESCALEY
return textLayer
}
is there something I'm doing wrong?
I had a similar problem and used this:
// Set text alignment. Apparently CATextLayer doesn't use value in NSAttributedString.
if let style = text.attribute(NSParagraphStyleAttributeName, atIndex: 0, effectiveRange: nil) as? NSParagraphStyle {
switch style.alignment {
case .Center:
textLayer.alignmentMode = kCAAlignmentCenter
case .Left:
textLayer.alignmentMode = kCAAlignmentLeft
case .Right:
textLayer.alignmentMode = kCAAlignmentRight
default:
break
}
}

How to make text appear in centre of the image?

I want to add a text on an image, and I'm able to do it as shown in below code.
func textToImage(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
// Setup the font specific variables
var textColor: UIColor = UIColor.redColor()
var textFont: UIFont = UIFont(name: "AmericanTypewriter", size: 75)!
let textStyle = NSTextEffectLetterpressStyle
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
NSTextEffectAttributeName : textStyle
]
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
var rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
drawText.drawInRect(rect, withAttributes: textFontAttributes)
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
I called this function like shown below
let newImage : UIImage = textToImage(textToAdd!, inImage: imageToSave, atPoint:CGPoint(x: 20, y: 20)) //For now text is displaying at the top in left end for point(x:20 ,y:20)
But the problem is, text is taken by user. They can give either single word or big sentence. So if they give only single word, it should appear in top and middle of the image or else in top from left to right. it is more like, I want to set the text alignment to centre. To achieve it, Accordingly I should change the CGPoint given above. But I'm not getting how to change it so that it should look good in all scenarios. Please help me how to achieve this.
You can center the text near the top of the image like this:
func textToImage(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
// Setup the font specific variables
var textColor: UIColor = UIColor.redColor()
var textFont: UIFont = UIFont(name: "AmericanTypewriter", size: 75)!
let textStyle = NSTextEffectLetterpressStyle
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
NSTextEffectAttributeName : textStyle
]
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
let textSize = drawText.sizeWithAttributes(textFontAttributes)
let textRect = CGRectMake(inImage.size.width / 2 - textSize.width / 2, 0,
inImage.size.width / 2 + textSize.width / 2, inImage.size.height - textSize.height)
drawText.drawInRect(textRect, withAttributes: textFontAttributes)
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
Added to #osteven answer. Below code works as I expected. Hope it helps others.
func textToImage(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
// Setup the font specific variables
var textColor: UIColor = UIColor.redColor()
var textFont: UIFont = UIFont(name: "AmericanTypewriter", size: 75)!
let textStyle = NSTextEffectLetterpressStyle
//Setup the image context using the passed image.
UIGraphicsBeginImageContext(inImage.size)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
NSTextEffectAttributeName : textStyle
]
inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
let textSize = drawText.sizeWithAttributes(textFontAttributes)
if textSize.width < inImage.size.width {
println("lesser")
let textRect = CGRectMake(inImage.size.width / 2 - textSize.width / 2, 0,
inImage.size.width / 2 + textSize.width / 2, inImage.size.height - textSize.height)
drawText.drawInRect(textRect, withAttributes: textFontAttributes)
}
else {
println("greater")
let textRect = CGRectMake(0 , 0,
inImage.size.width, inImage.size.height)
drawText.drawInRect(textRect, withAttributes: textFontAttributes)
}
var newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
It may be a simple as what you suggested with "I want to set the text alignment to centre".
Add a line here:
// Setup the font specific variables
var textColor: UIColor = UIColor.redColor()
var textFont: UIFont = UIFont(name: "AmericanTypewriter", size: 75)!
let textStyle = NSTextEffectLetterpressStyle
let textAlignment = NSTextAlignment.Center
and add to your array:
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
NSTextEffectAttributeName : textStyle
NSTextAlignment: textAlignment
]
This should make the text centered in the image.
If you change the point of text origin back to (0, 0) and set your Text Rectangle as big as the image, it should be able to account for the width of Rect and thus center all of the text accordingly.