android data binding with a custom view - android

The Android data binding guide discusses binding values within an activity or fragment, but is there a way to perform data binding with a custom view?
I would like to do something like:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mypath.MyCustomView
android:id="#+id/my_view"
android:layout_width="match_parent"
android:layout_height="40dp"/>
</LinearLayout>
with my_custom_view.xml:
<layout>
<data>
<variable
name="myViewModel"
type="com.mypath.MyViewModelObject" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{myViewModel.myText}" />
</LinearLayout>
</layout>
While it appears possible to do this by setting custom attributes on the custom view, this would quickly become cumbersome if there's a lot of values to bind.
Is there a good way to accomplish what I'm trying to do?

In your Custom View, inflate layout however you normally would and provide a setter for the attribute you want to set:
private MyCustomViewBinding mBinding;
public MyCustomView(...) {
...
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = MyCustomViewBinding.inflate(inflater);
}
public void setMyViewModel(MyViewModelObject obj) {
mBinding.setMyViewModel(obj);
}
Then in the layout you use it in:
<layout xmlns...>
<data>
<variable
name="myViewModel"
type="com.mypath.MyViewModelObject" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mypath.MyCustomView
android:id="#+id/my_view"
app:myViewModel="#{myViewModel}"
android:layout_width="match_parent"
android:layout_height="40dp"/>
</LinearLayout>
</layout>
In the above, an automatic binding attribute is created for app:myViewModel because there is a setter with the name setMyViewModel.

Data binding works even with merge only parent had to be "this" and attach to parent true.
binding = DataBindingUtil.inflate(inflater, R.layout.view_toolbar, this, true)

First, don't do this if this custom view is already being <include> in another layout, such as activity etc. You'll just get an exception about the tag being unexpected value. The data binding already ran the binding on it, so you're set.
Did you try using onFinishInflate to run the bind? (Kotlin example)
override fun onFinishInflate() {
super.onFinishInflate()
this.dataBinding = MyCustomBinding.bind(this)
}
Keep in mind that if you use the binding in your view, it won't be able to be created programmatically, at least it would be very convoluted to support both even if you can.

Following the solution presented by george the graphical editor in android studio was no longer able to render the custom view. The reason is, that no view is actually inflated in the following code:
public MyCustomView(...) {
...
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = MyCustomViewBinding.inflate(inflater);
}
I suppose that the binding handles the inflation, however the graphical editor did not like it.
In my specific use case I wanted to bind a single field and not an entire view model. I came up with (kotlin incoming):
class LikeButton #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
val layout: ConstraintLayout = LayoutInflater.from(context).inflate(R.layout.like_button, this, true) as ConstraintLayout
var numberOfLikes: Int = 0
set(value) {
field = value
layout.number_of_likes_tv.text = numberOfLikes.toString()
}
}
The like button consists of an image and a text view. The text view holds the number of likes, which I want to set via data binding.
By using the setter for numberOfLikes as an attribute in the following xml, data binding automatically makes the association:
<views.LikeButton
android:id="#+id/like_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:numberOfLikes="#{story.numberOfLikes}" />
Further reading: https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47

