Limit UITextField to one decimal point Swift

爱⌒轻易说出口 提交于 2019-12-22 19:44:49

问题


How can I limit a UITextField to one decimal point with Swift? The text field is for entering a price, so I cannot allow more than one decimal point. If I was using Objective-C, I would have used this code:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];

    NSArray *sep = [newString componentsSeparatedByString:@"."];
    if([sep count] >= 2)
    {
        NSString *sepStr=[NSString stringWithFormat:@"%@",[sep objectAtIndex:1]];
        return !([sepStr length]>1);
    }
    return YES;
}

But due a difference with how Swift uses ranges, I cannot convert this code to Swift. The first line gives me an error saying NSRange is not convertible to Range<String.Index>

EDIT: I ended up doing it like this before I saw the answer:

func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
    let tempRange = textField.text.rangeOfString(".", options: NSStringCompareOptions.LiteralSearch, range: nil, locale: nil)
    if tempRange?.isEmpty == false && string == "." {
        return false
    }

    return true
}

I found this on a different post. This solution works fine but I'm not sure if it is the best way to do it but it is a short and clean way.


回答1:


Alexey got there before me, but seeing as I'd implemented a Swift version to check things out, here it is:

func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {

    // I'm explicitly unwrapping newString here, as I want to use reverse() on it, and that
    // apparently doesn't work with implicitly unwrapped Strings.
    if let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string) {

        var decimalFound = false
        var charactersAfterDecimal = 0

        for ch in reverse(newString) {
            if ch == "." {
                decimalFound = true
                break
            }
            charactersAfterDecimal++
        }
        if decimalFound && charactersAfterDecimal > 1 {
            return false
        }
    }
    return true;
}

Note that the first line now explicitly casts the textField.text to an NSString. This is because the String version of stringByReplacingCharactersInRange takes a Swift range, not an NSRange like the one that's passed in.

I've also made the later code a lot more Swiftian, removing NSString operations. (I'm not convinced that this is wonderfully efficient, as reverse(String) might actually reverse the whole String rather than providing a simple backward iterator, but it looks like the most Swifty way of doing it.)




回答2:


Your first line in Swift will look like:

var newString = NSString(string: textField.text).stringByReplacingCharactersInRange(range, withString: string)



回答3:


Swift 4 & Xcode 9.2

This solution allows only one decimal point to be input, therefore allowing a valid double.

// Only allows one decimal point
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
    let arrayOfString = newString.components(separatedBy: ".")

    if arrayOfString.count > 2 {
        return false
    }
    return true
}



回答4:


I suggest using NSNumberFormatter's decimalSeparator property to split your String. Here's how to limit your input to one decimal place only using the NSNumberFormatter:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    if string.isEmpty { // back key
        return true
    }

    if let input = textField.text {
        let numberFormatter = NSNumberFormatter()
        let range = input.rangeOfString(numberFormatter.decimalSeparator)
        if let r = range {
            let endIndex = input.startIndex.advancedBy(input.startIndex.distanceTo(r.endIndex))
            let decimals = input.substringFromIndex(endIndex)
            return decimals.characters.count < 1
        }
    }

    return true
}



回答5:


Try this for one decimal entry:-

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {


    if(string == "." ){
        let countdots = textField.text!.componentsSeparatedByString(".").count - 1

        if countdots > 0 && string == "."
        {
            return false
        }
    }
    return true

}



回答6:


I hope it might help you:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 

 let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string) 

 let stringArr: [String] =   newString.components(separatedBy: ".")

if stringArr.count < 2 || (stringArr.count == 2 && stringArr[1].count == 1){ 
     return true

  } 
 return false
  }



回答7:


Swift 4, Xcode 9.2

This will remove the last entered decimal point:

let numberOfDecimalPoints = textField.text.components(separatedBy: ".").count - 1

if numberOfDecimalPoints > 1 {
    textField.deleteBackward()
}



回答8:


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
            if (textField.text?.componentsSeparatedByString(".").count > 1 && string == ".")
            {
                return false
            }
            return string == "" || (string == "." || Float(string) != nil)
    }


来源:https://stackoverflow.com/questions/25225904/limit-uitextfield-to-one-decimal-point-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!