2016-05-06 15 views
7

Vorrei associare un messaggio di errore direttamente a android.support.design.widget.TextInputLayout. Non riesco a trovare un modo per impostare l'errore attraverso il layout. È possibile?Posso associare un messaggio di errore a un TextInputLayout?

Questo è come mi immaginavo di lavoro:

<?xml version="1.0" encoding="utf-8"?> 
<layout 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"> 
    <data> 
     <import type="android.view.View" /> 
     <variable 
      name="error" 
      type="String" /> 
    </data> 
    <android.support.v7.widget.LinearLayoutCompat 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical"> 

     <android.support.design.widget.TextInputLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      app:errorEnabled="true" 
      app:errorText="@{error}"> 
      <EditText 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" 
       android:hint="@string/username" 
       android:inputType="textEmailAddress" /> 
     </android.support.design.widget.TextInputLayout> 
    </android.support.v7.widget.LinearLayoutCompat> 
</layout> 
+0

Usa può leggere all'indirizzo: http://developer.android.com/intl/vi/tools/data-binding/guide.html. Ottieni il binding dall'attività, come: MainActivityBinding binding = DataBindingUtil.setContentView (this, R.layout.main_activity); e imposta valore da binding.setError ("String you want") –

+0

Non si tratta proprio di una domanda. So già come eseguire il binding di base. – Theyouthis

risposta

17

Non v'è alcun attributo XML corrispondente al setError() metodo, quindi non è possibile impostare il messaggio di errore direttamente in XML (che è po 'strano sapendo errorEnabled è lì). Ma questo può essere facilmente risolto creando Binding Adapter che l'avrebbe impostato per te. Qualcosa del genere.

@BindingAdapter("app:errorText") 
public static void setErrorMessage(TextInputLayout view, String errorMessage) { 
    view.setError(errorMessage); 
} 

V. official binding docs, sezione "attributi Setter" in particolare "Setter personalizzati"

EDIT

domanda Forse stupida, ma dove dovrei mettere questo? Devo estendere TextInputLayout e metterlo lì dentro?

In realtà non è una domanda stupida, semplicemente perché non è possibile ottenere una risposta completa leggendo la documentazione ufficiale. Fortunatamente è piuttosto semplice: non è necessario estendere nulla: è sufficiente inserire il metodo in qualsiasi punto nei progetti. È possibile creare una classe separata (ad esempio BindingTools.java) o semplicemente aggiungere questo metodo a qualsiasi classe esistente nel progetto. Finché si annotare questo metodo con @BindingAdapter, assicurarsi che sia publicestatic non importa quale classe si vive.

+0

Forse domanda stupida, ma dove dovrei metterlo? Devo estendere TextInputLayout e metterlo lì dentro? – Theyouthis

+0

Vedere la risposta modificata. –

+0

Grazie signore per la vostra guida. – Theyouthis

1

Ho fatto un legante come la mia risposta su How to set error on EditText using DataBinding Framwork MVVM. Ma questa volta ha usato TextInputLayout come esempio, come il precedente.

scopi di questa idea:

  1. Fare il xml più leggibili possibile e indipendente
  2. Fare la convalida convalida di attività-side e xml-side in modo indipendente

Naturalmente, è possibile rendi la tua convalida e impostala utilizzando il tag <variable> in xml

In primo luogo, implementa la statica metodo di associazione e le relative regole di convalida della stringa per la preparazione.

Binding

@BindingAdapter({"app:validation", "app:errorMsg"}) 
    public static void setErrorEnable(TextInputLayout textInputLayout, StringRule stringRule, 
     final String errorMsg) { 
    } 

StringRule

public static class Rule { 

    public static StringRule NOT_EMPTY_RULE = s -> TextUtils.isEmpty(s.toString()); 
    public static StringRule EMAIL_RULE = s -> s.toString().length() > 18; 
    } 

    public interface StringRule { 

    boolean validate(Editable s); 
    } 

In secondo luogo, mettere la validazione di default e il messaggio di errore nel TextInputLayout e rendere più facile per conoscere la convalida, vincolante in xml

