2015-08-31 20 views
12

staram się nowy Android Wiązanie danych biblioteki (1.0-rc1) i zrobiłem obiekt użytkownika z trzech pól String (imię i nazwisko, adres e-mail, i wiek) oraz połączyłem je z 3 EditTexts w moim układzie.EditText kursor resetowania do lewej po Android Data aktualizacji powiązania

Na pierwszym polu (nazwa) umieściłem obiekt TextWatcher. Wszystko wydaje się działać dobrze. Zapobiegłem pętli notifyPropertyChanged w polu nazwy, sprawdzając, czy tekst jest inny przed zezwoleniem na wywołanie metody setName.

Problem polega na tym, że za każdym razem, gdy wpiszesz pole nazwy, kursor resetuje się po lewej stronie EditText po każdym znaku. Szukałem rozwiązania, ale większość poprawionych sugestii dotyczących problemu z kursorem mówi, aby pobrać odwołanie do EditText i ręcznie ustawić pozycję kursora. Ale chciałbym tego uniknąć, ponieważ muszę znaleźć FindByID w EditText, a celem Data Binding było uniknięcie tego. Dziękuję za pomoc.

Mój układ wygląda następująco:

<layout> 

<data> 
    <variable name="user" type="com.carlpoole.databindingstest.User"/> 
</data> 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:bind="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:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> 

    <EditText 
     android:layout_width="200dp" 
     android:layout_height="wrap_content" 
     android:id="@+id/name" 
     android:text="@{user.name}" 
     bind:addTextChangedListener="@{user.nameChanged}" 
     /> 

    <EditText 
     android:layout_width="200dp" 
     android:layout_height="wrap_content" 
     android:id="@+id/email" 
     android:layout_below="@+id/name" 
     android:text="@{user.email}"/> 

    <EditText 
     android:layout_width="200dp" 
     android:layout_height="wrap_content" 
     android:id="@+id/age" 
     android:layout_below="@+id/email" 
     android:text="@{user.age}"/> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_below="@+id/age" 
     android:text="@{user.name}"/> 

</RelativeLayout> 

Mój obiekt użytkownika wygląda następująco:

import android.databinding.BaseObservable; 
import android.databinding.Bindable; 
import android.text.Editable; 
import android.text.TextWatcher; 

public class User extends BaseObservable { 

    private String name; 
    private String email; 
    private String age; 

    public User(String name, String email, String age) { 
     this.name = name; 
     this.email = email; 
     this.age = age; 
    } 

    public User(){}; 

    @Bindable 
    public String getName() { 
     return name; 
    } 

    @Bindable 
    public String getEmail() { 
     return email; 
    } 

    @Bindable 
    public String getAge() { 
     return age; 
    } 

    public final TextWatcher nameChanged = new TextWatcher() { 
     @Override 
     public void afterTextChanged(Editable s) { 
      if(!s.toString().equalsIgnoreCase(name)) 
       setName(s.toString()); 
     } 

     @Override 
     public void beforeTextChanged(CharSequence s, int start, int count, int after) {} 

     @Override 
     public void onTextChanged(CharSequence s, int start, int before, int count) {} 
    }; 

    public void setName(String name) { 
     this.name = name; 
     notifyPropertyChanged(com.carlpoole.databindingstest.BR.name); 
    } 

    public void setEmail(String email) { 
     this.email = email; 
    } 

    public void setAge(String age) { 
     this.age = age; 
    } 
} 

Moja aktywność wygląda to

import android.databinding.DataBindingUtil; 
import android.os.Bundle; 
import android.support.v7.app.AppCompatActivity; 
import com.carlpoole.databindingstest.databinding.ActivityMainBinding; 

public class MainActivity extends AppCompatActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); 
     User user = new User("Carl Poole", "[email protected]", "26"); 
     binding.setUser(user); 

    } 
} 
+1

„I uniemożliwił notifyPropertyChanged pętli w polu Nazwa sprawdzając, czy tekst jest inny, zanim zezwolisz na wywołanie funkcji setName "- jednak, gdybym był graczem, bym był tym, co powoduje problemy z kursorem. Dlaczego masz "TextWatcher" na pierwszym miejscu? – CommonsWare

+0

@CommonsObserwuj moduł TextWatcher nasłuchujący aktualizacji w EditText, aby mógł uruchomić aktualizację do zmiennej nazwy w obiekcie User. Bez tego nie będzie wiedział.Jeśli usunę połączenie setName z metody afterTextChanged, wydaje mi się, że działa dobrze, więc wygląda na to, że problem może wynikać z tego, jak korzystam z biblioteki powiązania danych. –

+1

"Bez tego nie będzie wiadomo" - zaktualizuj model, gdy użytkownik prosi o aktualizację modelu (kliknięcie przycisku "DONE", wyjście z aktywności poprzez HOME itd.). – CommonsWare

Odpowiedz

8

Najprościej tutaj jest użycie niestandardowego @BindingAdapter, która będzie już zawierać odniesienie do EditText. W ten sposób można uniknąć ponownego wiązania, jeśli tekst w numerze EditText jest zgodny z modelem, co rozwiąże problem z kursorem.

Najpierw zmień android:text="@{user.name}" na bind:binding="@{user.name}". Następnie dodaj tę statyczną metodę w dowolnym miejscu w projekcie. Przechowujemy je wszystkie w klasie o nazwie BindingAdapters.java. Nawiasem mówiąc, zaczynając od RC2, możesz tworzyć nie statyczne metody adapterów wiążących, ale to prawdopodobnie nie jest teraz twoim największym zmartwieniem.

@BindingAdapter("binding") 
public static void bindEditText(EditText editText, CharSequence value) { 
    if (!editText.getText().toString().equals(value.toString())) { 
    editText.setText(value); 
    } 
} 
+1

Przewodnik wiązania danych nadal odnosi się do RC1. Czy RC2 już jest, czy jest nadal w użyciu? – curioustechizen

+2

RC2 nie jest jeszcze dostępny. Wkrótce w bibliotece wsparcia w Twojej okolicy. –

+0

Musiałem użyć TextWatchera, aby mieć wiązanie danych wraz z niestandardowym widokiem, i znalazłem ten sam problem. Twoje rozwiązanie działa idealnie dla mnie. Dzięki. – rajath

2

Problem jest z setter zamieszania: Twój seter, zgodnie z zaleceniami dokumentacji DataBinding, wywołuje metodę notifyPropertyChanged. Ale metoda notifyPropertyChanged, między innymi, resetuje kursor, co jest przyczyną problemu. Ich nie ma potrzeby, aby osoba ustawiająca aktualizowała interfejs użytkownika, gdy był to interfejs użytkownika (TextWatcher) wywołujący program ustawiający. Rozwiązaniem jest wtedy, aby ustawiające wywoływały tylko metodę notifyPropertyChanged, gdy niektóre obliczenia/manipulacje zaplecza powinny spowodować aktualizację interfejsu.

2

Aby rozwiązać dane dziwne zachowanie, które przywraca kursor na początku EditText wiążące, można dodać następujące InverseBindingAdapter:

@InverseBindingAdapter(attribute = "android:text") public static 
String getText(EditText view) { 

String text = view.getText().toString(); 
view.setSelection(text.length()); 

return text; 

}

+1

To wygląda jak czyste rozwiązanie –