How to use Two-way data binding in android (kotlin) - android

I need to enable my Button after check some condition, i want to call one method using #InverseBinding OR Two Way data binding and reflect the changes with return value.
my Code :
<Button
android:id="#+id/save_btn_disabled_3"
android:enabled="#={controller}"
....
/>
my Two Way data binding logic here :
#InverseBindingAdapter(attribute = "enable")
fun getEnableButton(view:View, controller:Controller): Boolean {
//some conditions
return false
}
i want to know am i going in correct direction ?, code is ok ?
please suggest me.

First Add Button Status Object
<variable
name="button"
type="com.brl.test.app.vm.ButtonStatus" />
<Button
android:id="#+id/save_btn_disabled_3"
bind:state_change="#{button.state}"
....
/>
Set your logic in buttonEnabled funtion then Enable Your Button
#BindingAdapter({"bind:state_change"})
public static void buttonEnabled(TextView view, State state) {
view.setEnabled(true);
}

You can set one variable in field like:
<variable
name="wantsToVisibleProgress"
type="boolean" />
and set it in your button like this:
<Button
android:id="#+id/constraint_select_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/bg_button_blue_big"
android:enabled="#={wantsToVisibleProgress}"
android:gravity="center"
android:onClick="#{v -> fragment.onClick()}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/txt_evse_one">
You can set that value like this:
binding.setWantsToVisibleProgress(true);

Related

Unable to get the data from EditText view in the alert dialog

