[android] MVVM – 3. EditText, RatingBar, Validation

========= 2017.05.31 수정 ========

https://stackoverflow.com/a/33474455/1025379 의 방법으로 변경했음.

 


정보를 입력하는 화면에서 제대로 입력하지 않았을 때도 MVVM으로 할 수 있다. 이런 작업은 RxBindig을 사용했는데,  MVVM과 RxJava를 같이 사용하는 글을 따라하다가 문득 생각나서 찾아보니 RxBinding 이 RxJava 2를 지원하게 바뀌어서 혹시나 싶어서 RxJava 2로 바꾸다가 실패해서 다른 방법을 찾았다. 이게 더 쉬운 것 같다.

이 방법은 보통은 2-way data bingding 같은 걸로 많이 검색되더라.

 

이름, 이메일, 점수를 모두 입력해야하고, 이메일은 이메일 규칙에 맞아야만 버튼이 활성화 되게 만들었다.

 

사용할 뷰모델을 만든다.

public class InputViewModel implements BaseViewModel {
  public final ObservableField<String> name = new ObservableField<>();
  public final ObservableField<String> email = new ObservableField<>();
  public final ObservableInt score = new ObservableInt();
  public final ObservableBoolean isValid = new ObservableBoolean();

  @Override
  public void onCreate() {
    score.set(0);
    isValid.set(false);

    name.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
      @Override
      public void onPropertyChanged(Observable observable, int i) {
        validation();
      }
    });

    email.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
      @Override
      public void onPropertyChanged(Observable observable, int i) {
        validation();
      }
    });
  }

  @Override
  public void onResume() {}

  @Override
  public void onPause() {}

  @Override
  public void onDestroy() {}

  private void validation() {
    boolean isValidName = !TextUtils.isEmpty(name.get());
    boolean isValidEmail = !TextUtils.isEmpty(email.get()) && Patterns.EMAIL_ADDRESS.matcher(email.get()).matches();
    boolean isValidScore = score.get() > 0;
    isValid.set(isValidName && isValidEmail && isValidScore);
  }

  public RatingBar.OnRatingBarChangeListener scoreChangeListener = new RatingBar.OnRatingBarChangeListener() {
    @Override
    public void onRatingChanged(RatingBar ratingBar, float v, boolean b) {
      score.set((int) v);
      validation();
    }
  };
}

 

화면도 만든다.

<?xml version="1.0" encoding="utf-8"?>
<layout>

  <data>

    <variable
      name="model"
      type="kr.susemi99.testmvvm.view_models.InputViewModel"/>
  </data>

  <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <EditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="name"
      android:text="@={model.name}"/> <!-- not @{model.name} -->

    <EditText
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="email"
      android:inputType="textEmailAddress"
      android:text="@={model.email}"/> <!-- not @{model.email} --> 

    <RatingBar
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:rating="@{model.score}"
      android:stepSize="1"
      app:OnRatingBarChangeListener="@{model.scoreChangeListener}"/>

    <Button
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:enabled="@{model.isValid}"
      android:text="@android:string/ok"/>
  </LinearLayout>
</layout>

 

뷰모델을 연결시켜주면 끝난다.

public class InputActivity extends AppCompatActivity {

  private InputViewModel model = new InputViewModel();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityInputBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_input);
    binding.setModel(model);
    model.onCreate();
  }
}

 

아무 것도 입력하지 않으면 ok 버튼은 비활성화 된다.

 

 

 

이름과 이메일을 넣어도 점수를 넣지 않으면 비활성화 된다.

 

 

 

다 넣었지만, 이메일 규격이 맞지 않으면 역시 비활성화 된다.

 

 

 

모두 입력하고, 이메일 규격에도 맞으면 활성화 된다.

 

 

RxBinding과 ButterKnife 를 안 써도 이렇게 쉽게 할 수 있다.