<android.support.design.widget.TextInputLayout 
     android:id="@+id/imageUrlValidation" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     app:validation="@{Rule.NOT_EMPTY_RULE}" 
     app:errorMsg='@{"Cannot be empty"}' 
     > 
     <android.support.design.widget.TextInputEditText 
     android:id="@+id/input_imageUrl" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:hint="Image Url" 
     android:text="@={feedEntry.imageUrl}" /> 
    </android.support.design.widget.TextInputLayout> 

In terzo luogo, quando si attiva il pulsante clic, è possibile utilizzare l'ID predefinito in TextInputLayout (ad es. imageUrlValidation) per fare la validazione finale sull'attività

Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE); 
     button.setOnClickListener(view1 -> { 
      // TODO Do something 
      //to trigger auto error enable 
      FeedEntry inputFeedEntry = dialogFeedEntryBinding.getFeedEntry(); 
      Boolean[] validations = new Boolean[]{ 
       dialogFeedEntryBinding.imageUrlValidation.isErrorEnabled(), 
       dialogFeedEntryBinding.titleValidation.isErrorEnabled(), 
       dialogFeedEntryBinding.subTitleValidation.isErrorEnabled() 
      }; 
      boolean isValid = true; 
      for (Boolean validation : validations) { 
      if (validation) { 
       isValid = false; 
      } 
      } 
      if (isValid) { 
      new AsyncTask<FeedEntry, Void, Void>() { 
       @Override 
       protected Void doInBackground(FeedEntry... feedEntries) { 
       viewModel.insert(feedEntries); 
       return null; 
       } 
      }.execute(inputFeedEntry); 
      dialogInterface.dismiss(); 
      } 
     }); 

Il codice completo è il seguente:

dialog_feedentry.xml

<?xml version="1.0" encoding="utf-8"?> 
<layout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto"> 
    <data> 

    <import type="com.example.common.components.TextInputEditTextBindingUtil.Rule" /> 

    <variable 
     name="feedEntry" 
     type="com.example.feedentry.repository.bean.FeedEntry" /> 

    </data> 
    <LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:padding="10dp" 
    android:orientation="vertical"> 
    <android.support.design.widget.TextInputLayout 
     android:id="@+id/imageUrlValidation" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     app:validation="@{Rule.NOT_EMPTY_RULE}" 
     app:errorMsg='@{"Cannot be empty"}' 
     > 
     <android.support.design.widget.TextInputEditText 
     android:id="@+id/input_imageUrl" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:hint="Image Url" 
     android:text="@={feedEntry.imageUrl}" /> 
    </android.support.design.widget.TextInputLayout> 

    <android.support.design.widget.TextInputLayout 
     android:id="@+id/titleValidation" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     app:validation="@{Rule.NOT_EMPTY_RULE}" 
     app:errorMsg='@{"Cannot be empty"}' 
     > 

     <android.support.design.widget.TextInputEditText 
     android:id="@+id/input_title" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:hint="Title" 
     android:text="@={feedEntry.title}" 

     /> 
    </android.support.design.widget.TextInputLayout> 
    <android.support.design.widget.TextInputLayout 
     android:id="@+id/subTitleValidation" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     app:validation="@{Rule.NOT_EMPTY_RULE}" 
     app:errorMsg='@{"Cannot be empty"}' 
     > 

     <android.support.design.widget.TextInputEditText 
     android:id="@+id/input_subtitle" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:hint="Subtitle" 
     android:text="@={feedEntry.subTitle}" 

     /> 
    </android.support.design.widget.TextInputLayout> 
    </LinearLayout> 
</layout> 

TextInputEditTextBindingUtil.java

package com.example.common.components; 

import android.databinding.BindingAdapter; 
import android.support.design.widget.TextInputLayout; 
import android.text.Editable; 
import android.text.TextUtils; 
import android.text.TextWatcher; 

/** 
* Created by Charles Ng on 7/9/2017. 
*/ 

public class TextInputEditTextBindingUtil { 