I created an alertDialog which basically contains two editTexts to enter the data(component Id, component name).When the user clicks on yes button in the alert dialog new component is added to the datbase(as of now I haven't added any on click listeners for yes and no buttons in the dialog) but for some reason I can't get the data from the edit text. I'm new to android app development please help me out guys.....Thanks in Advance :)
Note : 1. I'm using viewModel.flag so that the alertDialog stays persistent with rotations.
onCancel() method simply cancels the alertDialog(I intend to use this for updating certain parameters).
This is kotlin code which creates the alert dialogs.
fun onAddComponent()
{
val builder = AlertDialog.Builder(requireActivity())
builder?.setTitle("New Component Info")
val inflater = requireActivity().layoutInflater
builder?.setView(inflater.inflate(R.layout.new_comp, null))
builder?.setPositiveButton(R.string.Okay_button){ dialogInterface, which->
viewModel.flag = false
val editText : EditText? = compAlert?.findViewById(R.id.new_Component)
println(editText.toString())
}
builder?.setNegativeButton(R.string.NO){ dialogInterface, which->
viewModel.flag = false
}
compAlert= builder?.create()
compAlert?.setOnCancelListener{OnCancel()}
viewModel.flag = true
compAlert?.show()
}
This is the xml layout which I inflated in the onAddComponent()
<androidx.constraintlayout.widget.ConstraintLayout
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">
<EditText
android:id="#+id/new_Component"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:ems="10"
android:hint="comp Id"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="#+id/new_component_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:ems="10"
android:hint="comp name"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="#+id/new_Component"
app:layout_constraintStart_toStartOf="#+id/new_Component"
app:layout_constraintTop_toBottomOf="#+id/new_Component" />
</androidx.constraintlayout.widget.ConstraintLayout>
To get the text inside the EditText you need to do editText.getText().toString() and NOT editText.toString() which you have in your code.
In your code, editText.toString() will return the string representation of the editText object. See the documentation of String's toString() method here.

Android: one-way binding make Switch OnCheckedChangeListener not working

Im just curious about this case, about how one-way binding really work.
I have a Switch and 2 textviews which have colors that bind with checked status of the Switch
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:textColor="#{swLanguage.checked ? #color/term_condition_gray_1 : #color/term_condition_green_1}"
android:textSize="#dimen/_10ssp" />
<Switch
android:id="#+id/swLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/_8sdp"
android:layout_marginRight="#dimen/_8sdp"
android:thumb="#drawable/term_condition_switch_thumb"
android:track="#drawable/term_condition_switch_track" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:textColor="#{swLanguage.checked ? #color/term_condition_green_1 : #color/term_condition_gray_1}"
android:textSize="#dimen/_10ssp" />
I want to do some extra actions when checked status of the Switch changed in java code. But as long as 2 textviews color bind with status of the switch in xml code, setOnCheckedChangeListener is not working.
So is it a problem of databinding feature itself or I just do not know how databinding really work ?
You can connect ObservableBoolean with Two-way binding.
XML
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="activity"
type="someActivity"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:textColor="#{activity.languageChecked ? #color/term_condition_gray_1 : #color/term_condition_green_1}"
android:textSize="#dimen/_10ssp" />
<Switch
android:id="#+id/swLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/_8sdp"
android:layout_marginRight="#dimen/_8sdp"
android:checked="#={activity.languageChecked}"
android:thumb="#drawable/term_condition_switch_thumb"
android:track="#drawable/term_condition_switch_track" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:textColor="#{activity.languageChecked ? #color/term_condition_green_1 : #color/term_condition_gray_1}"
android:textSize="#dimen/_10ssp" />
</LinearLayout>
</layout>
Activity
public ObservableBoolean languageChecked = new ObservableBoolean(false)
How does it work?
If the switch's checked state was changed, languageChecked variable will change.
If languageChecked variable was changed, the internal process of DataBinding will reflect changes of languageChecked into all binding object (in this case, Two textview)
You can change 'languageChecked' variable in Java code and also observe changes of that variable with addOnPropertyChangedCallback
--- Edit ---
If you don't use Two-way binding using ObservableBoolean and using checked property of the switch itself, DataBinding will use InverseBinding to achieve this.
When the build succeeds, You can watch written code in Binding Object. (in this case, my layout name is test_layout, so class name is TestLayoutBindingImpl since I used DataBindingV2)
// Inverse Binding Event Handlers
private androidx.databinding.InverseBindingListener swLanguageandroidCheckedAttrChanged = new androidx.databinding.InverseBindingListener() {
#Override
public void onChange() {
synchronized(TestLayoutBindingImpl.this) {
mDirtyFlags |= 0x2 L;
}
requestRebind();
}
};
if ((dirtyFlags & 0x6 L) != 0) {
// read swLanguage.checked
swLanguageChecked = swLanguage.isChecked();
if ((dirtyFlags & 0x6 L) != 0) {
if (swLanguageChecked) {
dirtyFlags |= 0x10 L;
dirtyFlags |= 0x40 L;
} else {
dirtyFlags |= 0x8 L;
dirtyFlags |= 0x20 L;
}
}
// read swLanguage.checked ? #android:color/term_condition_gray_1 : #android:color/term_condition_green_1
swLanguageCheckedMboundView1AndroidColorTermConditionGray1MboundView1AndroidColorTermConditionGreen1 = ((swLanguageChecked) ? (getColorFromResource(mboundView1, R.color.term_condition_gray_1)) : (getColorFromResource(mboundView1, R.color.term_condition_green_1)));
// read swLanguage.checked ? #android:color/term_condition_green_1 : #android:color/term_condition_gray_1
swLanguageCheckedMboundView2AndroidColorTermConditionGreen1MboundView2AndroidColorTermConditionGray1 = ((swLanguageChecked) ? (getColorFromResource(mboundView2, R.color.term_condition_green_1)) : (getColorFromResource(mboundView2, R.color.term_condition_gray_1)));
}
// batch finished
if ((dirtyFlags & 0x6 L) != 0) {
// api target 1
this.mboundView1.setTextColor(swLanguageCheckedMboundView1AndroidColorTermConditionGray1MboundView1AndroidColorTermConditionGreen1);
this.mboundView2.setTextColor(swLanguageCheckedMboundView2AndroidColorTermConditionGreen1MboundView2AndroidColorTermConditionGray1);
}
if ((dirtyFlags & 0x4 L) != 0) {
// api target 1
androidx.databinding.adapters.CompoundButtonBindingAdapter.setListeners(this.swLanguage, (android.widget.CompoundButton.OnCheckedChangeListener) null, swLanguageandroidCheckedAttrChanged);
}
In last statement, they use setListeners() methods to register OnCheckedChangeListener() with swLanguageandroidCheckedAttrChanged. swLanguageandroidCheckedAttrChanged using InverseBindingAdapter to observe changes.
Since setListener() using setOnCheckedChangeListener methods to setting listener, you can't operate two setOnCheckedChangeListener in code between Binding Object and Java code.
So, if you want to use setOnCheckedChangeListener in your java code(activity), using ObservableBoolean and observe changes by addOnPropertyChangedCallback.
If you want to compare result of two solution, see Gist

Databinding onclick listener on button

trying to understand data binding, not getting it though. Any help appreciated.
what i need is all together my custom method call "setOnClick(User user)" on click of the button. I just want understand Binding Adapters Concepts.
Execution failed for task ':databinding:compileDebugJavaWithJavac'.
android.databinding.tool.util.LoggedErrorException: Found data binding errors.
****/ data binding error ****msg:cannot find method setOnClick() in class com.locale.databinding.MyAdapter file:/Users/svernekar003/Documents/GitHub/RxDagger2Demo/databinding/src/main/res/layout/activity_main.xml loc:61:35 - 61:61 ****\ data binding error ****
sample code.
activity_main.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="user"
type="com.locale.databinding.User"></variable>
<variable
name="myClickHandler"
type="com.locale.databinding.MyAdapter"></variable>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.locale.svernekar.databinding.MainActivity">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="#{user.name}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/last_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:text="#{user.lastName}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="#+id/name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.502" />
<ViewStub
android:id="#+id/view_stub"
android:layout_width="20dp"
android:layout_height="20dp"
android:inflatedId="#+id/inflate_id"
android:layout="#layout/view_stub_sample" />
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:onClick="#{()->myClickHandler.setOnClick(user)}"
android:text="Change Data"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/last_name" />
</android.support.constraint.ConstraintLayout>
MyAdapter.java
public class MyAdapter {
private User user;
#BindingAdapter("android:onClick")
public static void setOnClick(User user) {
Log.d("Onclick", "after do long time");
}
#BindingAdapter("android:src")
public static void setImageResource(ImageView imageView, int resource) {
imageView.setImageResource(resource);
}
public int getId() {
return android.R.drawable.ic_dialog_dialer;
}
}
Use this
android:onClick="#{user}"
Because you have created BindingAdapter
#BindingAdapter("android:onClick")
public static void setOnClick(User user) {
...
}
Reason
You have created #BindingAdapter of attribute android:onClick so it will work like above.
You're missing an understanding of callbacks here. I suggest doing Google's databinding code lab here:
https://codelabs.developers.google.com/codelabs/android-databinding/index.html
However, we can walk through the solution together.
First, to create a BindingAdapter, you need to specify a view type in the method. So, it should look something like this:
#BindingAdapter("android:onClick")
fun setOnClick(view: View, user: User) {
Log.d("Onclick", "after do long time")
}
Now, the thing about BindingAdapters is, they are set either when the page loads or when their bound value changes. So, if User is a LiveData, this will work, BUT it won't call when the user clicks- it'll call when the user value is updated. BindingAdapters call when their bound value updates, no matter what the name is. So, the above code is the same as this block:
#BindingAdapter("app:userUpdated")
fun setUserUpdated(view: View, user: User) {
Log.d("UserUpdated", "after user value is updated")
}
Your onClick binding isn't setting a click listener in this case- it's setting a binding to the "user" field. So, there will be two bindingadapters for onClick- one if you bind a User, and one (system default) if you bind a ClickListener. The XML you have binds to the clicklistener, not the user, so your adapter will never be executed. But even if it was bound correctly, it wouldn't bind on click, because it's not bound that way. To get it to bind on click for the user, you'd need to do something like this:
#BindingAdapter("android:onClick")
fun setOnClick(view: View, user: User) {
view.setOnClickListener(View.OnClickListener { Log.d("Onclick", "after do long time") })
}

How to bind method on RadioGroup on checkChanged event with data-binding

I was searching over the internet for how to perform the new cool android data-binding over the RadioGroup and I didn't find a single blog post about it.
Its a simple scenario, based on the radio button selected, I want to attach a callback event using android data binding. I don't find any method on the xml part which allows me to define a callback.
Like here is my RadioGroup:
<RadioGroup
android:id="#+id/split_type_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:checkedButton="#+id/split_type_equal"
android:gravity="center"
<!-- which tag ? -->
android:orientation="horizontal">
...
</RadioGroup>
How do I attach a handler method which will be called on RadioGroup's checkChnged event will fire using data-binding?
I have tried using onClick (don't know if it is the same) in layout file and defining method in the Activity and located it using this in the layout file:
<variable
name="handler"
type="com.example.MainActivity"/>
...
<RadioGroup
android:onClick="handler.onCustomCheckChanged"
.. >
And defined method onCustomCheckChanged like this:
public void onCustomCheckChanged(RadioGroup radio, int id) {
// ...
}
But, it gives me the compilation error:
Error:(58, 36) Listener class android.view.View.OnClickListener with method onClick did not match signature of any method handler.onCustomCheckChanged
I have seen many blogs mentioning it is possible with RadioGroup but non of them really say how. How can I handle this with data-binding ?
After digging to the bunch of methods, I found this question on SO which helped me understand how to bind single methods of listeners.
Here is what to do with RadioGroup:
In RadioGroup listener you have a method onCheckedChanged(RadioGroup g, int id). So you can directly bound that method to your handler or your activity by passing an instance of it as a variable in layout file and calling a method with the same signature.
So call on layout file like this:
<RadioGroup
android:id="#+id/split_type_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:checkedButton="#+id/split_type_equal"
android:gravity="center"
android:onCheckedChanged="#{handler.onSplitTypeChanged}"
android:orientation="horizontal">
...
</RadioGroup>
And in my activity or handler, I need to simply provide the method with same name and signature like this:
public void onSplitTypeChanged(RadioGroup radioGroup,int id) {
// ...
}
Just make sure method is public.
NOTE: This works for any (most of, I have not tried all) listener methods. Like for EditText you can provide android:onTextChanged and so on.
I am using a string, and in this case I have bindable based on viewModel.getCommuteType() viewModel.setCommuteType(String)
<RadioGroup
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.DRIVING)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.DRIVING)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="D"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.BICYCLE)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.BICYCLE)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="B"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.WALKING)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.WALKING)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="W"/>
<RadioButton
android:checked="#{viewModel.commuteType.equals(Commute.BUS)}"
android:onClick="#{()->viewModel.setCommuteType(Commute.BUS)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="T"/>
After some hours I found easy way: two-way databinding in android. It's base skeleton with livedata and Kotlin. Also you can use ObservableField()
Set your viewmodel to data
Create your radiogroup with buttons as you like. Important: set all radio buttons id !!!
Set in your radio group two-way binding to checked variable (use viewmodel variable)
Enjoy)
layout.xml
<data>
<variable
name="VM"
type="...YourViewModel" />
</data>
<LinearLayout
android:id="#+id/settings_block_env"
...
>
<RadioGroup
android:id="#+id/env_radioGroup"
android:checkedButton="#={VM.radio_checked}">
<RadioButton
android:id="#+id/your_id1"/>
<RadioButton
android:id="#+id/your_id2" />
<RadioButton
android:id="#+id/your_id3"/>
<RadioButton
android:id="#+id/your_id4"/>
</RadioGroup>
</LinearLayout>
class YourViewModel(): ViewModel {
var radio_checked = MutableLiveData<Int>()
init{
radio_checked.postValue(R.id.your_id1)//def value
}
//other code
}
Often you care more about what was actually checked instead of "something was checked". In such case alternative solution is to ignore RadioGroup and bind all items as below:
<RadioGroup (...) >
<RadioButton (...)
android:checked="#={viewModel.optionA}"/>
<RadioButton (...)
android:checked="#={viewModel.optionB}"/>
<RadioButton (...)
android:checked="#={viewModel.optionC}"/>
</RadioGroup>
where optionA, optionB and optionC are defined in ViewModel like below:
public final ObservableBoolean optionA = new ObservableBoolean();
public final ObservableBoolean optionB = new ObservableBoolean();
public final ObservableBoolean optionC = new ObservableBoolean();
This is usually enough, however if you want to react immediately on click then you can add callBacks and use them like that:
OnPropertyChangedCallback userChoosedA = new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(Observable sender, int propertyId) {
(...) // basically propertyId can be ignored in such case
}
};
optionA.addOnPropertyChangedCallback(userChoosedA);
Advantage of such approach is that you don't need to compare and track "id".
In my current project, I did it like this.
I have three currency in the project and I choose one of them via RadioGroup.
It's enum with currencies:
enum class Currency(val value: Byte) {
USD(0),
EUR(1),
RUB(2);
companion object Create {
fun from(sourceValue: Byte): Currency = values().first { it.value == sourceValue }
fun from(sourceValue: String): Currency = values().first { it.toString() == sourceValue }
}
}
A piece of my ViewModel:
class BaseCurrencyViewModel : ViewModelBase<BaseCurrencyModelInterface>() {
/**
* Selected currency
*/
val currency: MutableLiveData<Currency> = MutableLiveData()
/**
*
*/
init {
currency.value = Currency.USD // Init value
}
}
Part of my layout (pay attention to binding in RadioGroup and tags of RadioButton):
<RadioGroup
android:id="#+id/currencySwitchers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:selectedCurrency = "#{viewModel.currency}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toEndOf="parent">
<RadioButton
android:id="#+id/usdSwitcher"
android:text="USD"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="USD"
/>
<RadioButton
android:id="#+id/eurSwitcher"
android:text="EUR"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="EUR"
/>
<RadioButton
android:id="#+id/rubSwitcher"
android:text="RUB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:tag="RUB"
/>
</RadioGroup>
And the final part - binding adapter.
#BindingAdapter("selectedCurrency")
fun setSelectedCurrency(view: View, value: MutableLiveData<Currency>?) {
view.getParentActivity()?.let { parentActivity ->
value?.observe(parentActivity, Observer { value ->
view.findViewWithTag<RadioButton>(value.toString())
?.also {
if(!it.isChecked) {
it.isChecked = true
}
}
}
)
(view as RadioGroup).setOnCheckedChangeListener { radioGroup, checkedId ->
val currency = Currency.from(radioGroup.findViewById<RadioButton>(checkedId).tag as String)
if(value != null && value.value != currency) {
value.value = currency
}
}
}
}
In this way, I got two-way binding between RadioGroup and a property in my ViewModel.

