This question already has an answer here:
RxSwift/RxCocoa: prevent UITextField from having more than ... characters
(1 answer)
Closed 4 years ago.
I want to set a limit for characters in a textFiled using RxSwift,
may be i can benefit from Scan operator but i don't know how to use it in this case ,
I want my resulting code to behave as same as implementing it in shouldChangeCharacterInRage method:
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String)
-> Bool {
if textField == baseTextFiled{
let enteredString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
if enteredString.count > limit{ // limit defined previously
return false
}
}
return true
}
Any help?
ReactiveX pushes data, so isn't really compatible with that particular delegate method. That said, you can still do it because .rx.text is a control property...
baseTextField.rx.text.orEmpty // pushes text
.map { String($0.prefix(limit)) } // pushes first X characters in text
.distinctUntilChanged() // only pushes if text is different than previously
.bind(to: baseTextField.rx.text) // pushes text into text field
.disposed(by: bag)
Related
Our App has a few UITextField where users enter alphanumeric input codes such as "AA149873A".
We'd like voice over to read these as "A A 1 4 9 8 7 2 A", but it instead reads the digits as a number: "One hundred and forty nine thousand, eight hundred and seventy three".
Is there some way to configure UITextField so that it knows its content shouldn't be thought of as numbers, but individual digits?
Thanks.
We'd like voice over to read these as "A A 1 4 9 8 7 2 A", but it instead reads the digits as a number: "One hundred and forty nine thousand, eight hundred and seventy three".
The fastest wy to reach your goal is to add spaces between each character in the accessibilityValue of the UITextField as follows: 🤓
class AccessibilityTextField: UITextField {
var _str: String?
override var text: String? {
get { return _str}
set {
_str = newValue!
accessibilityValue = _str!.map{String($0)}.joined(separator: " ")
}
}
convenience init() { self.init() }
required init?(coder: NSCoder) { super.init(coder: coder) }
}
I didn't implement all the text field delegate stuff to test it ⟹ I created a blank project only with an UITextField adding a "BB0024FG" plain text and changed the text in the viewDidAppear of my view controller:
myTextField.text = "AA14987A"
In the end, VoiceOver spells out each character after another without reading out the initial plain text. 👍
Following this rationale, you have a way that let VoiceOver know that the UITextField content must be thought as individual digits. 😉
As of iOS 13 it is possible to add a string attribute to direct voice-over vocalisation to spell strings out as individual letters and digits.
I've not found a way to direct UITextField to add this attribute to its content. However, a UITextField subclass can override it's accessibilityValue to achieve this.
The subclass given here adds a property to enable or disable this behaviour.
final class AccessibilityTextField: UITextField {
var isAlphanumeric: Bool = false
override public var accessibilityAttributedValue: NSAttributedString? {
get {
guard let text = text, !text.isEmpty else {
return nil
}
return NSAttributedString(string: text, attributes: valueAttributes)
}
set {
// Ignore these values.
_ = newValue
}
}
private var valueAttributes: [NSAttributedString.Key: Any] {
guard #available(iOS 13.0, *), isAlphanumeric else {
return [:]
}
return [.accessibilitySpeechSpellOut: true]
}
}
An alternative approach is given in another answer here that doesn't use the iOS 13 feature . accessibilitySpeechSpellOut. However, I've seen it suggested that this is not ideal for brail output systems as they also use accessibilityLabel. Perhaps this is a good fallback on pre iOS 13 systems.
What is the purpose of writing comments in Swift as:
// MARK: This is a comment
When you can also do:
// This is a comment
What does the // MARK achieve?
The // MARK: and // MARK: - syntax in Swift functions identically to the #pragma mark and #pragma mark - syntax in Objective-C.
When using this syntax (plus // TODO: and // FIXME:), you can get some extra information to show up in the quick jump bar.
Consider these few lines of source code:
// MARK: A mark comment lives here.
func isPrime(_ value: UInt) -> Bool { return true }
And for reference, the quick jump bar is at the top in Xcode:
It exists mostly to help with quick navigation within the file.
Note that the dash (// MARK: -) causes a nice separation line to show up. Consider this MARK comment:
// MARK: - A mark comment lives here.
The darker gray separator line just above the bolded option in that menu comes from the dash.
Additionally, we can achieve this separator line without a comment by simply not having any text after the dash:
// MARK: -
As mentioned, // TODO: and // FIXME: comments will also appear here.
// MARK: - Prime functions
func isPrime(_ value: UInt) -> Bool {
// TODO: Actually implement the logic for this method
return true
}
func nthPrime(_ value: UInt) -> Int {
// FIXME: Returns incorrect values for some arguments
return 2
}
FIXMEs get a little band-aid icon that help them standout.
MARK icon looks like a table of contents
TODO icons look more like a checklist
Clicking on any line in the quick jump bar takes you directly to that line in the source code.
MARK simply adds a visual MARK in the jump bar like this:
ex // MARK: Core Data Stack
I have a UITextField that handles input of currency. The initial state of the text field has a set value of $0.00 but changes to just $ when it becomes the first responder.
I have successfully disabled the user from deleting the $ prefix of the text field's text by adding this:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if textField == priceTextField {
if range.length == 1 && count(string) == 0 {
// Deleting text
if range.location <= 0 {
return false
}
}
}
return true
}
However, this only works when the user enters text with keys and then deletes text by pressing the backspace key. If the user copies text, highlights the $ prefix and then pastes in the text, the $ prefix gets replaced with the pasted text.
If the user selects the location before the $ prefix and pastes the text, I move the $ prefix to the replacement string by handling it with:
if range.location == 0 && count(string) >= 1 {
textField.text = "$\(string)"
return false
}
I realize that I need to create some logic for using the range of the text in the text field, but I'm not sure about where to start.
I'm not asking for a handout of a code snippet, but rather if someone can point me in the direction of what sort of logic I am needing to implement so that the $ prefix is not editable and always at the beginning of the text (even when selected and pasted over)?
I would suggest you to,
1.If textfield is empty, use placeholder property of UITextField to indicate what needs to be entered.
2.If the textfield has a value,
i) in textFieldDidBeginEditing delegate, remove the $ symbol from the value, i.e. when textfield is active.
ii) in textFieldDidEndEditing delegate, add the $ symbol to the value entered, i.e. when textfield is inactive.
This question already has answers here:
Swift - Resolving a math operation in a string
(4 answers)
Closed 8 years ago.
My question is on SWIFT/COCOA programming. I want to evaluate the content inside a string. For example, I have
var1 = "2 + 3"
Is there any inbuilt function in SWIFT/COCOA that can evaluate content in var1 and return 5. I tried what I could understand from string interpolation but that is not helping
var myNum = "45/30"
var myNum2 = "sin(30)"
var myNum3 = "\(Float(myNum) * Float(myNum2))";
error: could not find member 'convertFromStringInterpolationSegment'
Also, got another question.. How do I detect Return key pressed in SWIFT? Any trigger similar to "func applicationWillTerminate(aNotification: NSNotification) "
For your second question, assuming you're using a textField, you can use the delegate method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
This method is executed when the return key is pressed. If don't want to hide the keyboard, you need to return NO from this function at the end.
If you're using a textView, you can refer to this thread. You implement the textView:shouldChangeTextInRange:replacementText: method of UITextViewDelegate and in that check if the replacement text is \n.
is there a way to limit a textfield but not by character count? I would like to stop the ability to type when the end of the field is reached. But as different characters have different dimensions stopping at a certain count ist not really a solution. Something like "stop at the end of the line" would be perfect.
this doesn't work for me
Max length UITextField
What you want to do is instead of calculating the maximum number of characters of the new string, calculate it's width in points and compare it to the width you need.
[Swift]
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let combinedString = textField.attributedText!.mutableCopy() as NSMutableAttributedString
combinedString.replaceCharactersInRange(range, withString: string)
return combinedString.size().width > textField.bounds.size.width
}
You might need to edit the attributes to get it to render on a single line.
Subscribe to controlTextDidChange and calculate the size of the text via
let s = NSString(string: <yourtext>)
let size = s.boundingRectWithSize(<#size: NSSize#>, options: <#NSStringDrawingOptions#>, attributes: <#[NSObject : AnyObject]?#>)
Now you can check if the text is too large.