this is some code in my parent 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"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="(..).viewmodels.TestViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:theme="#style/AppTheme.AppBarOverlay"
>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<include
android:id="#+id/layout"
bind:viewModel="#{viewModel}"
layout="#layout/test_content"/>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Here's the child include layout
<layout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="(..).TestViewModel" />
</data>
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
tools:layout_editor_absoluteX="74dp"
tools:layout_editor_absoluteY="1dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/disable"
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/orange"
android:text="#{viewModel.buttonText}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</layout>
As you can see in this example I data binded text to the viewmodel and passed it down from parent to child via bind:viewModel="#{viewModel}"
Here's the code in the activity:
val binding:TestContentBinding = DataBindingUtil.setContentView(this, R.layout.test_content)
binding.setLifecycleOwner(this)
binding.viewModel = testViewModel
If I set the binding to the child xml then the data gets binded, however if i set the binding to the parent activity the viewmodel doesn't get passed down.
The back end certainly has the correct data however I don't know how to bind data to the child.
I've even tried manually setting the layout's viewModel however that doesn't work. How do I pass the viewmodel?
You could try changing the name of the variable in your included layout.
Here is a quick article explaining how to use include layout with ViewModel.
Related
I´m trying to create a include to use as a default recyclerview to reuse in all my views, the code is this:
<?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">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.jsm.baserecycler.BaseRecyclerViewModel" />
<variable
name="listItemResource"
type="android.widget.LinearLayout" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:onRefreshListener="#{() -> viewModel.onRefresh()}"
app:refreshing="#{viewModel.isLoading}">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/elementsRV"
style="#style/RecyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#{listItemResource}">
</androidx.recyclerview.widget.RecyclerView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<TextView
android:id="#+id/empty"
style="#style/TextViewNoItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/default_recyclerview_emptyMessage"
android:visibility="#{viewModel.textEmptyVisibility ? View.VISIBLE : View.GONE}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
My goal is to pass a variable to the include which can configure the tools:listItem of the recycler inside the include
I tried to find which type I need to put in listItemResource to use the variable in
tools:listitem
I tried several types as Integer, Viewgroup... but always receive a error of type:
{"msg":"Cannot find a setter for \u003candroidx.recyclerview.widget.RecyclerView tools:listitem\u003e that accepts parameter type...
Which type I need to put on ????....
<variable
name="listItemResource"
type="????" />
...To do:
tools:listitem="#{listItemResource}
?
Update: As ADM pointed in comments and I researched, my approach is wrong, I guess the solution is to create a CompoundView that accepts that parameter
I am trying to delay inflating some views in a large fragment to avoid a freeze.
in fragment.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="vm"
type="exm.ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- some other views -->
<ViewStub
android:id="#+id/fragment_stub"
android:inflatedId="#+id/fragment_content"
android:layout="#layout/fragment_stub_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:vm="#{vm}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
fragment_stub_content.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">
<data>
<variable
name="vm"
type="exm.ViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ACustomView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{()->vm.toggleDetails()}"
app:isExpanded="#{vm.canShowDetails}"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Function toggleDetails in vm toggles boolean livedata canShowDetails. I can see that this function is successfully called by a log. But canShowDetails (A MutableLiveData<Boolean>) does not change despite being observed in a view. A trivial code would be fragment_stub?.inflate() in my Fragment's onViewCreated() which is called successfully.
I have a fragment called PostsFragment which is used on two places.
HomeActivity
PostActivity
In the HomeActivity, I am attaching PostsFragment and everything is going well, but, In the second activity PostActivity, I have in the top some components -post details- and below them, there is FragmentContainerView where I want to attach it again, -I want to display the related posts-.
The PostActivity parent's view is NestedScrollView.
when I set nestedScrollingEnabled to true inside PostsFragment the scrollbar only works on the recyclerView but I want to make the whole view in PostActivity scrollable, which doesn't work if I set nestedScrollingEnabled to false.
I did lots of searches and nothing works.
Edit 1:
Here is the code of PostActivity
<?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">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.trade.scope.ui.project.ProjectViewModel" />
</data>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:overScrollMode="never"
app:layout_behavior="android.support.design.widget.AppBarLayout$ScrollingViewBehavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.project.ProjectActivity">
<com.trade.scope.ui.custom.ViewPagerPauseAble
android:id="#+id/image_view_banner"
android:layout_width="match_parent"
android:layout_height="256dp"
android:layout_marginHorizontal="16dp"
app:layout_collapseMode="parallax"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/text_view_title_"
style="#style/Auth.Sub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="18dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="18dp"
android:fontFamily="#font/muller_bold"
android:text="#string/project_request"
android:textColor="#color/dark_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/image_view_banner" />
<FrameLayout
android:id="#+id/divider"
android:layout_width="0dp"
android:layout_height="2dp"
android:layout_marginTop="8dp"
android:background="#drawable/primary_line"
app:layout_constraintStart_toStartOf="#+id/text_view_title_"
app:layout_constraintTop_toBottomOf="#+id/text_view_title_"
app:layout_constraintWidth_percent="0.4" />
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragment_container_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
app:layout_constraintTop_toBottomOf="#+id/divider" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</layout>
The code of PostsFragment
<?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">
<data>
<variable
name="viewModel"
type="com.trade.scope.ui.projects.ProjectsViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/view_holder_project" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
You're building a complex view, I can recommend CoordinatorLayout with AppBarLayout and CollapsingToolbarLayout and don't miss the app:layout_behavior="#string/appbar_scrolling_view_behavior"
You have 2 options:
Put nestedScrollingEnabled programally like this:
yourRecyclerView.isNestedScrollingEnabled = false
Put into your recyclerview in xml file
android:nestedScrollingEnabled="false"
Hope it's help you
You have not posted your code so I am assuming this might be the case. You have to set the nestedScrollingEnabled to false for recyclerview not for NestedScrollView
I am using concept of Databinding-mvvm to implement such things. I have declared recyclerview into the my mainactivity. like
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View"/>
<variable
name="ffvm"
type="com.example.the_king.apartmentmanagementsystem.ViewModal.
FragmentViewModal.ViewModal"/>
</data>
<FrameLayout 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"
tools:context="com.example.the_king.apartmentmanagementsystem.
Fragment.Fragment_FlatHolder">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</FrameLayout>
</layout>
my cardview is look like
<layout>
<data>
<import type="android.view.View"/>
<variable
name="cfhvm"
type="com.example.the_king.apartmentmanagementsystem.ViewModal.
CardViewModel.CardViewModal"/>
</data>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.example.the_king.apartmentmanagementsystem.
CardView.CardViewFlatHolder"
layout_width="match_parent"
android:background="#color/colorPrimaryLight"
android:elevation="25dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:innerRadius="15dp"
android:thicknessRatio="1.9"
layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{cfhvm.firstname+` `+cfhvm.lastname}"
android:layout_marginLeft="5dp"
android:textSize="#dimen/text_title"
/>
</android.support.v7.widget.CardView>
</layout>
for the cardview i have created viewmodel as cardviewmodal and for Recyclerview i have created viewmodel and i have also created adapter to fill data now i got confuse how do i set value of recyclerview from the viewmodel which contains cardviewmodel.
I'm trying to use databinding without any binding data to widgets such as TextViews on main layout but i get this error when i run application:
Only one layout element and one data element are allowed
Main layout:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:slidingLayer="http://schemas.android.com/apk/res-auto">
<data>
</data>
<variable
name="presenter"
type="com.example.Ui.Register.Presenter.ActivityRegisterPresenter"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d1d1d1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/permission_for_read_contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="#string/permission_for_read_contacts"
android:textColor="#color/white"/>
<TextView
android:layout_width="match_parent"
android:layout_height="#dimen/default_textview_height"
android:text="#string/get_read_contact_permission"
android:background="#drawable/selector_blue_buttons"
android:clickable="#{()->presenter.getReadContactsPermission()}"
android:textColor="#color/white"/>
</LinearLayout>
<TextView
android:id="#+id/activity_register_view_port"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
</FrameLayout>
</layout>
in this activity i don't have any binding by default such as setText, after removing this line:
<variable
name="presenter"
type="com.example.Ui.Register.Presenter.ActivityRegisterPresenter"/>
problem resolved!!
public class ActivityRegisterPresenter {
private ActivityRegisterContract.View view;
public ActivityRegisterPresenter(ActivityRegisterContract.View mView) {
view = mView;
}
public void getReadContactsPermission(){
view.getReadContactsPermission();
}
}
You need to write variable tag within data tag as follows :
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:slidingLayer="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="presenter"
type="com.example.Ui.Register.Presenter.ActivityRegisterPresenter"/>
</data>
...
</layout>
Your <variable> element needs to be inside the <data> element.
E.g.:
<data>
<variable
name="presenter"
type="com.example.Ui.Register.Presenter.ActivityRegisterPresenter"/>
</data>