web-dev-qa-db-ja.com

小数点付きの数値を入力する最良の方法は何ですか?

私のアプリでは、ユーザーは小数点以下の数値を入力できる必要があります。 iPhoneは、この目的に固有のキーボードを提供していません。テンキーと、数字と記号を備えたキーボードのみです。

後者を使用して、最終結果を正規表現しなくても数値以外の入力が行われないようにする簡単な方法はありますか?

ありがとう!

51
Andrew Grant

よりエレガントなソリューションは、最も単純なものです。

小数点記号は必要ありません

どうして?ユーザーの入力から単純に推測できるからです。たとえば、USロケールでは、$ 1.23に何を入力するかを指定するときに、1〜2〜3の数字を(この順序で)入力することから始めます。システムでは、各文字が入力されると、これは次のように認識されます。

  • ユーザーが1を入力:$ 0.01
  • ユーザーが2を入力:$ 0.12
  • ユーザーが3を入力:$ 1.23

ユーザーの入力に基づいて小数点記号を推定したことに注目してください。ユーザーが$ 1.00で入力したい場合は、1-0-0の数字を入力するだけです。

コードで異なるロケールの通貨を処理するには、通貨の最大の小数桁を取得する必要があります。これは、次のコードスニペットで実行できます。

NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
int currencyScale = [currencyFormatter maximumFractionDigits];

たとえば、日本円の最大小数桁は0です。そのため、円入力を処理する場合、小数点記号がないため、小数を気にする必要もありません。

この問題へのアプローチにより、Appleによって提供される標準の数値入力キーパッドをカスタムキーパッドや正規表現検証などの問題なしに使用できます。

49
shek

IOS 4.1以降では新しいUIKeyboardTypeDecimalPadを使用できることを指摘しておくとよいでしょう。

だから今あなたはただしなければならない:

myTextField.keyboardType=UIKeyboardTypeDecimalPad;
53
Zebs

受け入れられた回答で提案されたソリューションの例を次に示します。これは他の通貨や何も処理しません-私の場合、ロケール/通貨に関係なく、ドルのサポートだけが必要でしたので、これは私にとっては問題ありませんでした:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
    replacementString:(NSString *)string {

    double currentValue = [textField.text doubleValue];
    //Replace line above with this
    //double currentValue = [[textField text] substringFromIndex:1] doubleValue];
    double cents = round(currentValue * 100.0f);

    if ([string length]) {
        for (size_t i = 0; i < [string length]; i++) {
            unichar c = [string characterAtIndex:i];
            if (isnumber(c)) {
                cents *= 10;
                cents += c - '0'; 
            }            
        }
    } else {
        // back Space
        cents = floor(cents / 10);
    }

    textField.text = [NSString stringWithFormat:@"%.2f", cents / 100.0f];
    //Add this line
    //[textField setText:[NSString stringWithFormat:@"$%@",[textField text]]];
    return NO;
}

丸めと床は重要です。a)浮動小数点表現では.00001などが失われることがあり、b)バックスペース部分で削除した精度を切り上げるフォーマット文字列。

12
Mike Weller

まったく同じことをしたかったのですが、10進数の値ではなく通貨を使用しました。

最終的に、UITextFieldとUILabelを含むカスタムビューを作成しました。ラベルはテキストフィールドを覆っていますが、テキストフィールドはまだタッチを受けています。 UITextFieldTextDidChange通知を使用してテキストフィールドの変更を監視し(NSNumberFormatterを使用して結果の数値をフォーマット済みの通貨値に変換し)、ラベルを更新します。

ユーザーが挿入ポイントを再配置できるルーペを無効にするには、カスタムUITextFieldサブクラスを使用してtouchesBegan:withEvent:をオーバーライドし、何もしないように設定する必要があります。

小数点は常に固定されているため、私の解決策は必要なものとは異なる可能性があります-システムの通貨設定を使用して、小数点の後に何桁あるべきかを決定します。ただし、テンキーには小数点がありません。そして、キーボードにボタンを追加することはできません(キーボードの左下隅に小数点に最適な空白のボタンがあるため、これは特に悪化します!)そのための解決策はありません、残念ながら。

3
Alex

スライダー(Martin v。Löwisが推奨)または数字ごとに個別のホイールを備えたUIPickerViewを使用することができます。

2
Jeroen Heijmans

