Riddhi Shah
Riddhi Shah

Reputation: 3122

How to request or remove the focus on edittext using data binding

I am learning mvvm structure and making an app using mvvm structure and data binding also.

Now, what I want to do is, I wanted to fetch a user from sharedpreference, If I am getting a user successfully then, I would set the name of usr to edittext1. In that case, I want to request focus on edittext2.

How to achieve that using databinding? (in such a way that i don't have to use activity. The job should be done using view model and xml only.)

I have tried that using following way.

StartGameViewModel

public class StartGameViewModel extends ViewModel {

    public static String TAG="StartGameViewModel";

    private Preference<User> preference;
    public ObservableField<String> player1Name=new ObservableField<>("");
    public ObservableField<String> player2Name=new ObservableField<>("");

    public ObservableBoolean shouldRequestFocus=new ObservableBoolean(false);


    StartGameViewModel(Preference preference){
        this.preference=preference;
    }

    public void getPreference() {
        preference.get(Constants.CURRENT_USER,User.class)
                .subscribe(new Observer<User>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(User user) {
                        player1Name.set(user.name);
                        shouldRequestFocus.set(true);
                    }

                    @Override
                    public void onError(Throwable e) {
                       Log.i(TAG,"user is logged out");
                    }

                    @Override
                    public void onComplete() {
                        Log.i(TAG,"Completed Preference");
                    }
                });
    }
}

activity_start_game.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"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".view.StartGameActivity">

    <data>
        <variable
            name="startGameViewModel"
            type="com.sevenbits.android.mvvmsample.viewmodel.StartGameViewModel" />
    </data>

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/splash_bg">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Enter Players Name"
            android:textSize="24sp"
            android:textColor="@color/white"
            app:layout_constraintVertical_bias="0.75"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/input_layout"
            app:layout_constraintTop_toTopOf="parent"
            />

        <LinearLayout
            android:id="@+id/input_layout"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginLeft="40dp"
            android:layout_marginRight="40dp"
            android:background="@color/white"
            android:elevation="20dp"
            android:orientation="vertical"
            android:paddingBottom="40dp"
            android:paddingLeft="20dp"
            android:paddingRight="20dp"
            android:paddingTop="40dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.45"
            tools:layout_editor_absoluteX="8dp">

            <android.support.design.widget.TextInputLayout
                android:id="@+id/til_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="10dp">

                <android.support.design.widget.TextInputEditText
                    android:id="@+id/et_player1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Player1"
                    android:text="@{startGameViewModel.player1Name}"
                    app:addTextChangedListener="@{startGameViewModel.Player1Watcher}" />

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


            <android.support.design.widget.TextInputLayout
                android:id="@+id/til_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="10dp">

                <android.support.design.widget.TextInputEditText
                    android:id="@+id/et_player2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Player2"
                    android:text="@{startGameViewModel.player2Name}"
                    app:addTextChangedListener="@{startGameViewModel.Player2Watcher}" />

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

        </LinearLayout>

        <Button
            android:id="@+id/start_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/bg_button"
            android:elevation="20dp"
            android:gravity="center"
            android:paddingBottom="20dp"
            android:paddingEnd="40dp"
            android:paddingStart="40dp"
            android:paddingTop="20dp"
            android:text="Start"
            android:textAllCaps="false"
            android:textColor="@color/white"
            android:textSize="18sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/input_layout" />

    </android.support.constraint.ConstraintLayout>
</layout>

StartGameActivity:

public class StartGameActivity extends AppCompatActivity {

    ActivityStartGameBinding activityStartGameBinding;
    StartGameViewModel startGameViewModel;

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

    private void initDataBinding() {
        activityStartGameBinding = DataBindingUtil.setContentView(this, R.layout.activity_start_game);

        StartGameViewModelFactory startGameViewModelFactory= Injection.provideStartGameViewModelFactory(this);
        startGameViewModel = ViewModelProviders.of(this,startGameViewModelFactory).get(StartGameViewModel.class);
        activityStartGameBinding.setStartGameViewModel(startGameViewModel);

        startGameViewModel.getPreference();
        if(startGameViewModel.shouldRequestFocus.get())
            findViewById(R.id.et_player2).requestFocus();
    }

    private void setStartGameListener() {
        findViewById(R.id.start_button).setOnClickListener(v -> {
            Intent intent=new Intent(StartGameActivity.this,GameActivity.class);
            intent.putExtra(Constants.PLAYER1_NAME,startGameViewModel.player1Name.get());
            intent.putExtra(Constants.PLAYER2_NAME,startGameViewModel.player2Name.get());
            startActivity(intent);
        });
    }
}

Upvotes: 9

Views: 6632

Answers (2)

hushed_voice
hushed_voice

Reputation: 3608

I know this is an old question, but I was not able to solve the issue with the current answer. Posting my answer here:

in XML:

<EditText
    android:id="@+id/email"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:elevation="@dimen/elevation15"
    app:requestFocus="@{viewmodel.focus}"/>

And in the viewModel, I had a Boolean variable declared as

val focus = true

And the binding adapter is as follows:

companion object{
    @BindingAdapter("requestFocus")
    @JvmStatic fun requestFocus(editText: EditText, requestFocus: Boolean){
        if(requestFocus){
            editText.isFocusableInTouchMode = true
            editText.requestFocus()
        }
    }
}

Basically what is happening here is, Since app:requestFocus is written inside the xml, it will invoke the binding adapter with the focus Boolean, which is given as the value for the attribute for app:requestFocus.

In my case, I didn't want to remove focus, that's why I used Boolean. If it needs to be changed, using a livedata and set the value, and update the binding adapter accordingly

Disclaimer: I am new to MVVM and Databinding, someone please correct me if I am wrong.

Upvotes: 5

Serg Burlaka
Serg Burlaka

Reputation: 2496

Very simple via binding adapter

@JvmStatic
@BindingAdapter("requestFocus")
fun requestFocus(view: TextView, requestFocus: Boolean) {
    if (requestFocus) {
        view.isFocusableInTouchMode = true
        view.requestFocus()
    }
}



             <EditText
                android:id="@+id/et_company"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:imeOptions="actionDone"
                android:inputType="textCapSentences"
                android:maxLength="32"
                android:scrollbars="vertical"

                app:requestFocus="@{company.requestFocus}" />

Upvotes: 8

Related Questions