Today, I want to use the dataBinding on my Custom View class. But I don't know how to create data binding to my class. so I search the answer on StackOverflow.
Firstly I try the answer:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = BottomBarItemCustomViewBinding.inflate(inflater);
but, I found this is not working for my code
so I change another method:
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = DataBindingUtil.inflate(inflater, R.layout.bottom_bar_item_custom_view, this, true);
It's working for me.
the complete code is:
bottom_bar_item_custom_view.xml
<data>
<variable
name="contentText"
type="String" />
<variable
name="iconResource"
type="int" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<ImageView
android:id="#+id/bottomBarItemIconIv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="2dp"
android:src="#{iconResource}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/bottomBarItemContentTv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="#{contentText}"
android:textColor="#color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/bottomBarItemIconIv" />
</androidx.constraintlayout.widget.ConstraintLayout>
BottomBarItemCustomView.java
public class BottomBarItemCustomView extends ConstraintLayout {
public BottomBarItemCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
//use dataBinding on custom view.
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
BottomBarItemCustomViewBinding binding = DataBindingUtil.inflate(inflater, R.layout.bottom_bar_item_custom_view, this, true);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BottomBarItemCustomView);
int iconResourceId = typedArray.getResourceId(R.styleable.BottomBarItemCustomView_bottomBarIconResource, R.drawable.my_account_icon);
binding.setIconResource(iconResourceId);
String contentString = typedArray.getString(R.styleable.BottomBarItemCustomView_bottomBarContentText);
if (contentString != null) {
binding.setContentText(contentString);
}
typedArray.recycle();
}
hope is useful for you!

In Kotlin we can directly use ViewBinding:
class BenefitView(context: Context, attrs: AttributeSet) : ConstraintLayout(context, attrs) {
init {
val binding = BenefitViewBinding.inflate(LayoutInflater.from(context), this, true)
val attributes = context.obtainStyledAttributes(attrs, R.styleable.BenefitView)
binding.image.setImageDrawable(attributes.getDrawable(R.styleable.BenefitView_image))
binding.caption.text = attributes.getString(R.styleable.BenefitView_text)
attributes.recycle()
}
}

There are some good answers on here already, but I wanted to offer what I believe to be the simplest.
Create your custom control with the layout tags surrounding it, just like any other layout. See the following toolbar for example. this gets used in each of the activity classes
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="YACustomPrefs" type="com.appstudio35.yourappstudio.models.YACustomPreference" />
</data>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/YATheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
app:popupTheme="#style/YATheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
Now this custom layout is a child of every Activity. You simply treat it as such in the onCreate binding setup.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.yaCustomPrefs = YACustomPreference.getInstance(this)
binding.toolbarMain?.yaCustomPrefs = YACustomPreference.getInstance(this)
binding.navHeader?.yaCustomPrefs = YACustomPreference.getInstance(this)
binding.activity = this
binding.iBindingRecyclerView = this
binding.navHeader?.activity = this
//local pointer for notify txt badge
txtNotificationCountBadge = txtNotificationCount
//setup notify if returned from background so we can refresh the drawer items
AppLifeCycleTracker.getInstance().addAppToForegroundListener(this)
setupFilterableCategories()
setupNavigationDrawer()
}
Notice I set the children's content at the same time I do the parent and it is all done through dot notation access. As long as the files are surrounded with layout tags and you named them, it is simple to do.
Now if the custom class has it's own associated code inflation, then it can easily just do it's own binding in it's onCreate or constructor, but you get the picture. If you have your own class just throw the following in the constructor to match it's named binding class. It follows the name convention of the layout file pascal cased, so it's easy to find and auto fill.
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mBinding = NameOfCustomControlBinding.inflate(inflater);
Hope that helps.

I faced the same issue when I am trying to add a child views to a LinearLayout inside my host fragment(Nested fragment UI/UX)
here is my solution
var binding: LayoutAddGatewayBinding? = null
binding = DataBindingUtil.inflate(layoutInflater, R.layout.layout_add_gateway,
mBinding?.root as ViewGroup?, false)
binding?.lifecycleOwner=this
val nameLiveData = MutableLiveData<String>()
nameLiveData.value="INTIAL VALUE"
binding?.text=nameLiveData
Here mBinding is child fragment ViewDataBinding object and I have used nameLiveData for two-way databinding

Related

ViewBinding reports "missing view with id "error when trying to bind a custom view

