I try to change the placeholder text color. This code doesn't work:
let color = NSColor.redColor()
let attrs = [NSForegroundColorAttributeName: color]
let placeHolderStr = NSAttributedString(string: "My placeholder", attributes: attrs)
myTextField.placeholderAttributedString = placeHolderStr
I get the error -[NSTextField setPlaceholderAttributedString:]: unrecognized selector sent to instance. Any ideas, how I can change the color of the placeholder?
UPDATE:
This works:
(myTextField.cell() as NSTextFieldCell).placeholderAttributedString = placeHolderStr
UPDATE 2:
Hmm, it changes the color, but if the text field gets the focus, the placeholder font size get's smaller, very strange.
By explicitly defining the font of the NSAttributedString, the placeholder font resizing referred to in the original question is fixed.
The following is a working example in Swift 3.0.
let color = NSColor.red
let font = NSFont.systemFont(ofSize: 14)
let attrs = [NSForegroundColorAttributeName: color, NSFontAttributeName: font]
let placeholderString = NSAttributedString(string: "My placeholder", attributes: attrs)
(textField.cell as? NSTextFieldCell)?.placeholderAttributedString = placeholderString
The following is a working example in Swift 4.2.
let attrs = [NSAttributedString.Key.foregroundColor: NSColor.lightGray,
NSAttributedString.Key.font: NSFont.systemFont(ofSize: 14)]
let placeholderString = NSAttributedString(string: "My placeholder", attributes: attrs)
(taskTextField.cell as? NSTextFieldCell)?.placeholderAttributedString = placeholderString
You should set the placeholder text in NSTextFieldCell and not NSTextField.
myTextField.cell.placeholderAttributedString = placeHolderStr
You should keep current font, and current value from IB
extension NSTextField {
func setHintTextColor (color: NSColor) {
let currentHint = placeholderString ?? ""
let placeholderAttributes: [NSAttributedString.Key: Any] = [
NSAttributedString.Key.foregroundColor: color,
NSAttributedString.Key.font: font!
]
let placeholderAttributedString = NSMutableAttributedString(string: currentHint, attributes: placeholderAttributes)
let paragraphStyle = NSMutableParagraphStyle()
placeholderAttributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0,length: placeholderAttributedString.length))
self.placeholderAttributedString = placeholderAttributedString
}
}
Related
As NSGridView isn´t available in Interfacebuilder, I tried to create one programatically.
I tried like this:
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let lb1 = NSTextField(labelWithString: "Label1")
let lb2 = NSTextField(labelWithString: "Label2")
let lb3 = NSTextField(labelWithString: "Label3")
let lb4 = NSTextField(labelWithString: "Label4")
let lb5 = NSTextField(labelWithString: "Label 5 long text ...")
let bu = NSButton(title: "Button", target: nil, action: nil)
let empty = NSGridCell.emptyContentView
let gridView = NSGridView(views:
[
[empty, lb1],
[empty, lb2],
[lb3, lb4],
[lb5],
[bu],
])
self.view.addSubview(gridView)
}
But I only get a blanc Window - what´s going wrong?
You need to set translatesAutoresizingMaskIntoConstraints property of gridView to false and add constraints
gridView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// Your constraints
])
Or you can set the frame manually
I have a problem with UITextKit using exclusionPaths: when I place an image inside a TextView, that I’m editing, first everything looks fine:
But when the „Done“-Button is tapped, it will look like this, the ident is wrong:
This is the class to store the informations for the image
class ImageClass {
var image: UIImage!
var imageView: UIImageView
var imageName: String!
var active:Bool
var exclusivePath: UIBezierPath!
init(image: UIImage!, imageName: String!) {
self.image = image
imageView = UIImageView(image: image!)
self.imageName = imageName
self.active = false
self.exclusivePath = nil
}
}
The user chooses the image in a UICollectionView that fires a delegate, when the image was selected. (imageViewObjects is an array, where I can put objects of ImageClass, so I can use mutiple images)
// MARK: - SelectImageDelegate
func selectedImage(name:String) {
let image = UIImage(named: name)
let imageViewObject = ImageClass(image: image, imageName: name)
self.imageViewObjects.append(imageViewObject)
imageViewObject.imageView.frame = CGRectMake(4, 7, width!, height!)
// define the exlusionPaths
let bezierPath = self.exclusionPathForImageView(imageViewObject.imageView)
imageViewObject.exclusivePath = bezierPath
self.updateExclusionPaths()
self.textView.addSubview(imageViewObject.imageView)
}
// set UIBezierPath for the UIImageView
func exclusionPathForImageView(imageView: UIImageView) -> UIBezierPath {
let bezierPath = UIBezierPath(rect:
CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y,
imageView.frame.width, imageView.frame.height))
return bezierPath
}
func updateExclusionPaths() {
textView.textContainer.exclusionPaths = []
for imageViewObject in self.imageViewObjects {
textView.textContainer.exclusionPaths.append(imageViewObject.exclusivePath)
}
}
The context of bezierPath is ok.
When „Done“ is tapped, I stop the editing
let doneBarButton = UIBarButtonItem(title: "Done", style: .Done, target: view, action: Selector("endEditing:"))
In textViewDidEndEditing() now I do nothing.
I also tried it with a UIButton for the image. Similar result.
Any tip for a solution? plz help me!!!!
found a workaround:
func textViewShouldEndEditing(textView: UITextView) -> Bool {
textView.editable = false
}
and I had to add to set textView.editable = true, i.e. in viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: "resetEditable")
tapGesture.numberOfTapsRequired = 1
self.textView.addGestureRecognizer(tapGesture)
func resetEditable() {
textView.editable = true
textView.becomeFirstResponder()
}
I have archived an NSColor to store it in NSUserDefaults:
var data = NSArchiver.archivedDataWithRootObject(NSColor.redColor())
storage.setObject(data, forKey: "color")
storage.synchronize()
But now I need to get the color back from NSData, I have no idea how to do that
You just need to use if let to unwrap your NSData and also you will need a conditional cast as follow:
edit/update:
Swift 3 or later
// archiving
let color: NSColor = .red
let data = NSKeyedArchiver.archivedData(withRootObject: color)
UserDefaults.standard.set(data, forKey: "color")
// unarchiving
if let loadedData = UserDefaults.standard.data(forKey: "color"),
let loadedColor = NSKeyedUnarchiver.unarchiveObject(with: loadedData) as? NSColor {
// you can access loadedColor here
print(loadedColor) // "sRGB IEC61966-2.1 colorspace 1 0 0 1\n"
}
Ran into some errors trying to get Leo's answer working in Swift 5. Came up with this extension which lets UserDefaults store and retrieve colors. Try pasting this into a Playground.
import Cocoa
extension UserDefaults {
func set(_ color: NSColor, forKey: String) {
if let data = try? NSKeyedArchiver.archivedData(withRootObject: color, requiringSecureCoding: false) {
self.set(data, forKey: forKey)
}
}
func color(forKey: String) -> NSColor? {
guard
let storedData = self.data(forKey: forKey),
let unarchivedData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: NSColor.self, from: storedData),
let color = unarchivedData as NSColor?
else {
return nil
}
return color
}
}
// get defaults instance
let defaults = UserDefaults.standard
// create a color
let mycolor = NSColor(red: 0.0, green: 0.5, blue: 0.8, alpha: 0.5)
// save the color
defaults.set(mycolor, forKey: "mycolor")
// read the color back. this returns an optional, may be nil
defaults.color(forKey: "mycolor")
After upgrading to Xcode 6.1 Beta 2 from Xcode 6 Beta 7, the following no longer works:
let font = UIFont(name: "Arial", size: 16)
let colour = UIColor.redColor()
let attributes = [NSFontAttributeName: font, NSForegroundColorAttributeName: colour]
I have tried specifically declaring the dictionary as
let attributes: [NSString : AnyObject] = [NSFontAttributeName: font, NSForegroundColorAttributeName: colour]
but I am receiving the error "Cannot convert ... 'Dictionary' to 'NSString!'". Declaring the key as NSString! rather than NSString complains that NSString! is not hashable. Any clues?
Sorted. As usual, the actual error is a red herring. UIFont(name: , size:) now has an init? initialiser, and so is optional. Correct usage is now :
let font = UIFont(name: "Arial", size: 16)! // Unwrapped
let colour = UIColor.redColor()
let attributes: [NSString : AnyObject] = [NSFontAttributeName: font, NSForegroundColorAttributeName: colour]
or, more correctly:
if let font = UIFont(name: "Arial", size: 16) {
let colour = UIColor.redColor()
let attributes: [NSString : AnyObject] = [NSFontAttributeName: font, NSForegroundColorAttributeName: colour]
// ...
}
I've got several UILabels with multiple lines of text, but the line spacing is larger than I would prefer. Is there any way to change this?
hi this is a late reply but it may help some one line height can be change change the text from plain to attribute
Since iOS 6, Apple added NSAttributedString to UIKit, making it possible to use NSParagraphStyle to change the line spacing.
To actually change it from NIB, please see souvickcse's answer.
Because I friggin hate using attributed text in interface builder (I always run into IB bugs), here is an extension to allow you to set line height multiple directly to a UILabel in interface builder
extension UILabel {
#IBInspectable
var lineHeightMultiple: CGFloat {
set{
//get our existing style or make a new one
let paragraphStyle: NSMutableParagraphStyle
if let existingStyle = attributedText?.attribute(NSAttributedString.Key.paragraphStyle, at: 0, effectiveRange: .none) as? NSParagraphStyle, let mutableCopy = existingStyle.mutableCopy() as? NSMutableParagraphStyle {
paragraphStyle = mutableCopy
} else {
paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 1.0
paragraphStyle.alignment = self.textAlignment
}
paragraphStyle.lineHeightMultiple = newValue
//set our text from existing text
let attrString = NSMutableAttributedString()
if let text = self.text {
attrString.append( NSMutableAttributedString(string: text))
attrString.addAttribute(NSAttributedString.Key.font, value: self.font, range: NSMakeRange(0, attrString.length))
}
else if let attributedText = self.attributedText {
attrString.append( attributedText)
}
//add our attributes and set the new text
attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attrString.length))
self.attributedText = attrString
}
get {
if let paragraphStyle = attributedText?.attribute(NSAttributedString.Key.paragraphStyle, at: 0, effectiveRange: .none) as? NSParagraphStyle {
return paragraphStyle.lineHeightMultiple
}
return 0
}
}