问题
I would like to make a UITextField
, which has a static prefix and that the user cannot edit or delete, which at the same time is also attributed with a light gray font color.
The editable part of the text field should always be shown in black color.
An example is given below:
It is essentially for typing in a user name, with a constantly prefixed domain.
I have already tried using the textFieldShouldClear
and textField:shouldChangeCharactersInRange:replacementString:
delegate methods together with NSMutableAttributedString
, but simply haven't been able to crack it:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSMutableAttributedString *text = [textField.attributedText mutableCopy];
[text addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:NSMakeRange(0, 7)];
if (textField.text.length > 7)
{
[text addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(7, textField.attributedText.length - 7)];
}
[text addAttribute:NSFontAttributeName value:[UIFont gothamFontForSize:textField.font.pointSize andWeight:kGothamLight] range:NSMakeRange(0, textField.attributedText.length)];
return range.location > 6;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"kombit\\"];
[text addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:NSMakeRange(0, 7)];
[text addAttribute:NSFontAttributeName value:[UIFont gothamFontForSize:textField.font.pointSize andWeight:kGothamLight] range:NSMakeRange(0, text.length)];
textField.attributedText = text;
[textField setSelectedTextRange:[textField textRangeFromPosition:[textField endOfDocument] toPosition:[textField endOfDocument]]];
return NO;
}
I am certain that someone has already done something similar.
回答1:
The code below creates an attributed string out of your permanent text, colors it gray, and adds it to a textfield. Then in shouldChangeCharactersInRange:
a range comparison is done to determine whether or not the range is within the area that should be occupied by "kombit\", and if it isn't, a black coloring attribute is passed back to the text field.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.textField setDelegate:self];
NSString *fixedString = @"kombit\\";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:fixedString];
[attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor lightGrayColor] range:NSMakeRange(0, fixedString.length)];
[self.textField setAttributedText:attributedString];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSRange substringRange = [textField.text rangeOfString:@"kombit\\"];
if (range.location >= substringRange.location && range.location < substringRange.location + substringRange.length) {
return NO;
}
NSMutableAttributedString *attString = [textField.attributedText mutableCopy];
[attString addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(substringRange.length, textField.text.length - substringRange.length)];
[textField setAttributedText:attString];
return YES;
}
EDIT:
Okay, this isn't something I would have ever expected to be this big of a pain, and frankly I'm embarrassed to post this code because it's really dirty, but it does seem to be doing the job better than before.
What I ended up doing was creating a property to reference a BOOL to hold whether or not the text should be updates (to block the recursion) and adding a target to the text field's UIControlEventEditingChanged
control event to get a callback when editing occurred.
Then, because for some reason none of the normal ways of doing this seem to be working here, I'm moving the "cursor" to the end of the text field by placing a call to becomeFirstResponder directly after a call to resignFirstResponder, and surprisingly this is pretty much working. There is an issue with the text size changing slightly that I have yet to identify, but it should just be a matter of adding additional attributes to match the font size you want
Sorry I couldn't be any more help in solving this, it is quite the curious problem. And I usually hate to suggest this, but after spending so much time trying to do something that should be trivial I'm starting to think there's something buggy going on in NSAttributedString. Anyway, let me know if this code eventually leads you to the answer, I'd be really interested in the solution.
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (nonatomic, assign) BOOL shouldUpdateAttributes;
- (void)viewDidLoad
{
[super viewDidLoad];
[self.textField setDelegate:self];
[self.textField setSpellCheckingType:UITextSpellCheckingTypeNo];
[self setShouldUpdateAttributes:YES];
NSString *fixedString = @"kombit\\ ";
[self.textField setText:fixedString];
[self.textField addTarget:self action:@selector(textFieldDidChangeText:) forControlEvents:UIControlEventEditingChanged];
[self textFieldDidChangeText:self.textField];
}
- (void)textFieldDidChangeText:(UITextField *)sender
{
if (self.shouldUpdateAttributes) {
[self setShouldUpdateAttributes:NO];
NSString *fixedString = @"kombit\\ ";
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:sender.text];
[attributedString setAttributes:@{NSForegroundColorAttributeName: [UIColor lightGrayColor]} range:NSMakeRange(0, fixedString.length)];
[attributedString setAttributes:@{NSForegroundColorAttributeName: [UIColor blackColor]} range:NSMakeRange(fixedString.length, sender.text.length - fixedString.length)];
[sender setAttributedText:attributedString];
[sender resignFirstResponder];
[sender becomeFirstResponder];
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
[self setShouldUpdateAttributes:YES];
NSString *fixedString = @"kombit\\";
NSRange substringRange = [textField.text rangeOfString:fixedString];
if (range.location >= substringRange.location && range.location < substringRange.location + substringRange.length) {
return NO;
}
return YES;
}
回答2:
Put simply UILabel
(styled like you want) to the left of UITextField
and set rect for UITextField's
text.
http://alwawee.com/wordpress/2013/02/18/uitextfield-edge-insets/
来源:https://stackoverflow.com/questions/18333052/make-uitextfield-which-has-a-static-and-attributed-prefix