Progressbar visibility property not working with data binding - android

Visibility property not working
<data>
<import type="android.view.View"/>
<variable
name="viewmodel"
type="com.wiesoftware.spine.ui.auth.LoginViewModel" />
</data>
This is my progressbar code
<ProgressBar
android:id="#+id/pbLogin"
android:visibility="#{viewmodel.isVisibles ? View.VISIBLE : View.GONE, default=gone}"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="#+id/editTextTextPersonName2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/editTextTextPersonName" />
I am changing the value of isVisibles in viewModel but it doesn't reflect please give a solution. This is the class where I change isVisibles value.
class LoginViewModel(
private val authRepositry: AuthRepositry
):ViewModel() {
var email:String?=null
var password:String?=null
var loginEventListener:LoginEventListener?=null
var isVisibles:Boolean=false
fun loginButtonClicked(view: View){
isVisibles=true
if (email.isNullOrEmpty() || password.isNullOrEmpty()){
loginEventListener?.onLoginFailed("Please enter credentials.")
isVisibles=false
return
}
}
}```
> I have updated viewmodel class please check and let me know where is the issue I am using Kotlin Please provide me solution thanks

try add this
binding.lifecycleOwner = this // activity

Related

Data Binding - Cannot call function from a layout file

I'm trying to call a function from my Data Binding layout, but I'm always receiving some error. I'm trying to set the text on my textView using MyUtilClass's function which I have created. here's my 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>
<import type="com.example.testapp.User"/>
<import type="com.example.testapp.MyUtilClass"/>
<variable
name="user"
type="User" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{MyUtilClass.Companion.changeText(user.firstName)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MyUtilClass
class MyUtilClass {
companion object {
#JvmStatic
fun changeText(text: String): String {
return text
}
}
}
User
data class User(
val firstName: String,
val lastName: String,
val age: Int,
val loggedIn: Boolean
)
MainActivity.java
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val myUser = User("John", "Doe", 25, true)
binding.user = myUser
}
}
Error:
C:\Users\Stefan\AndroidStudioProjects\TestApp\app\build\generated\source\kapt\debug\com\example\testapp\DataBinderMapperImpl.java:9:
error: cannot find symbol import
com.example.testapp.databinding.ActivityMainBindingImpl;
^ symbol: class ActivityMainBindingImpl location: package
com.example.testapp.databinding
cannot find method changeText(java.lang.String) in class
com.example.testapp.MyUtilClass.Companion Open File
Adding JvmStatic to the changeText() method in MyUtilClass automatically makes it static.
Therefore, you can access it like this in your layout file:
<?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="com.example.testapp.User"/>
<import type="com.example.testapp.MyUtilClass"/>
<variable
name="user"
type="User" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{MyUtilClass.changeText(user.firstName)}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
You can check this link to find out more:
Kotlin DataBinding pass static function into layout xml
This is the change I made, and it worked. I basically removed class keyword and added object instead.
object MyUtilClass {
#JvmStatic
fun changeText(text: String): String {
return text
}
}

How can I set a ConstraintLayout Group's visibility via DataBinding?

I have 2 Groups in my layout which control the visibility of my Views.
However, I cannot set their visibility via DataBinding:
<layout>
<data>
<import type="android.view.View"/>
<variable
name="viewModel"
type="co.aresid.book13.fragments.trackinglist.TrackingListViewModel"
/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout>
...
<androidx.constraintlayout.widget.Group
android:id="#+id/content_group"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="#{viewModel.hideLoadingAndShowContent ? View.VISIBLE : View.GONE, default=gone}"
app:constraint_referenced_ids="tracking_list_recycler_view"
/>
<androidx.constraintlayout.widget.Group
android:id="#+id/loading_group"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="#{viewModel.hideLoadingAndShowContent ? View.GONE : View.VISIBLE, default=visible}"
app:constraint_referenced_ids="progress_circular"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The hideLoadingAndShowContent variable is a LiveData which gets its value from a corresponding MutableLiveData in my ViewModel:
private val _hideLoadingAndShowContent = MutableLiveData<Boolean>()
val hideLoadingAndShowContent: LiveData<Boolean>
get() = _hideLoadingAndShowContent
This LiveData is only set in the ViewModel and does not occur in the Fragment class.
In the Fragment class, I have also set the binding.lifecycleOwner:
binding.lifecycleOwner = viewLifecycleOwner
What detail am I missing out?
I forgot to pass the ViewModel to the layout binding in my Fragment class:
binding.viewModel = viewModel
Because that android:visibility does not support binding variable observation,
You can create BindingAdapter this way
#BindingAdapter("mutableVisibility")
fun setMutableVisibility(view: View, visibility: MutableLiveData<Boolean>) {
val owner = (view.getParentActivity() ?: view.context) as LifecycleOwner
if (owner != null) {
visibility.observe(
owner,
Observer { value ->
view.visibility = if(value) View.VISIBLE else View.GONE
})
}
}
Utility function for getting activity from view.
fun View.getParentActivity(): AppCompatActivity?{
var context = this.context
while (context is ContextWrapper) {
if (context is AppCompatActivity) {
return context
}
context = context.baseContext
}
return null
}
Then in your XML you can do it like
<androidx.constraintlayout.widget.Group
android:id="#+id/content_group"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="#{viewModel.hideLoadingAndShowContent}"
app:constraint_referenced_ids="tracking_list_recycler_view"
/>

Textview and Seekbar are bound to the same property, but the textview doesn´t show the updated value

I´ve created a viemodel with a MutableLiveData
val duration = MutableLiveData(2)
In my Activity in set the Databinding
binding = DataBindingUtil.setContentView(this, R.layout.activity_ticket)
binding.viewmodel = this.viewModel
Here is my Layout
<data>
<variable
name="viewmodel"
type="com.text.viewmodel.TicketViewModel"/>
</data>
...
<TextView
android:id="#+id/textview_duration"
android:layout_margin="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{String.valueOf(viewmodel.duration)}"
/>
<SeekBar
android:id="#+id/seekBar_duration"
android:max="8"
android:min="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="#={viewmodel.duration}"
/>
When the user changed the seekbar, then the value in the ViewModel is updated correctly, but the text view does not refresh itself.
I found the solution by myself.
I forgot to set the the activity as lifecycleowner
binding = DataBindingUtil.setContentView<ActivityTicketBinding>(this, R.layout.activity_ticket)
binding.lifecycleOwner = this
binding.viewmodel = this.viewModel

MVVM BindingAdapters not showing ProgressBar

I'm trying to create a simple example with databinding and BindingAdapters in order to show/hide a ProgressBar depending on TextView if it's empty or not. Below you can see my code. What I'm doing wrong?
loading_state.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="textString"
type="String"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:visibleGone="#{textString==null}">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{textString}"/>
</android.support.constraint.ConstraintLayout>
</layout>
My BindingAdapter
object BindingAdapters {
#JvmStatic
#BindingAdapter("visibleGone")
fun showHide(view: View, visible: Boolean){
view.visibility = if (visible) View.VISIBLE else View.GONE
}
}
I include the layout in my second fragment in order to check the textview text
<include layout="#layout/loading_state"
app:textString="#{textView2.text.toString()}"/>
and also in my SecondFramgent class I take the value from MainFragment class (I'm using the new Navigation component)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val txtFromMain = SecondFragmentArgs.fromBundle(arguments)
textView2.text = txtFromMain.txtFromMain
}
What am I missing?
Thank you very much.
For those facing the same issue you can find my solutions matches in my case below:
I had to change my BindingAdapter.
#BindingAdapter("visibleGone")
fun showHide(view: View, visible: String){
view.visibility = if (visible.isEmpty()) View.VISIBLE else View.GONE
}
You did not set two-way databinding for TV, thus string is not getting updated inside databinding
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{textString}"/>
Change android:text="#{textString}" to android:text="#={textString}"
This is first look of the problem, does it help?

Use data binding to set View visibility

Trying to set visibility of View using custom variable, but error occurs: Identifiers must have user defined types from the XML file. visible is missing it. Is it possible to set view visibility using data binding? Thanks.
<data>
<variable
name="sale"
type="java.lang.Boolean"/>
</data>
<FrameLayout android:visibility="#{sale ? visible : gone}"/>
As stated in the Android Developer Guide, you need to do it like this:
<data>
<import type="android.view.View"/>
<variable
name="sale"
type="java.lang.Boolean"/>
</data>
<FrameLayout android:visibility="#{sale ? View.GONE : View.VISIBLE}"/>
In your layout:
<data>
<variable
name="viewModel"
type="...."/>
</data>
<View
android:layout_width="10dp"
android:layout_height="10dp"
android:visibility="#{viewModel.saleVisibility, default=gone}"/>
In your ViewModel java code:
#Bindable
public int getSaleVisibility(){
return mSaleIndecator ? VISIBLE : GONE;
}
The problem is that visibility is an Integer on the View class, this means you have two ways to make this work:
Use the View.VISIBLE and View.GONE constants. https://developer.android.com/topic/libraries/data-binding/index.html#imports
Define a custom setter for visibility that takes a Boolean. https://developer.android.com/topic/libraries/data-binding/index.html#custom_setters
Possible implementation:
#BindingAdapter("android:visibility")
public static void setVisibility(View view, Boolean value) {
view.setVisibility(value ? View.VISIBLE : View.GONE);
}
Which will make <FrameLayout android:visibility="#{sale}"/> work.
Similar to Kiskae solution. Put this method in a separate file, for instance, Bindings.kt:
#BindingAdapter("android:visibility")
fun View.bindVisibility(visible: Boolean?) {
isVisible = visible == true
// visibility = if (visible == true) View.VISIBLE else View.GONE
}
Then in layout XML:
<data>
<variable
name="viewModel"
type="SomeViewModel" />
</data>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="#{viewModel.number == 1}" />

Categories

Resources