    @BindingAdapter({"app:validation", "app:errorMsg"}) 
    public static void setErrorEnable(TextInputLayout textInputLayout, StringRule stringRule, 
     final String errorMsg) { 
    textInputLayout.getEditText().addTextChangedListener(new TextWatcher() { 
     @Override 
     public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { 
     } 

     @Override 
     public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { 
     } 

     @Override 
     public void afterTextChanged(Editable editable) { 
     textInputLayout 
      .setErrorEnabled(stringRule.validate(textInputLayout.getEditText().getText())); 
     if (stringRule.validate(textInputLayout.getEditText().getText())) { 
      textInputLayout.setError(errorMsg); 
     } else { 
      textInputLayout.setError(null); 
     } 
     } 
    }); 
    textInputLayout 
     .setErrorEnabled(stringRule.validate(textInputLayout.getEditText().getText())); 
    if (stringRule.validate(textInputLayout.getEditText().getText())) { 
     textInputLayout.setError(errorMsg); 
    } else { 
     textInputLayout.setError(null); 
    } 
    } 

    public static class Rule { 

    public static StringRule NOT_EMPTY_RULE = s -> TextUtils.isEmpty(s.toString()); 
    public static StringRule EMAIL_RULE = s -> s.toString().length() > 18; 
    } 

    public interface StringRule { 

    boolean validate(Editable s); 
    } 

} 

FeedActivity.java

public class FeedActivity extends AppCompatActivity { 

    private FeedEntryListViewModel viewModel; 

    @SuppressLint("StaticFieldLeak") 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_feed); 
    viewModel = ViewModelProviders.of(this) 
     .get(FeedEntryListViewModel.class); 
    viewModel.init(this); 
    ViewPager viewPager = findViewById(R.id.viewpager); 
    setupViewPager(viewPager); 
    // Set Tabs inside Toolbar 
    TabLayout tabs = findViewById(R.id.tabs); 
    tabs.setupWithViewPager(viewPager); 
    Toolbar toolbar = findViewById(R.id.toolbar); 
    setSupportActionBar(toolbar); 
    FloatingActionButton fab = findViewById(R.id.fab); 
    fab.setOnClickListener(view -> { 
     //insert sample data by button click 
     final DialogFeedentryBinding dialogFeedEntryBinding = DataBindingUtil 
      .inflate(LayoutInflater.from(this), R.layout.dialog_feedentry, null, false); 
     FeedEntry feedEntry = new FeedEntry("", ""); 
     feedEntry.setImageUrl("http://i.imgur.com/DvpvklR.png"); 
     dialogFeedEntryBinding.setFeedEntry(feedEntry); 
     final Dialog dialog = new AlertDialog.Builder(FeedActivity.this) 
      .setTitle("Create a new Feed Entry") 
      .setView(dialogFeedEntryBinding.getRoot()) 
      .setPositiveButton("Submit", null) 
      .setNegativeButton("Cancel", (dialogInterface, i) -> dialogInterface.dismiss()) 
      .create(); 
     dialog.setOnShowListener(dialogInterface -> { 
     Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE); 
     button.setOnClickListener(view1 -> { 
      // TODO Do something 
      //to trigger auto error enable 
      FeedEntry inputFeedEntry = dialogFeedEntryBinding.getFeedEntry(); 
      Boolean[] validations = new Boolean[]{ 
       dialogFeedEntryBinding.imageUrlValidation.isErrorEnabled(), 
       dialogFeedEntryBinding.titleValidation.isErrorEnabled(), 
       dialogFeedEntryBinding.subTitleValidation.isErrorEnabled() 
      }; 
      boolean isValid = true; 
      for (Boolean validation : validations) { 
      if (validation) { 
       isValid = false; 
      } 
      } 
      if (isValid) { 
      new AsyncTask<FeedEntry, Void, Void>() { 
       @Override 
       protected Void doInBackground(FeedEntry... feedEntries) { 
       viewModel.insert(feedEntries); 
       return null; 
       } 
      }.execute(inputFeedEntry); 
      dialogInterface.dismiss(); 
      } 
     }); 
     }); 
     dialog.show(); 

    }); 
    } 
} 
Problemi correlati