I have a custom view. In onFinishInflate() I bind the view.
class CreatePlaylistButton(context: Context, attributeSet: AttributeSet) :
ViewGroup(context, attributeSet) {
private lateinit var binding: ButtonCreatePlaylistBinding
.....
......
override fun onFinishInflate() {
super.onFinishInflate()
binding = ButtonCreatePlaylistBinding.bind(this)
}
The layout is simple. See snippet below
<com.tendai.musicx.ui.discover.customviews.CreatePlaylistButton xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:clickable="true"
android:focusable="true">
<TextView
android:id="#+id/textview_create_playlist"
style="#style/TextAppearance.AppCompat.Caption"
.....
...
android:clickable="false"
/>
<ImageView
android:id="#+id/imageViewCreatePlaylist"
......
.....
android:src="#drawable/ic_add" />
</com.tendai.musicx.ui.discover.customviews.CreatePlaylistButton>
I use the custom view in a fragment's layout like so:
<androidx.constraintlayout.widget.ConstraintLayout />
.....
....
<com.tendai.musicx.ui.discover.customviews.CreatePlaylistButton
android:id="#+id/button_create_playlist"
........
/>
When I try to run the app I get the error Missing required view with ID: packageName/imageViewCreatePlaylist but the ImageView is there? What I am missing?
Your layout in first file has ImageView with the id nested in CreatePlaylistButton.
In fragment layout you're just using plain CreatePlaylistButton which is essentially a ViewGroup without any children, so the view is not there - hence the error.
To get what you're trying to do, you need to replace CreatePlaylistButton in first layout with e.g. LinearLayout and then inflate it inside the CreatePlaylistButton class.

Android custom expandable/collapsable view with child elements

I am working on a custom expandable view in android.
The goal is that I can add child elements in the xml files and they will be expanded and collapsed when the user clicks the expand/collapse button as on the picture below.
The expananding/collapsing works fine, but I cannot find out how to handle the child views.
In the constructor of my custom view, I inflate an xml layout, and I have a linear layout inside, in which i would like to put the child elements.
I tried using the solution suggested in the answer to the question here.
But I get StackOverflowError, and about a hundres of these:
"at android.view.ViewGroup.resetResolvedLayoutDirection(ViewGroup.java:7207)", even if I try to use the solution in the second aswer, using a while loop instead of the for.
Here is the kotlin class of my view:
class CollapsableCategoryView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
/** Declare some variables */
private var titleString : String = ""
private var subtitleString : String = ""
private var isExpaneded : Boolean = false
/** The required views */
private lateinit var ivIcon : ImageView
private lateinit var llExpandableContent : LinearLayout
init {
/** Receive the attributes */
context.theme.obtainStyledAttributes(
attrs,
R.styleable.CollapsableCategoryView,
0, 0
).apply {
try {
titleString = getString(R.styleable.CollapsableCategoryView_categoryTitle) ?: ""
subtitleString = getString(R.styleable.CollapsableCategoryView_categorySubtitle) ?: ""
} finally {
recycle()
}
}
/** Inflate the layout */
val root : View = View.inflate(context, R.layout.collapsable_task_category, this)
/** Find the views we need*/
ivIcon = root.findViewById(R.id.ivCollapsableCategoryIcon) as ImageView
llExpandableContent = root.findViewById(R.id.llExpandableContent) as LinearLayout
/** onClickListener for the icon */
ivIcon.setOnClickListener {
toggleExpanded()
}
}
override fun onFinishInflate() {
for(i in 0..childCount){
var view : View = getChildAt(i)
removeViewAt(i)
llExpandableContent.addView(view)
}
super.onFinishInflate()
}
/** This method is called when user clicks the expand/collapse button */
fun toggleExpanded(){
isExpaneded = !isExpaneded
if(isExpaneded)
{
ivIcon.setImageResource(R.drawable.ic_collapse)
llExpandableContent.visibility = VISIBLE
}else{
ivIcon.setImageResource(R.drawable.ic_expand)
llExpandableContent.visibility = GONE
}
}
}
I read somewhere else about a different solution, which also doesn't work. That solution suggests to ovverride the addView() method something like this:
override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
llExpandableContent.addView(child, params)
}
But if I do so, I get an exception that the lateinint var llExpandableContent is never initialized.
I have also seen solutions that override onMeasure() method but that doesn't seem to be the right approach for me to this problem, since I don't wan't to lay my views out in a special way, just want to add them in a linear layout.
Here is the xml resource file for the layout of the custom view:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="#dimen/collapsable_category_corner_radius"
android:background="#drawable/bg_collapsable_category_top"/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/clCollapsableCategoryMain"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/bg_collapsable_category_middle">
<ImageView
android:id="#+id/ivCollapsableCategoryIcon"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_marginStart="8dp"
android:src="#drawable/ic_expand"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/clCollapsableCategoryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Title"
app:layout_constraintStart_toEndOf="#+id/ivCollapsableCategoryIcon"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/clCollapsableCategorySubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Subtitle"
app:layout_constraintStart_toEndOf="#+id/ivCollapsableCategoryIcon"
app:layout_constraintTop_toBottomOf="#+id/clCollapsableCategoryTitle" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="#+id/llExpandableContent"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#drawable/bg_collapsable_category_middle"
android:visibility="gone">
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="#dimen/collapsable_category_corner_radius"
android:background="#drawable/bg_collapsable_category_bottom"/>
</LinearLayout>
And here is how I am trying to use my custom view in a layout xml file:
<com.test.test.util.CollapsableCategoryView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Child view 1"/>
</com.test.test.util.CollapsableCategoryView>
Does anyone know how to solve this problem?
Thank you very much in advance for any help. Best regards,
Agoston
So I found the solution at another question, which I cannot find again...
But this solution works like a charm :)
override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
if(llExpandableContent == null){
super.addView(child, index, params)
}else{
llExpandableContent?.addView(child, index, params)
}
}
Hope it will help someone else at some point :)

