0

この問題を1日以上調べた後、助けが得られるかどうかを確認します。この質問は以前に多かれ少なかれ尋ねられましたが、誰も完全な答えを出していないようですので、うまくいけば今それを得ることができます。

UILabelとUITextView(テンキー付き)を使用するユーザーが数字を入力するだけで、ラベルに通貨としてフォーマットされるというATMのような動作を実現したいと思います。アイデアは基本的にここに概説されています:

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

唯一の問題は、テキストフィールドに123のような整数を入れて、ラベルに$1.23や123¥などとして表示する方法を明示的に示していないことです。これを行うコードを持っている人はいますか。

4

4 に答える 4

3

私は解決策を見つけました。この質問の目的に従って、将来この問題を抱えている人に完全な回答を提供します. まず、NumberFormatting という新しいヘルパー クラスを作成し、2 つのメソッドを作成しました。

//
//  NumberFormatting.h
//  Created by Noah Hendrix on 12/26/09.
//

#import <Foundation/Foundation.h>


@interface NumberFormatting : NSObject {

}

-(NSString *)stringToCurrency:(NSString *)aString;
-(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal;

@end

実装ファイルは次のとおりです。

//
//  NumberFormatting.m
//  Created by Noah Hendrix on 12/26/09.
//

#import "NumberFormatting.h"


@implementation NumberFormatting

  -(NSString *)stringToCurrency:(NSString *)aString {
    NSNumberFormatter *currencyFormatter  = [[NSNumberFormatter alloc] init];
    [currencyFormatter setGeneratesDecimalNumbers:YES];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

    if ([aString length] == 0)
      aString = @"0";

    //convert the integer value of the price to a decimal number i.e. 123 = 1.23
    //[currencyFormatter maximumFractionDigits] gives number of decimal places we need to have
    //multiply by -1 so the decimal moves inward
    //we are only dealing with positive values so the number is not negative
    NSDecimalNumber *value  = [NSDecimalNumber decimalNumberWithMantissa:[aString integerValue]
                                                                exponent:(-1 * [currencyFormatter maximumFractionDigits])
                                                              isNegative:NO];

    return [currencyFormatter stringFromNumber:value];
  }

  -(NSString *)decimalToIntString:(NSDecimalNumber *)aDecimal {
    NSNumberFormatter *currencyFormatter  = [[NSNumberFormatter alloc] init];
    [currencyFormatter setGeneratesDecimalNumbers:YES];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];

    if (aDecimal == nil)
      aDecimal = [NSDecimalNumber zero];

    NSDecimalNumber *price  = [NSDecimalNumber decimalNumberWithMantissa:[aDecimal integerValue]
                                                                exponent:([currencyFormatter maximumFractionDigits])
                                                              isNegative:NO];

    return [price stringValue];
  }

@end

最初のメソッド stringToCurrency は、整数 (この場合はテキストフィールドから渡されます) を受け取り、ユーザーのロケール設定に応じて小数点を移動して 10 進数値に変換します。次に、NSNumberFormatter を使用して通貨としてフォーマットされた文字列表現を返します。

2 番目の方法は、1.23 のような値を取り、同様の方法を使用してそれを 123 に戻す逆の処理を行います。

これが私がそれをどのように使用したかの例です

...
self.accountBalanceCell.textField.text  = [[NumberFormatting alloc] decimalToIntString:account.accountBalance];
...
[self.accountBalanceCell.textField addTarget:self
                                            action:@selector(updateBalance:)
                                  forControlEvents:UIControlEventEditingChanged];

ここでは、テキスト フィールドの値をデータ ストアからの 10 進数値に設定し、オブザーバーを設定してテキスト フィールドへの変更を監視し、メソッド updateBalance を実行します。

- (void)updateBalance:(id)sender {
  UILabel *balanceLabel = (UILabel *)[accountBalanceCell.contentView viewWithTag:1000];
  NSString *value       = ((UITextField *)sender).text;
  balanceLabel.text     = [[NumberFormatting alloc] stringToCurrency:value];
}

これは単純に textfield 値を取得し、上記の stringToCurrency メソッドで実行します。

私にはこれはハックのように思えるので、使用することに興味がある場合は、少し時間をかけて全体を調べてクリーンアップしてください。また、値が大きいと壊れることに気付きます。

于 2009-12-27T22:14:00.827 に答える
2

NSNumberFormatter現在または指定されたロケールに基づいて数値データをフォーマットする を見てください。

于 2009-12-25T08:37:35.197 に答える
0

ここでの既存の回答があまり好きではなかったので、いくつかの手法を組み合わせました。入力にはテンキー キーボードで非表示の UITextField を使用し、書式設定には可視の UILabel を使用しました。

私はすべてを保持するプロパティを持っています:

@property (weak, nonatomic) IBOutlet UILabel *amountLabel;
@property (weak, nonatomic) IBOutlet UITextField *amountText;
@property (retain, nonatomic) NSDecimalNumber *amount;

ivar として金額と NSNumberFormatter を取得しました。

NSDecimalNumber *amount_;
NSNumberFormatter *formatter;

初期化時にフォーマッターをセットアップします。

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        // Custom initialization
        formatter = [NSNumberFormatter new];
        formatter.numberStyle = NSNumberFormatterCurrencyStyle;
    }
    return self;
}