Android - Conditional text value using Data Binding

I want to set the text of my TextView conditionally to either one or the other.
Android Data Binding documentation suggests that you can set the text conditionally if the text is a property of the view model. e.g.
android:text="#{user.displayName != null ? user.displayName : user.lastName}"
But is there any way to set the text from the strings.xml rather than adding it in my view model? I want something like this-
android:text="#{viewModel.expanded ? #string/collapse : #string/expand}"
The XML looks somewhat like this:
<?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 class="TravellerInfoBinding">
<import type="android.view.View" />
<variable name="viewModel" type="com.myproject.viewmodel.TravellerInfoViewModel" />
</data>
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal">
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="#drawable/expandable_arrow_blue" />
<TextView style="#style/primary_pair_element_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{viewModel.expanded ? #string/taxes_fees_detail : #string/hide_taxes_fees_detail}"
android:textSize="12sp" />
</LinearLayout>
</layout>
And this is my View Model-
package com.myproject.viewmodel;
imports...
public class TravellerInfoViewModel extends BaseObservable {
#Bindable
private final TaxDetailsViewModel taxDetailsViewModel;
#Bindable
private boolean expanded;
Constructor....
public boolean isExpanded() {
return expanded;
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
notifyPropertyChanged(BR.expanded);
}
public void toggleExpanded() {
setExpanded(!expanded);
}
}
Actually, this works fine for me
<TextView
android:id="#+id/btnEdit"
style="#style/Common.Toolbar.Action.Text"
android:onClickListener="#{onEditClick}"
android:text="#{vm.editMode ? #string/contacts_done : #string/contacts_edit}"
tools:text="#string/contacts_edit"/>
Where vm - it's a ViewModel and editMode - it's ObservableBoolean
Here's a fix/work-around :
define a duplicate Xml definition of the layout where you want a conditional value
for each block, set one of the condition values
set the visibility of each Xml definition according to the data binding boolean value
Not the ideal solution, not very pretty .. but functionally equivalent - and works in the interim until proper solution is found.
Here's how I solved it for android:textStyle, where I had a special case requirement for showing values in bold.
<variable
name="viewModel"
type="com.demo.app.SomeViewModel"/>
...
<TextView
style="#style/RowValue"
android:visibility="#{ ! viewModel.boldRow ? View.VISIBLE : View.GONE}"
android:text="#{viewModel.currentValue}"
/>
<TextView
style="#style/RowValue"
android:visibility="#{ viewModel.boldRow ? View.VISIBLE : View.GONE}"
android:text="#{viewModel.currentValue}"
android:textStyle="bold"
/>

Categories

Resources