NPE Crash in databinding when change the hierarchy of customView

import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
class MyCustomView #JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null) : FrameLayout(
context,
attributeSet
) {
val binding = MylayoutBinding.inflate(
LayoutInflater.from(context),
this,
true
)
}
// mylayout.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<merge>
<FrameLayout
android:id="#+id/myChildContainer"
android:layout_width="100dp"
android:layout_height="100dp"/>
</merge>
</layout>
I am using my custom view in the form below.
// myactivity.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout android:layout_width="match_parent" android:layout_height="match_parent">
<MyCustomView
android:id="#+id/myView"
android:layout_width="300dp"
android:layout_height="300dp">
<Button
android:id="#+id/myButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</MyCustomView>
</FrameLayout>
</layout>
In the example above, I want myButton to go into MyCustomView as a child of myChildContainer.
I followed the example from android: how to add children from an xml layout into a custom view and modified MyCustomView as below.
class MyCustomView #JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null) : FrameLayout(
context,
attributeSet
) {
val binding = MylayoutBinding.inflate(
LayoutInflater.from(context),
this,
true
)
override fun onFinishInflate() {
super.onFinishInflate()
while (childCount > 1) {
val child = getChildAt(1)
val param = child.layoutParams
removeView(child)
binding.myChildContainer.addView(child, param)
}
}
}
This code is fine if I don't apply data binding.
The problem is app has crashed when I apply data binding.
internal class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<MyactivityBinding>(this, R.layout.myactivity)
binding.myButton.text = "Test Text" <-- crash
}
}
Caused by: java.lang.NullPointerException: binding.myButton must not be null
When I change the execution point of remove view and addview of my code from onFinishInflate to onAttachedToWindow, the error generally does not occur, but I have confirmed that it recurs intermittently, so I think this is not a solution.
Is there any way to add Child View to CustomView while keeping DataBinding?
I actually use multiple such views, so I don't want to call individual functions like myView.sortView() after setContentView.

Passing a different ViewModel to an include layout

