Привязка данных и выбор в TextInputEditText
У меня проблема с правильной привязкой данных свойства выбора TextInputEditText.
Вот это 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>
<variable name="inputViewModel" type="com.example.ui.TextInputViewModel"/>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputLayout
android:id="@+id/layoutInput"
android:hint="@{inputViewModel.hint}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:errorEnabled="@{!inputViewModel.valid}"
app:error="@{inputViewModel.errorMessage}">
<android.support.design.widget.TextInputEditText
android:id="@+id/editInput"
android:text="@={inputViewModel.value}"
android:inputType="@{inputViewModel.inputType}"
android:maxLines="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:selection="@{inputViewModel.selection}"
app:setOnFocusChangeListener="@{inputViewModel.onFocusChangeListener}"
app:addTextChangedListener="@{inputViewModel.watcher}" />
</android.support.design.widget.TextInputLayout>
</FrameLayout>
</layout>
И классы MVVM:
@Getter
@Setter
public class InputModel {
private String value;
private String errorMessage;
private boolean valid;
private String hint;
private int inputType;
private int selection;
}
public abstract class BaseInputViewModel extends BaseObservable{
protected InputModel mInputModel;
public BaseInputViewModel(InputModel inputModel){
this.mInputModel = inputModel;
}
}
public class TextInputViewModel extends BaseInputViewModel {
public TextInputViewModel() {
setWatcher(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d("TextInputViewModel","getSelection1: " + getSelection());
}
@Override
public void onTextChanged(CharSequence value, int start, int before, int count) {
Log.d("TextInputViewModel","getSelection2: " + getSelection());
}
@Override
public void afterTextChanged(Editable s) {
Log.d("TextInputViewModel","getSelection3: " + getSelection());
}
});
}
@Bindable
public int getSelection() {
return mInputModel.getSelection();
}
@Bindable
public TextWatcher getWatcher() {
return watcher;
}
public void setWatcher(TextWatcher watcher) {
this.watcher = watcher;
notifyPropertyChanged(BR.watcher);
}
}
}
public class TextInputVie extends FrameLayout {
public TextInputVie(Context context) {
super(context);
initView(context, null);
}
public TextInputVie(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
void initView(@NonNull Context context, @Nullable AttributeSet attrs) {
mViewModel = createViewModel();
ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.text_input_layout, this, true);
binding.setVariable(BR.inputViewModel, mViewModel);
}
}
К сожалению читаю getSelection()
всегда возвращает 0, где курсор находится в поле редактирования. С другой стороны, если я нарушу правило разделения и использую что-то вроде view.getSelectionStart()
Я получаю правильный результат. Но это скорее подход MVC/MVP. Кто-нибудь есть какие-либо идеи о том, как связать свойство выбора, чтобы получить текущую позицию курсора с помощью привязки данных?
1 ответ
Использование Kotlin & двухстороннего связывания данных
Создайте адаптер для установки положения курсора, как описано:
@BindingAdapter("app:cursorPosition")
fun setCursorSelection(view:TextInputEditText, flag:Boolean) {
if (flag && view.text?.toString()?.length > 0) view.setSelection(view.text.toString().length)
}
Используйте его в своем xml следующим образом, передавая индикатор, если вы хотите, чтобы адаптер устанавливал положение курсора или нет:
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/space_large"
android:layout_marginRight="@dimen/space_large"
android:layout_marginTop="@dimen/space_large"
android:hint="@string/enter_username"
app:errorText="@{(loginData.userNameErrorEnable && loginData.name != null && loginData.name.length() > 0 ) ? loginData.userNameError : null}"
style="@style/MaterialEditText"
app:layout_constraintTop_toBottomOf="@+id/headerImage">
<android.support.design.widget.TextInputEditText
android:id="@+id/usernameET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={loginData.name}"
app:clearTextChangeListener="@{loginData.userNameWatcher}"
app:cursorPosition="@{loginData.name != null}" />
</android.support.design.widget.TextInputLayout>