小数点付きのカスタムナンバーパッドビューコントローラを作成しました...確認してください:

http://sites.google.com/site/psychopupnet/iphone-sdk/tenkeypadcustom10-keypadwithdecimal

2
Richard

特定のアプリケーションに応じて、ユーザーが位置を選択できるスライダーを提供することは、iPhoneでのより良い選択かもしれません。その後、数字を入力する必要はまったくありません。

2

ここでは、通貨にとらわれない方法でfloat、round()、ceil()を使用せずにそれを行う方法を説明します。

ビューコントローラーで、次のインスタンス変数を設定します(バッグの場合は、関連する@propertyステートメントを使用します)。

@interface MyViewController : UIViewController <UITextFieldDelegate> {
@private
    UITextField *firstResponder;
    NSNumberFormatter *formatter;
    NSInteger currencyScale;
    NSString *enteredDigits;
}

@property (nonatomic, readwrite, assign) UITextField *firstResponder;
@property (nonatomic, readwrite, retain) NSNumberFormatter *formatter;
@property (nonatomic, readwrite, retain) NSString *enteredDigits;

@end

そしてあなたのviewDidLoadメソッドは以下を含むべきです:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSNumberFormatter *aFormatter = [[NSNumberFormatter alloc] init];
    [aFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    currencyScale = -1 * [aFormatter maximumFractionDigits];
    self.formatter = aFormatter;
    [aFormatter release];
}

次に、UITextFieldDelegateメソッドを次のように実装します。

#pragma mark -
#pragma mark UITextFieldDelegate methods

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    // Keep a pointer to the field, so we can resign it from a toolbar
    self.firstResponder = textField;
    self.enteredDigits = @"";
}

- (void)textFieldDidEndEditing:(UITextField *)textField {
    if ([self.enteredDigits length] > 0) {
        // Get the amount
        NSDecimalNumber *result = [[NSDecimalNumber decimalNumberWithString:self.enteredDigits] decimalNumberByMultiplyingByPowerOf10:currencyScale];
        NSLog(@"result: %@", result);
    }
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {

    // Check the length of the string
    if ([string length]) {
        self.enteredDigits = [self.enteredDigits stringByAppendingFormat:@"%d", [string integerValue]];
    } else {
        // This is a backspace
        NSUInteger len = [self.enteredDigits length];
        if (len > 1) {
            self.enteredDigits = [self.enteredDigits substringWithRange:NSMakeRange(0, len - 1)];
        } else {
            self.enteredDigits = @"";
        }
    }

    NSDecimalNumber *decimal = nil;

    if ( ![self.enteredDigits isEqualToString:@""]) {
        decimal = [[NSDecimalNumber decimalNumberWithString:self.enteredDigits] decimalNumberByMultiplyingByPowerOf10:currencyScale];
    } else {
        decimal = [NSDecimalNumber zero];
    }

    // Replace the text with the localized decimal number
    textField.text = [self.formatter stringFromNumber:decimal];

    return NO;  
}

これはポンドとペンスでのみテストされましたが、日本円でも動作するはずです。通貨以外の目的で小数をフォーマットする場合は、 NSNumberFormatter のドキュメントを読み、必要なフォーマット/ maximumFractionDigitsを設定します。

1
Daniel Thorpe

IOS4.1以降、新しいキーボードタイプUIKeyboardTypeNumberPadがありますが、残念ながら、現時点ではInterface Builderの選択リストに表示されていないようです。

1
Screwtape

STATextField を使用して、currencyRepresentationをYESに設定できます。

小数点が1つだけ入力され、小数点の右側に2桁以下が入力されるようにします。

また、通貨モードATMテキストエントリをデフォルトでサポートする STAATMTextField もあります。

ATMマシンの入力動作を模倣するテキストフィールドを提供します。

0
Stunner

A Swift Mike Wellerの投稿の2つの実装、USDのみ:

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    guard let str = textField.text else {
        textField.text = "0.00"
        return false
    }

    let value = (str as NSString).doubleValue

    var cents = round(value * 100)
    if string.characters.count > 0 {
        for c in string.characters {
            if let num = Int(String(c)) {
                cents *= 10
                cents += Double(num)
            }
        }
    }
    else {
        cents = floor(cents / 10)
    }

    textField.text = NSString(format: "%.2f", cents/100) as String

    return false
}
0
ccwasden