How to dynamically change view visibility using an

2020-03-13 08:40发布

问题:

I'm trying to achieve one simple view hide/show using data binding. I have an api call and I have to show one progressbar while the api call is going on. Once I get the response have to dismiss this progress and display the data. I tried to change the visibility of progressbar dynamically using data binding. But nothing happens. Only for the first time the progresbar visibility is set according to the binding variable. its not dynamically updating as I update the binding variable.

following is my sample code for the same

Activity:

public class MainActivity extends AppCompatActivity {

private static final String TAG = MainActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
    final ViewModel viewmodel = new ViewModel();
    binding.setViewmodel(viewmodel);

    findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            loadData(viewmodel);
        }
    });
}

private void loadData(final ViewModel viewmodel) {
    viewmodel.setLoading(true);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "Loading finished");
            viewmodel.setLoading(false);
        }
    }, 2000);
}
}

ViewModel:

import android.databinding.BaseObservable;
import android.databinding.Bindable;

public class ViewModel extends BaseObservable {

private boolean isLoading;
private String data;


@Bindable
public String getData() {
    return data;
}

public void setData(String data) {
    this.data = data;
}

@Bindable
public boolean isLoading() {
    return isLoading;
}

public void setLoading(boolean loading) {
    isLoading = loading;
 }
} 

activity_main.xml

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

<data>
    <import type="android.view.View"/>
    <variable name="viewmodel" type="com.test.databindnig.ViewModel"/>
</data>
<LinearLayout
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.test.databindnig.MainActivity">

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="@{viewmodel.isLoading ? View.VISIBLE : View.GONE}"/>
    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{viewmodel.data}"
        android:visibility="@{viewmodel.isLoading ? View.GONE : View.VISIBLE}"/>


    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Load data"/>
</LinearLayout>
</layout>

and also in the app's build.gradle

dataBinding {
    enabled = true
}

What is missing over here? why doesn't it work? Thanks in advance..

回答1:

you need to notify that your property value is changed, try this

public void setLoading(boolean loading) {
    isLoading = loading;
    notifyPropertyChanged(BR._all);
}

or if you want to notify it just for single variable, use BR.propertyName

notifyPropertyChanged(BR.loading);


回答2:

I want to clarify that if you use notifyPropertyChanged(BR._all);, it will notify all observables unnecessarily.

You should use notifyPropertyChanged(BR.field); instead to notify only changed item.

If you want model.setLoading(true). It will refract on related views from this field.

Note that your accessor should be annotated with @Bindable attribute. Otherwise BR class will not have your field name.

@Bindable
public boolean isLoading() {
    return isLoading;
}

public void setLoading(boolean isLoading ) {
    this.isLoading = isLoading ;
    notifyPropertyChanged(BR.isLoading );
}


回答3:

add <import type="android.view.View" /> on top of your XMl file result solution will be like following

<data>
    <import type="android.view.View" />
    <variable
        name="obj"
        type="com.you.modal.class" />
</data>


 <import type="android.view.View" />