【问题标题】:Get decimal separator of decimal pad keyboard on iOS在iOS上获取小数键盘的小数分隔符
【发布时间】:2018-12-16 10:15:45
【问题描述】:

我正在尝试找出 iOS 中的小数键盘使用哪个小数分隔符,因此我可以将用户输入的字符串转换为带有 NumberFormatter 的数字并返回。

由于我想用现有值预填充文本字段,我需要一个数字格式化程序,它使用与小数点键盘相同的小数分隔符。


我的设备设置的语言(德语、德国)使用逗号作为小数分隔符。我已将 iOS 配置为将德语键盘作为主要和活动键盘,将英语(美国、QWERTY)作为辅助键盘。

我正在开发的应用程序只有一个基本本地化,即英语。在方案设置中,区域和语言设置为系统默认。

如果我运行我的应用程序,小数键盘使用的小数分隔符是“.”,它是 en-US 键盘使用的小数分隔符,而不是 de-DE 键盘使用的小数分隔符。普通字母键盘显示德语键盘布局。

如果我移除 iOS 设备上的 en-US 键盘,小数点分隔符会变为“,”。


我怎样才能可靠地找出小数键盘使用的是哪个小数分隔符?

到目前为止,我尝试过的所有解决方案都不起作用:

  • 使用NumberFormatter 的预设decimalSeparator 总是给出“,”。
  • 使用Locale.current.decimalSeparator 也总是返回“,”。
  • 使用textField.textInputMode?.primaryLanguage 找出语言环境总是返回de-DE
  • 使用Bundle.main.preferredLocalizations 找出应用使用的本地化总是返回en

这是数字格式化程序的配置方式:

let numberFormatter = NumberFormatter()
numberFormatter.minimumIntegerDigits = 1
numberFormatter.minimumFractionDigits = 0
numberFormatter.maximumFractionDigits = 2

编辑:似乎可以通过查找活动文本输入模式和应用程序本地化之间的匹配来确定小数点使用的语言环境:

let inputLocales = UITextInputMode.activeInputModes.compactMap {$0.primaryLanguage}.map(Locale.init(identifier:))
let localizations = Bundle.main.preferredLocalizations.map(Locale.init(identifier:))

let locale = inputLocales.flatMap { l in localizations.map {(l, $0)}}
    .filter { preferredLanguage, preferredLocalization in
        if preferredLocalization.regionCode == nil || preferredLanguage.regionCode == nil {
            return preferredLanguage.languageCode == preferredLocalization.languageCode
        } else {
            return preferredLanguage == preferredLocalization
        }
    }
    .first?.0
    ?? Locale.current

numberFormatter.locale = locale

但是这个解决方案有几个缺点:

  1. 我不知道 UIKit 是否正是这样选择小数分隔符的。某些语言的行为可能会有所不同
  2. 每次格式化数字时都必须计算它,因为用户可能会在应用运行时更换键盘。

【问题讨论】:

  • 在设置应用程序中的语言和地区下,您是否在“首选语言顺序”下列出了其他语言?如果有的话,试着删除它们,看看会发生什么。
  • 更改此设置不会更改小数分隔符。它似乎是启用的UITextInputModes 集和应用程序的首选本地化之间的交集。使用这种方法,我成功地确定了我测试过的语言的小数点分隔符,但我无法知道我的算法在每种情况下是否正确。
  • 伙伴,谢谢!

标签: ios uikit foundation


【解决方案1】:

我的经验是,当您只支持英文本地化时,十进制键盘类型中的小数分隔符将始终为.。因此,在从字符串中解析数字时,您需要在 NumberFormatter 中强制使用 en_US 语言环境。

这是一个代码 sn-p,它首先尝试使用 en_US 进行解析,然后尝试使用 Locale.current 进行解析。

func parseNumber(_ text:String) -> Double? {

    // since we only support english localization, keyboard always show '.' as decimal separator,
    // hence we need to force en_US locale
    let fmtUS = NumberFormatter()
    fmtUS.locale = Locale(identifier: "en_US")
    if let number = fmtUS.number(from: text)?.doubleValue {
        print("parsed using \(fmtUS.locale)")
        return number
    }

    let fmtCurrent = NumberFormatter()
    fmtCurrent.locale = Locale.current
    if let number = fmtCurrent.number(from: text)?.doubleValue {
        print("parsed using \(fmtCurrent.locale)")
        return number
    }

    print("can't parse number")
    return nil
}

如果 Apple 将 Locale.current 十进制分隔符添加为十进制键盘类型的小数分隔符,我将不胜感激,否则我们需要为所有语言环境添加本地化以实现此目的。

【讨论】:

  • 感谢您的回复。虽然这种方法适用于从字符串到数字的转换,但它不适用于反向,即使用默认值或先前选择的值预填充文本字段。 (此外,在涉及分组分隔符时,小数分隔符之间的动态切换可能会导致歧义)。
  • 我不确定我理解你想要做什么。您似乎想对预填充的值使用键盘小数点分隔符,但对我来说使用当前的 lokale 更有意义。在从数字转换为字符串时也是如此。
猜你喜欢
  • 1970-01-01
  • 2010-11-13
  • 2011-04-18
  • 1970-01-01
  • 2012-06-16
  • 1970-01-01
  • 2016-10-29
  • 2014-01-28
  • 2015-12-08
相关资源
最近更新 更多