I'm including a layout passing a viewmodel:
<include
layout="#layout/user_login"
app:model="#{model}" />
My goal is to use this include in different places passing a different ViewModel too.
For example I would like to pass: UserViewModel in one place, in another place InformationViewModel.
Can I do that?
Thanks in advance
Here is the component class
class SomeComponent(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs) {
private var mBinding: SomeLayoutBinding? = null
init {
if (isInEditMode) {
val view = LayoutInflater.from(context).inflate(R.layout.some_layout, this, false)
addView(view)
} else {
mBinding = SomeLayoutBinding.inflate(LayoutInflater.from(context), this, true)
}
}
fun setVm(vm: InformationViewModel) {
mBinding!!.vm = vm
mBinding!!.executePendingBindings()
}
}
Here is the layout for component
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="vm"
type="yourpackage.InformationViewModel" />
</data>
</layout>
Here is the way how you set vm
<yourpackage.SomeComponent
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:vm="#{item}" />

Enabling the `onClick` method in a custom FrameLayout view

I'm not able to get a onClick method to work with a custom FrameLayout view.
When I refactor a default Button view into a custom ProgressButton view containing a Button, the onClick method doesn't get called.
Custom ProgressButton view class:
class ProgressButton #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
defStyleRes: Int = 0
) : FrameLayout(context, attrs, defStyle, defStyleRes){
private var button: Button
init {
val view = LayoutInflater.from(context).inflate(R.layout.view_progress_button, this, true)
button = view.findViewById(R.id.button)
context.theme.obtainStyledAttributes(
attrs,
R.styleable.ProgressButton,
0, 0
).apply {
try {
if (hasValue(R.styleable.ProgressButton_buttonText)) {
button.text = getString(R.styleable.ProgressButton_buttonText)
}
if (hasValue(R.styleable.ProgressButton_buttonBackground)) {
button.background = getDrawable(R.styleable.ProgressButton_buttonBackground)
}
} finally {
recycle()
}
}
}
}
ProgressButton XML Layout file: res/layout/view_progress_button.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</FrameLayout>
Usage of ProgressButton view with android:onClick:
<com.example.ui.common.ProgressButton
android:id="#+id/progress_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{() -> viewModel.onProgressButtonClick()}"
app:buttonText="#string/test"
app:buttonBackground="#drawable/selectable_button_blue"
/>
What's the best way to pass a click listener to a custom view using Android databinding?
Assuming that you have dataBinding.enabled true defined in your build.gradle. If not, check this out.
It doesn't look like your layout is currently a databinding layout. First you'd want to convert view_progress_button.xml to a databinding layout like the following:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.your.package.YourViewModelClass" />
</data>
<FrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.ui.common.ProgressButton
android:id="#+id/progress_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="#{() -> viewModel.onProgressButtonClick()}"
app:buttonText="#string/test"
app:buttonBackground="#drawable/selectable_button_blue"
/>
</FrameLayout>
There should be an option in Android Studio that lets you auto-convert your layout. Do this by hitting alt + enter (Windows) or option + enter (OSX) on the root ViewGroup in your layout. In this case you'd want to hit that combination on your FrameLayout.
In your ProgressButton class, you'd want to do something like this:
val binding: ViewProgressButtonBinding = DataBindingUtil.inflate(getLayoutInflater(), R.layout.view_progress_button, null, false);
instead of:
val view = LayoutInflater.from(context).inflate(R.layout.view_progress_button, this, true)
Using the binding object, you can do:
binding.setViewModel(yourViewModelInstance)
You can instantiate your ViewModel however, but inside your ViewModel class you should have onProgressButtonClick() defined.
If I remember correctly, you might need to do something like this in your layout for the onClick:
android:onClick="#{(v) -> viewModel.onProgressButtonClick()}"
because the lambda expects the view as a parameter.
Another note is that you no longer need to do findViewById since you have access to that view like so:
binding.button

Categories

Resources