UITextField attributedPlaceholder has no effect - ios

I'm trying to make the placeholders in my textfields italic, and since my app is targeting iOS 6.0 or newer, decided to use attributedPlaceholder property instead of rolling something more custom. The code goes as follows:
NSString *plString = #"optional";
NSAttributedString *placeholder = [[NSAttributedString alloc] initWithString:plString
attributes:#{NSFontAttributeName : [UIFont fontWithName:#"HelveticaNeue-LightItalic" size:15]}];
for (UITextField *t in myTextfields){
t.placeholder = plString;
t.attributedPlaceholder = placeholder;
}
Yet the styling of the placeholder still is not italic, but the same as regular text, just dimmer. What am I missing to make the NSAttributedString work?

As noted by warren, the styling currently can't be accomplished the way you're trying. A good workaround would be to set up your textfield's font attributes the way you would like your placeholder to look and then change the font of the textfield whenever the user begins typing. It will look like the placeholder and text are different fonts.
You can do this by creating a delegate of the textfield and utilizing shouldChangeCharactersinRange like this:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// If there is text in the text field
if (textField.text.length + (string.length - range.length) > 0) {
// Set textfield font
textField.font = [UIFont fontWithName:#"Font" size:14];
} else {
// Set textfield placeholder font (or so it appears)
textField.font = [UIFont fontWithName:#"PlaceholderFont" size:14];
}
return YES;
}

This is almost certainly a bug. The documentation for the attributedPlaceholder property claims that the string will be drawn using a gray color regardless of the foreground color attribute, but this is not the case: you can set both the foreground and background colors. Unfortunately, the font attribute appears to get stripped out and reverted to the system font.
As a workaround, I recommend overriding drawPlaceholderInRect: and drawing the placeholder yourself. Additionally, you should file a Radar on this and include a minimal sample project that demonstrates the bug.

I just stumbled upon this issue myself. Apparently, the placeholder will take whatever font the textfield is being assigned with. Just set the textfield's font and you are good.
For everything else, like the colour of the placeholder, I'd still go back to attributedPlaceholder

iOS8/9/Swift 2.0 - working example
func colorPlaceholderText(){
var multipleAttributes = [String : NSObject]()
multipleAttributes[NSForegroundColorAttributeName] = UIColor.appColorCYAN()
//OK - comment in if you want background color
//multipleAttributes[NSBackgroundColorAttributeName] = UIColor.yellowColor()
//OK - Adds underline
//multipleAttributes[NSUnderlineStyleAttributeName] = NSUnderlineStyle.StyleDouble.rawValue
let titleString = "Search port/country/vessel..."
let titleAttributedString = NSAttributedString(string: titleString,
attributes: multipleAttributes)
self.textFieldAddSearch.attributedPlaceholder = titleAttributedString
}

Related

how to set a UITextView's text to be bolded and not clickable

I have the following HTML in a UITextView and would like to render it into a UITextView
is my body for the note
food item - more item stuff;`
Let me add: it's currently showing as blue and underlined and not clickable. I would like to make it bolded and not clickable. I have read the docs regarding linkTextAttributes but, not having used this, it is a bit beyond me and I don't really see any easy way to manipulate this. How would I just render the above link bolded and black (not blue) and maintain the non-clickable nature?
UPDATE (solution using UITextView's linkTextAttributes)
self.testTextView.editable = NO;
self.testTextView.selectable = YES;
self.testTextView.userInteractionEnabled = NO; // workaround to disable link - CAUTION: it also disables scrolling of UITextView content
self.testTextView.dataDetectorTypes = UIDataDetectorTypeLink;
self.testTextView.linkTextAttributes = #{NSFontAttributeName : [UIFont boldSystemFontOfSize:14.0f], // NOT WORKING !?
NSForegroundColorAttributeName : [UIColor redColor]};
...
self.testTextView.text = #"Lorem ipsum http://www.apple.com Lorem ipsum";
As you can see in comments, I wasn't able to set new font to linkTextAttributes, though the colour attribute was working as expected.
If you can get away with colour attribute or some other text attribute to style your URLs and you don't have to worry about disabled UITextView scrolling, then this may be your solution.
PREVIOUS (alternative solution)
If you're using Storyboard/xib then make sure you've deselected Detection -> Links for your UITextView. You can make your link bold by setting its container font to some bold typeface. If you want to support different text/font styles in one string object then you should really look for NSAttributedString or NSMutableAttributedString.
See: https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/classes/NSAttributedString_Class/Reference/Reference.html.
Example:
UIFont *linkFont = [UIFont fontWithName:#"SomeBoldTypeface" size:12];
NSString *link = #"food item - more item stuff";
NSMutableAttributedString *someString = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"is my body for the note %#; let me ad", link]];
[someString addAttribute:NSFontAttributeName value:linkFont range:NSMakeRange(24, link.length)];
UITextView *textView = [[UITextView alloc] init];
textView.attributedText = someString;
...

Size of bullets in UITextField with secureTextEntry changes size as focus switches when using custom font

I have a UITextField that is using the Museo Sans Rounded 300 font. Everything works fine for normal UITextFields, but when you set the secureTextEntry = YES, then there's this disconcerting change to the size of the bullets as the UITextField gets and loses focus (i.e. becomes, and relinquishes, being the first responder).
When the UITextField has focus, the bullets appear to be using the custom font, but once it loses focus they change to being these much bigger (standard size) bullets.
So, the only way I found to combat this was to use the textFieldDidBeginEditing and textFieldDidEndEditing delegate methods, keep track of what was entered in the text field, replace it with a mask of bullets, and disable secureTextEntry. So, when they leave the field, they’re actually just seeing the right number of bullets, rather than their secured text. It’s hacky and messy, but it’ll do for me, perhaps for you, too.
I found an easy solution an it works quite good.
Basically you have to change the font to a custom font when you set secureTextEntry to yes.
- (void)textFieldDidBeginEditing:(UITextField *)textField{
if([textField.text isEqual:#"Password"]){
textField.text = #"";
textField.font = [UIFont fontWithName:#"Helvetica" size:14.5];
textField.secureTextEntry = YES;
}
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
if([textField.text isEqual:#""]){
textField.text = #"Password";
textField.secureTextEntry = NO;
textField.font = [UIFont fontWithName:#"YourFont" size:14.5];
}
}
Another workaround:
While this is an iOS bug (and new in iOS 7, I should add), I do have another way to work around it that one might find acceptable. The functionality is still slightly degraded but not by much.
Basically, the idea is to set the font to the default font family/style whenever the field has something entered in it; but when nothing is entered, set it to your custom font. (The font size can be left alone, as it's the family/style, not the size, that is buggy.) Trap every change of the field's value and set the font accordingly at that time. Then the faint "hint" text when nothing is entered has the font that you want (custom); but when anything is entered (whether you are editing or not) will use default (Helvetica). Since bullets are bullets, this should look fine.
The one downside is that the characters, as you type before being replaced by bullets, will use default font (Helvetica). That's only for a split second per character though. If that is acceptable, then this solution works.
i just test result above, #Javier Peigneux's answer is the most concise
#pragma mark -- UITextFieldDelegate
- (void)textFieldDidBeginEditing:(UCSSafeTF *)safeTF{
safeTF.font = [UIFont fontWithName:#"Helvetica" size:14];
}
- (void)textFieldDidEndEditing:(UCSSafeTF *)safeTF{
safeTF.font = [UIFont fontWithName:#"Helvetica" size:14];
}
now i write like this, and the result is OK. then the reason why you see the bullets size change from small to big is very clear, just because apple iOS 10 below "help" us resize the custom font. hope will help you .
Just create a method that gets called every time the show/hide password toggle is selected. Inside the method, set the font to nil, then set the font to your custom font and font size. You should be setting the custom font and size in the viewWillAppear method as well. Inside this method, you're re-setting it.
This way, you don't need to disable secureTextEntry(which could make your text field vulnerable) and you don't need to use textFieldDidBeginEditing or textFieldDidEndEditing.
Code Example:
//if the password is obscured and the toggle to show it has been turned on, display password. Else, obscure it.
- (IBAction)togglePasswordVisibility:(id)sender {
// Xcode contains a bug where the font changes to default font if these two lines of code are not included.
self.passwordInputTextField.font = nil;
self.passwordInputTextField.font = [UIFont fontWithName:#"myCustomFontName" size:myDesiredFontSize]; //set this in viewWillAppear as well!
if (self.passwordInputTextField.secureTextEntry == YES) {
self.passwordInputTextField.secureTextEntry = NO;
[self.showHideButton setTitle:#"HIDE" forState:UIControlStateNormal];
} else {
self.passwordInputTextField.secureTextEntry = YES;
[self.showHideButton setTitle:#"SHOW" forState:UIControlStateNormal];
}
}

How to set the color of the place holder text for a UITextField while preserving its existing properties?

I have seen some answers that show how to change the placeHolder text color for UITextField by overriding the drawPlaceholderInRect: method such as this one:
iPhone UITextField - Change placeholder text color
but that does not maintain the existing attributes such as alignment, font, etc...what is a better way to solve this?
From iOS 6,
Without any subclassing, one can accomplish this with a couple lines of code like so:
UIColor *color = [UIColor blackColor];
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:placeholderText attributes:#{NSForegroundColorAttributeName: color}];
There are multiple ways to achieve this.
Using Interface Builder or Storyboard
Select the Textfield for which you want to change placeholder color
go to the Identity inspector menu on Top right of Xcode
Add the key value pair this way
Key path = _placeholderLabel.textColor
Click the Type and chose Color attribute .
Then select the color in value.
Set The placeholder color using code :
Process 1:
[textField setValue:[UIColor blueColor] forKeyPath:#"_placeholderLabel.textColor"];
Process 2 :
Override drawPlaceholderInRect:(CGRect)rect method
- (void) drawPlaceholderInRect:(CGRect)rect {
[[UIColor blueColor] setFill];
[[self placeholder] drawInRect:rect withFont:[UIFont systemFontOfSize:14]];
}
There is indeed a much better way to handle this now. This will work for iOS 6 and 7.
(Note this example, I created the code in AwakeFromNib since it won't be changing colors once set. But if you don't use XIB, you will have to change the location where you put this code, such as in drawPlaceholderInRect,)
In this example, we create a subclass of UITextField, override awakeFromNib and then set the placeHolder text color to red:
- (void)awakeFromNib
{
if ([self.attributedPlaceholder length])
{
// Extract attributes
NSDictionary * attributes = (NSMutableDictionary *)[ (NSAttributedString *)self.attributedPlaceholder attributesAtIndex:0 effectiveRange:NULL];
NSMutableDictionary * newAttributes = [[NSMutableDictionary alloc] initWithDictionary:attributes];
[newAttributes setObject:[UIColor redColor] forKey:NSForegroundColorAttributeName];
// Set new text with extracted attributes
self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:[self.attributedPlaceholder string] attributes:newAttributes];
}
}
The nice thing about this approach is that it maintains the current UITextField properties for the placeHolder string and so will allow you to work in IB for most of what you set. In addition, its much more efficient than doing everytime you need to draw. It also allows you to change any other property you want on the placeHolder text while maintaining the rest of the properties.
As mentioned above, if don't use XIBs, then you will need to call this at some other time. If you do put this code in the drawPlaceholderInRect: method, then make sure you call [super drawPlaceholderInRect:] at the end of it.
The safe way to customize UITextField’s placeholder is subclassing the UITextField and overriding placeholderRectForBounds:, Apple won’t bother you on this one. However, if you want to take the risk, you can try this way:
[self.MyTextField setValue:[UIColor darkGrayColor] forKeyPath:#"_placeholderLabel.textColor"];
Source.

How to allow NSAttributedString text be typed into a UITextView?

I'm trying to allow different styles of text to be typed into a UITextView, a bit like a text editor using simple attributes such as bold or italics. I understand by using the textView's attributedText property I can apply attributes to certain ranges of text. This is nice, but I would like to be able to type attributed text into the textView, which would be toggled by a button (such as the typing of bold text).
Here's what I've thought of so far:
I've used the -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text UITextView delegate method to take the text argument, and modify it with attributes by creating an NSAttributedString with the same text. Then create a NSMutableAttributedString, which is a copy of the textView's attributedText. Append the two using appendAttributedString, and then set the textView's attributedText property to the resulting attributedString.
Here's the code:
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if (self.boldPressed) {
UIFont *boldFont = [UIFont boldSystemFontOfSize:self.textView.font.pointSize];
NSDictionary *boldAttr = [NSDictionary dictionaryWithObject:boldFont forKey:NSFontAttributeName];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]initWithString:text attributes:boldAttr];
NSMutableAttributedString *textViewText = [[NSMutableAttributedString alloc]initWithAttributedString:textView.attributedText];
[textViewText appendAttributedString:attributedText];
textView.attributedText = textViewText;
return NO;
}
return YES;
}
Having to reset the textViews attributedText every time a character is typed seems like a bit much for a simple action. Not only that, but it doesn't work properly. Here's what it looks like when the bold attribute is enabled:
There are two problems with this. The most obvious being how every new character is put onto a new line. But what's also strange is that the insertion point is always at the very first index of the text in the textview (only when bold is enabled, yet the bold character is inserted on a new line). So if you're typing with bold enabled, and then turn bold off, typing resumes in front of all existing text.
I'm not sure why these error are happening. I also just don't think that my solution is very efficient, but I can't think of any other way of implementing it.
This is what setTypingAttributes: is for. Set this to your attribute dictionary whenever the user presses one of your attribute buttons and new characters will pick up the requested attributes.
Here are sample codes to do so if you are looking for examples
Swift 3.0
var attributes = textField.typingAttributes
attributes["\(NSForegroundColorAttributeName)"] = UIColor.red
textField.typingAttributes = attributes
Objective-C
NSMutableDictionary* attributes = [textField.typingAttributes mutableCopy];
attributes[NSForegroundColorAttributeName] = [UIColor redColor];
textField.typingAttributes = attributes;

text editing in text view xcode

I have a text view in which text is displayed like this:
how are you?
Fine
Now if i set font for text view, then the same font is displayed for the two lines(ques and answer), however i want question to be displayed in one font and answer in some other font. How can i do this?
I set font like this:
textView = [[UITextView alloc]initWithFrame:CGRectMake(10, 80, 300, 440)];
textView.layer.borderColor = [UIColor blackColor].CGColor;
[textView setFont:[UIFont fontWithName:#"TimesNewRomanPS-ItalicMT" size:14]];
textView.layer.borderWidth = 1.0;
textView.autoresizesSubviews = YES;
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:textView];
Thanks in advance!!
From the UITextView class reference:
In iOS 6 and later, this class supports multiple text styles through
use of the attributedText property. (Styled text is not supported in
earlier versions of iOS.) Setting a value for this property causes the
text view to use the style information provided in the attributed
string. You can still use the font, textColor, and textAlignment
properties to set style attributes, but those properties apply to all
of the text in the text view.
This class does not support multiple styles for text. The font, color,
and text alignment attributes you specify always apply to the entire
contents of the text view. To display more complex styling in your
application, you need to use a UIWebView object and render your
content using HTML.
So you cannot have two on the same page for iOS 5 or less because it is not supported. Just use a webview and an HTML file. for iOS6 maybe you can try using attributedText property of UITextView. This is available under iOS 6. Never tried it though.
Or have 2 different UITextView's (its ugly but thats what it is).
I'm guessing you wanted to create a chatroom like app?
if so, I recommend make it a UITableView. And then make different Cells to match different styles.
You can use attributed strings to achieve this, for example:
NSMutableAttributedString *para1 = [[NSMutableAttributedString alloc] initWithString:#"How are you?"];
NSMutableAttributedString *para2 = [[NSMutableAttributedString alloc] initWithString:#"\nFine"];
[para2 setAttributes:#{ NSForegroundColorAttributeName : [UIColor blueColor]} range:NSMakeRange(0, para2.length)];
[para1 insertAttributedString:para2 atIndex:para1.length];
self.textLabel.attributedText = para1;
Or with a single attributed string:
NSMutableAttributedString *para1 = [[NSMutableAttributedString alloc] initWithString:#"How are you?\nFine"];
// Get the range of the last line in the string
__block NSRange range;
[para1.mutableString enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
range = [para1.mutableString rangeOfString:line];
}];
[para1 setAttributes:#{ NSForegroundColorAttributeName : [UIColor blueColor] } range:range];
self.textLabel.attributedText = para1;
Both examples result in:

Resources