问题
Is there anyway to use viewStubs with dataBinding ? can ViewStubProxy help ?
My stub current looks like this:
<ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="@{myobject.bottom ? bottom:top}" />
But this layout will be replaced when i inflate the viewStub so how can ViewStubs be used with android dataBinding ?
this is what i see from the docs:
ViewStubs
ViewStubs are a little different from normal Views. They start off invisible and when they either are made visible or are explicitly told to inflate, they replace themselves in the layout by inflating another layout.
Because the ViewStub essentially disappears from the View hierarchy, the View in the binding object must also disappear to allow collection. Because the Views are final, a ViewStubProxy object takes the place of the ViewStub, giving the developer access to the ViewStub when it exists and also access to the inflated View hierarchy when the ViewStub has been inflated.
When inflating another layout, a binding must be established for the new layout. Therefore, the ViewStubProxy must listen to the ViewStub's ViewStub.OnInflateListener and establish the binding at that time. Since only one can exist, the ViewStubProxy allows the developer to set an OnInflateListener on it that it will call after establishing the binding.
回答1:
Just set the listener as the doc says :
mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
ViewStubBinding binding = DataBindingUtil.bind(inflated);
binding.setModel(model);
}
});
public void inflateViewStub(View view) {
if (!mBinding.viewStub.isInflated()) {
mBinding.viewStub.getViewStub().inflate();
}
}
回答2:
Declare your xml namespace, and pass the variable through that. This works with <include>
, too, btw. Here's an example:
main_layout.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:my-namespace="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myData" type="com.example.SomeModel" />
</data>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ViewStub
android:id="@+id/view_stub"
android:inflatedId="@+id/view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/another_layout"
my-namespace:data="@{myData}"
/>
</RelativeLayout>
</layout>
another_layout.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<!-- No need to declare my-namespace here -->
<data>
<variable name="data" type="com.example.SomeModel" />
</data>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.someValue}" />
</RelativeLayout>
</layout>
So now you just have to call inflate()
and the layout will have the data.
You can check the generated binding class to verify this. It even has type safety, so you can't pass any other type into data
.
回答3:
I Also faced This Type of Issues, finally I got a solution and Its Perfectly Working.
ViewStub Holding Layout,,
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data class="MBinding">
<variable
name="mmmmm"
type="com.vvv.bbb.fragments.MFragment" />
</data>
--------------------
--------------------
<ViewStub
android:id="@+id/stub_import"
-------------------
-------------------
<ViewStub/>
--------------------
--------------------
<layout/>
layout Inside ViewStub is,,,
<?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 class="MViewStubLayoutBinding">
<variable
name="mmmmm"
type="com.vvv.bbb.fragments.MFragment" />
</data>
----------------
----------------
----------------
code Inside the Class is,,,
public Class KKKKKK() {
-----------------
MBinding mBinding;
MViewStubLayoutBinding mviewStubLayoutBinding;
-----------------------------
-----------------------------
mBinding.stubImport.getViewStub().setLayoutResource(R.layout.progress_overlay);
mBinding.stubImport.setOnInflateListener(new ViewStub.OnInflateListener() {
@Override
public void onInflate(ViewStub viewStub, View view) {
mviewStubLayoutBinding=DataBindingUtil.bind(view);
}
});
autoCheckBinding.vsAutoDetailsOne.getViewStub().inflate();
回答4:
Just to elaborate on @andrew-classen's accepted answer above, and include the @user9113597's answer as well:
In your layout that contains the stub (e.g. my_fragment.xml)
<data class="MyDataBinding">
...
</data>
...
<ViewStub
android:id="@+id/stub_import"
... />
In your activity or fragment (example below is using a fragment):
MyDataBinding mBinding;
MyViewModel mViewModel;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
mBinding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false);
mBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener()
{
@Override
public void onInflate(ViewStub stub, View inflated)
{
ViewDataBinding dataBinding = DataBindingUtil.bind(inflated);
binding.setVariable(BR.mViewModel, mViewModel));
}
});
}
public void inflateViewStub(View view) {
if (!mBinding.viewStub.isInflated()) {
mBinding.viewStub.getViewStub().inflate();
}
}
In your stub layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="mViewModel"
type="com.example.myapp.MyViewModel" />
</data>
...
回答5:
Set the listener to get access to inflated layout after successful inflating of viewStub
mBinding.viewStub.setOnInflateListener(new OnInflateListener() {
@Override
public void onInflate(ViewStub stub, View inflated) {
ViewStubBinding binding = DataBindingUtil.bind(inflated); //call after succesful inflating of viewStub
// set data here
}
});
Then inflate your viewStub
mBinding.viewStub.getViewStub().inflate();
回答6:
Another way I did this was using the ViewStubProxy. The documentation/source code for ViewStubProxy is good.
When you create your new ViewStubProxy, pass in your ViewStub in the constructor. Then ViewStubProxy.setContainingBinding(<pass in your root layout binding)
. If you don't do this you'll get nulls.
Then instead of setting the ViewStub.setOnInflateListener (the ViewStubProxy will set one internally for you), set the ViewStubProxy.setOnInflateListener to set your binding variables and LifecycleOwner.
Sample code:
private void setBindings(){
//usual outside layout binding steps
binding = (MeasurementsLayoutBinding) getBinding();
binding.setViewModel(viewModel());
binding.setLifecycleOwner(this);
//cartSideStubView is the root layout stubview
cartViewStubProxy = new ViewStubProxy(cartSideStubView);
cartViewStubProxy.setContainingBinding(binding);
cartViewStubProxy.setOnInflateListener(((viewStub, view) -> {
cartViewStubProxy.getBinding().setVariable(BR.viewModel, viewModel());
cartViewStubProxy.getBinding().setLifecycleOwner(this);
//after inflation you can find your viewstub views
cartHitchToFixedAxleInputField = view.findViewById(R.id.cart_hitch_to_fixed_axle_input_field);
}));
}
来源:https://stackoverflow.com/questions/34712952/android-data-binding-how-to-use-viewstub-with-data-binding