2016-05-26 4 views
5

ここで何かを紛失しているはずです。 Androidの双方向バインディングで見たすべての例は、EditTextのように、ユーザーが入力できるもののバッキングデータに基づいてStringに基づいています。数字をAndroidに正しく2ウェイバインドする方法editText

文字列ではないものを扱うのはやや控えめです。たとえば、私のドメインモデルで編集可能にする必要がある場合、私が思い付いた最良のバインディングは、ViewModelと、モデルとEditTextの間のインターフェイスに驚くほど多くのコードを必要とします。

何かキーがありませんか? EditTextをダブルでインターフェイスするには、30行のコードが本当に必要ですか?議論のために、のはEditTextバインド双方向で、二重のように表さ、通貨フィールドを考えてみましょう:

<EditText 
android:layout_width="wrap_content" 
android:layout_height="wrap_content" 
android:inputType="numberDecimal" 
android:text="@={fragModel.startBucks}" 
android:id="@+id/editText2"/> 

そして、ここで私はのEditTextにする文字列を与えるために構築しなければならなかったのViewModelです縛る

@Bindable private String startBucksString; 
private double localBucks; 
public String getStartBucksString() { 
    double domainBucks = cd.getStartBucks(); 
    // Ignore incoming change of less than rounding error 
    if(Math.abs(localBucks - domainBucks) < .001 ) return startBucksString; 
    startBucksString = ""; 
    if(domainBucks != 0) 
     startBucksString = String.format("$%.2f", domainBucks); 
    return startBucksString; 
} 

public void setStartBucksString(String inBuckstr) { 
    double calcBucks=0; 
    inBuckstr = inBuckstr.replaceAll("[^\\d.]", ""); 
    try { 
     calcBucks = Double.parseDouble(inBuckstr); 
    } catch(NumberFormatException e) { 
     return; 
    } 
    // Neglect outgoing change of less than rounding error 
    if(Math.abs(localBucks - calcBucks) < .001 ) return; 

    startBucksString = String.format("$%.2f", calcBucks); 
    localBucks = calcBucks; 
    cd.setStartBucks(calcBucks); 
    notifyPropertyChanged(BR.startBucksString); 
} 

ここでは、a simple, compilable example of 2-way binding with a ViewModelと書きました。これは、ドメインモデルでフロートを継続的に更新する際の難しさを示しています。結局、各ドメインフィールド用のカスタムTextWatcherを作成せずにそれを行う方法はないと判断しました。

答えて

1

私のアプローチは、Handleを使用してnotifyPropertyChangedメソッド呼び出しを遅らせることです。このように、ユーザーが入力している間、コードは実行されず、ユーザーが最後の文字を入力するのを停止してから2,5秒後に、notificationPropertyChangedが呼び出されます。

視覚効果はクールです。ユーザーは自由に数字を書くことができます。

は、これらの2つの例を参照してください:(?)

使用して、各フィールドに、このコンパクトなコードを使用することができます:あなたは、通貨コンバータまたはパーセントのコンバータを使用する場合

// 
// g1FuelCostYear field 
// 
private double g1FuelCostYear; 

@Bindable 
public String getG1FuelCostYear() { 
    return Double.valueOf(g1FuelCostYear).toString(); 
} 

private Handler hG1FuelCostYearDelay = null; 

public void setG1FuelCostYear(String g1FuelCostYear) { 

    // Delayed notification hadler creation 
    if (hG1FuelCostYearDelay == null) { 
    hG1FuelCostYearDelay = new Handler() { 
     @Override 
     public void handleMessage(Message msg) { 
     notifyPropertyChanged(it.techgest.airetcc2.BR.g1FuelCostYear); 
     } 
    }; 
    } else { 
    // For each call remove pending notifications 
    hG1FuelCostYearDelay.removeCallbacksAndMessages(null); 
    } 

    // Data conversion logic 
    try { 
    this.g1FuelCostYear = Double.parseDouble(g1FuelCostYear); 
    } 
    catch (Exception ex) { 
    this.g1FuelCostYear = 0.0; 
    log(ex); 
    } 

    // New delayed field notification (other old notifications are removed before) 
    hG1FuelCostYearDelay.sendEmptyMessageDelayed(0,2500); 
} 

このコードではなく、便利です。ユーザーはプレーン・ダブルを書くことができ、コードは通貨文字列に変換されます。 setterが通貨文字列で呼び出された場合、コードはそれをdoubleとしても変換できます。

// 
// g1FuelCostYear field 
// 
private double g1FuelCostYear; 

@Bindable 
public String getG1FuelCostYear() { 
    NumberFormat nf = NumberFormat.getCurrencyInstance(); 
    return nf.format(this.g1FuelCostYear); 
    //return Double.valueOf(g1FuelCostYear).toString(); 
} 

private Handler hG1FuelCostYearDelay = null; 

public void setG1FuelCostYear(String g1FuelCostYear) { 
    if (hG1FuelCostYearDelay == null) 
    { 
    hG1FuelCostYearDelay = new Handler() { 
     @Override 
     public void handleMessage(Message msg) { 
      notifyPropertyChanged(it.techgest.airetcc2.BR.g1FuelCostYear); 
     } 
    }; 
    } else { 
     hG1FuelCostYearDelay.removeCallbacksAndMessages(null); 
    } 
    boolean success = false; 
    try { 
    NumberFormat nf = NumberFormat.getCurrencyInstance(); 
    this.g1FuelCostYear = nf.parse(g1FuelCostYear).doubleValue(); 
    success = true; 
    } 
    catch (Exception ex) { 
    this.g1FuelCostYear = 0.0; 
    log(ex); 
    } 
    if (!success) { 
    try { 
     this.g1FuelCostYear = Double.parseDouble(g1FuelCostYear); 
     success = true; 
    } catch (Exception ex) { 
     this.g1FuelCostYear = 0.0; 
     log(ex); 
    } 
    } 
    updateG1FuelConsumption(); 
    hG1FuelCostYearDelay.sendEmptyMessageDelayed(0,2500); 
} 
+0

ありがとうございます!それは有用で現実的な例であり、おそらくもっと良い方法はありません。しかし、私が本当に探しているのは、フロートを最小限のコードでフィールドにバインドするエレガントでシンプルな方法です。ストリングを束縛するのはとても簡単で、フロートを束縛するほど複雑なことは私には奇妙に思えます。 –

関連する問題