Inflate a Viewstub that contains a Data Binding - android

I have an abstract BaseActivity class with this layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<ViewStub
android:id="#+id/activity_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
All activities in the app extends BaseActivity and overrides a method called getLayoutResID to provide its layout resource id which is inflated in the ViewStub. I do this to avoid having the Toolbar in each layout. The code in the base class that is used to inflate the layout is this:
private void setupLayout() {
setContentView(R.layout.activity_base);
ViewStub viewStub = (ViewStub) findViewById(R.id.activity_layout);
viewStub.setLayoutResource(getLayoutResID());
viewStub.inflate();
}
One of my activities use the new Data Binding system, below its layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.myapp.User" />
</data>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{user.name}" />
</layout>
Although the data binding works perfectly the problem is that the ToolBar is not visible. Any idea why the data binding engine removes/hides the toolbar in this activity?

ViewStubs requires special attention as they replace themselves when being inflated, rather than populating themselves.
Read more on data-binding/guide#viewstubs
Another solution (to avoid ViewStub altogether) is to let your ConcreteActivities include a toolbar layout in their layout - instead of inflating a stub containing the toolbar. You'll also have less headache if you ever want to use custom a toolbar for an activity.

Related

ViewBinding - How to switch/choose layout dynamically (<include>)?

I was planning on having two layout versions for the profile fragment, one for new user and one for logged in user.
How would I dynamically switch/choose the necessary layout in the Fragment's onCreateView() method?
The most straight-forward idea that comes to mind is to use two <include> layouts and hiding one of them in onCreateView() depending on variables. But I was wondering if there is a smarter approach.
Current layout xml:
The main content is inside the second FrameLayout and I'd like to have two versions to choose from.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<ImageView
android:id="#+id/profile_monk_head_imageview"
android:layout_width="match_parent"
android:layout_height="200dp"
android:contentDescription="#string/profile_monk_image_content_desc"
android:src="#drawable/monk_head" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- This is what I want to switch out -->
<FrameLayout ... >
</androidx.core.widget.NestedScrollView>
</FrameLayout>
Use DataBindingUtil version inflate if layoutId is unknown in advance ( a.k.a dynamic binding). Otherwise, use the generated Binding's inflate method to ensure type-safe inflation.
Crosslink reference

How inflate a Linear layout with custom view by databinding

I just want to make a map with some Vertical LinearLayout that in each of that have a Horizontal LinearLayout and in each of this layout wanna inflate a view that is like below code :
each_cell.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="live" type="Integer" />
<variable name="i" type="Integer" />
<variable name="j" type="Integer" />
</data>
<ImageView
android:id="#+id/itemView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
app:setI="#{i}"
app:setJ="#{j}"/>
each_row.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/row_instance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:orientation="horizontal">
</LinearLayout>
that I will add this Horizontal LL view to my main Vertical LL and the map will created
and kotlin code :
val cell = DataBindingUtil.inflate<EachCellBinding>(inflater , R.layout.each_cell , HorizontalLinearLayout.row_instance , true )
but the error is :
Required DataBindingComponent is null in class EachCellBindingImpl. A BindingAdapter in com.example.gameoflife.SartFragment.StartFragment is not static and requires an object to use, retrieved from the DataBindingComponent. If you don't use an inflation method taking a DataBindingComponent, use DataBindingUtil.setDefaultComponent or make all BindingAdapter methods static.
As shown in the error you have declared the binding adapter methods in com.example.gameoflife.SartFragment.StartFragment. Declaring it inside a class makes it non-static. But the binding adapter methods should be always static. So take the methods from inside the class and put it outside the class and it will become static and your error will be resolved.

Add custom view to LinearLayout Dynamically using data binding(MVVM)

How can custom layout be added in LinearLayout if you are using data binding?
Here is my activity layout.
I want to add multiple layouts dynamically to "layoutOptions" linearLayout.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/tools">
<data>
<variable
name="mainViewModel"
type="com.mihir.facilities.viewmodel.FacilitiesViewModel" />
</data>
<LinearLayout
android:id="#+id/layoutOptions"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"/>
</layout>
In my viewModel, I have inflated the layout I want to add, but I'm not sure how can I access "layoutOptions" linearLayout in my "FacilitiesViewModel" to call "addView" method.

Android Data Binding: Why doesn't passing in variable to ViewStubs work like include layouts?

With Android data binding it is possible to set a variable on a an included layout like so (from the documentation):
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="#layout/name"
bind:user="#{user}"/>
<include layout="#layout/contact"
bind:user="#{user}"/>
</LinearLayout>
</layout>
I've tried doing the same thing to pass in variables when using a ViewStub, but it doesn't work. Why don't ViewStubs work like include layouts?
Passing data to ViewStubs is working as expected. You define your namespace and pass the variable in that namespace, and accept it as a regular <variable> in your ViewStub layout, as follows:
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>
ViewStubs are called out as being different in the Data Binding Library documentation.
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.

Use ViewStub as generic layout in android

As I mentioned in the title, I would like to use ViewStub as a generic layout. What I mean is, currently I have my base activity class and base fragment class to be extended for other activities or fragments. So since I have generic classes, I wonder if I can have a generic layout. Is it possible?
Example layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".activities.Activity_Main">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar" />
<ViewStub
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/viewStub"
/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
Where #+id/viewStub content will change according to desired layout.
Yes, you can do that programmatically by using the setLayoutResource() method to which you pass the desired layout id.
ViewStub stub = (ViewStub) findViewById(R.id.viewStub);
stub.setLayoutResource(R.layout.some_layout);
View inflatedLayout = stub.inflate();
When inflate() is invoked, the ViewStub is replaced by the inflated View and the inflated View is returned. This lets applications get a reference to the inflated View without executing an extra findViewById().
Here is the reference.

Categories

Resources