入力を検証するために使用しているコードは次のとおりです。

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSString *asText = [textField.text stringByReplacingCharactersInRange:range withString:string];
    if ([asText length] == 0) {
        [self setAmount:[NSDecimalNumber zero]];
        return YES;
    }
    // We just want digits so cast the string to an integer then compare it
    // to itself. If it's unchanged then it's workable.
    NSInteger asInteger = [asText integerValue];
    NSNumber *asNumber = [NSNumber numberWithInteger:asInteger];
    if ([[asNumber stringValue] isEqualToString:asText]) {
        // Convert it to a decimal and shift it over by the fractional part.
        NSDecimalNumber *newAmount = [NSDecimalNumber decimalNumberWithDecimal:[asNumber decimalValue]];
        [self setAmount:[newAmount decimalNumberByMultiplyingByPowerOf10:-formatter.maximumFractionDigits]];
        return YES;
    }
    return NO;
}

ラベルの書式設定と完了ボタンの有効化を処理するこのセッターがあります。

-(void)setAmount:(NSDecimalNumber *)amount
{
    amount_ = amount;
    amountLabel.text = [formatter stringFromNumber:amount];
    self.navigationItem.rightBarButtonItem.enabled = [self isValid];
}
于 2012-07-23T16:14:38.677 に答える
0

この質問に対する正しい回答がまだ表示されていないため、NSScanner を使用せずに解決策を共有します (スキャナーは機能しないようです)。この「小数点を含む数値を入力する最良の方法は何ですか?」と「NSStringから数字以外をすべて削除する」の組み合わせです。

最初に、次のように UITextField でユーザーの現地通貨設定を含む NSString を提示します。

//currencyFormatter is of type NSNumberFormatter
if (currencyFormatter == nil) {
    currencyFormatter = [[NSNumberFormatter alloc] init];
    [currencyFormatter setLocale:[NSLocale currentLocale]];
    [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
    //[currencyFormatter setGeneratesDecimalNumbers:YES];
    decimalSeperator = [currencyFormatter decimalSeparator];  //NSString
    currencyScale = [currencyFormatter maximumFractionDigits]; //short
    //[currencyFormatter release]; don't forget to release the Formatter at one point

}


//costField is of type UITextField
NSDecimalNumber *nullValue = [NSDecimalNumber decimalNumberWithMantissa:0 exponent:currencyScale isNegative:NO];
[costField setText:[currencyFormatter stringFromNumber:nullValue]];

これは、viewControllers メソッドの viewDidLoad: で行うことができます。ユーザーの設定によっては、$0.00 (米国のローカル設定の場合) のような文字列が表示されます。ここでの状況によっては、データ モデルから値を提示したい場合があります。

ユーザーがテキスト フィールド内をタッチすると、次のタイプのキーボードが表示されます。

costField.keyboardType = UIKeyboardTypeDecimalPad; 

これにより、ユーザーは数字以外を入力できなくなります。

次の UITextField のデリゲート メソッドでは、文字列を分離して数字のみを取得します (ここでは NSScanner の使用を避けています)。これが可能なのは、以前に指定された 'currencyScale' 値を使用して小数点記号を設定する場所を知っているからです。

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

if (textField == costField) {

    //if for what ever reason ther currency scale is not available set it to 2
    //which is the most common scale value 
    if (!currencyScale) {
        currencyScale = 2;
    }

    // separate string from all but numbers
    // https://stackoverflow.com/questions/1129521/remove-all-but-numbers-from-nsstring/1163595#1163595
    NSString *aString = [textField text];
    NSMutableString *strippedString = [NSMutableString stringWithCapacity:10];
    for (int i=0; i<[aString length]; i++) {
        if (isdigit([aString characterAtIndex:i])) {
            [strippedString appendFormat:@"%c",[aString characterAtIndex:i]];
        }
    }

    //add the newly entered character as a number
    // https://stackoverflow.com/questions/276382/what-is-the-best-way-to-enter-numeric-values-with-decimal-points/2636699#2636699
    double cents = [strippedString doubleValue];
     NSLog(@"Cents:%f ",[strippedString doubleValue]);
    if ([string length]) {
        for (size_t i = 0; i < [string length]; i++) {
            unichar c = [string characterAtIndex:i];
            if (isnumber(c)) {
                cents *= 10;        //multiply by 10 to add a 0 at the end
                cents += c - '0';  // makes a number out of the charactor and replace the 0 (see ASCII Table)
            }            
        }
    } 
    else {
        // back Space if the user delete a number
        cents = floor(cents / 10);
    }

    //like this you could save the value as a NSDecimalNumber in your data model
    //costPerHour is of type NSDecimalNumber
    self.costPerHour = [NSDecimalNumber decimalNumberWithMantissa:cents exponent:-currencyScale isNegative:NO];

    //creat the string with the currency symbol and the currency separator
    [textField setText:[currencyFormatter stringFromNumber:costPerHour]];

    return NO;
    }

return YES;
}

このように、ユーザーが入力した通貨は常に正確であり、チェックする必要はありません。どの通貨設定が選択されていても、これは常に正しくフォーマットされた通貨になります。

于 2011-07-15T13:04:07.893 に答える