I am trying to use TextInputLayout in a preference screen so as have a nice neat password box that has a show password option. I know there are ways and means of doing it with checkboxes and scripting but I would really love to be to just use the TextInputLayout, maybe wrapped or in a custom widget. Gradle dependencies are correct as it works fine in other activity screens.
The following preferences.xml crashes with an "Error inflating class com.google.android.material.textfield.TextInputLayout"
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.google.android.material.textfield.TextInputLayout>
</androidx.preference.PreferenceScreen>
Ok I worked out the answer (and learned a lot in the process). Took a lot of research and trial and error but I hope the following might prove helpful to someone similarly frustrated.
The custom preference layout:
password.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textLay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="66dp"
android:hint="#string/Set_Password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="#android:id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
The preference screen layout:
preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.toggen.myapplication.PasswordPreference
android:key="pref_password"
android:layout="#layout/password" />
</PreferenceScreen>
SettingsActivity.kt
package com.toggen.myapplication
import kotlinx.android.synthetic.main.password0.view.*
import androidx.appcompat.app.AppCompatActivity
import android.util.AttributeSet
import android.widget.EditText
import android.content.Context
import androidx.preference.*
import android.os.Bundle
class PasswordPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs){
private var passW: EditText? = null
override fun onBindViewHolder(holder: PreferenceViewHolder?) {
super.onBindViewHolder(holder)
passW = holder?.itemView?.textLay?.editText?.apply{ setText(getPersistedString("admin")) }
}
override fun onDetached() {
super.onDetached()
passW?.apply{ persistString("$text") }
}
}
class SettingsActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState == null) {
supportActionBar?.title = "Settings"
supportFragmentManager.beginTransaction()
.replace(android.R.id.content, SettingsFragment()).commit()
}
}
override fun onSupportNavigateUp() = onBackPressed().run { true }
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) = setPreferencesFromResource(R.xml.preferences, rootKey)
}
}
Finally the answer that I've been looking for!! THANK YOU!!
Only modification that I would make is to use:
android:dialogLayout="#layout/password"
instead of:
android:layout="#layout/password"
Related
XML File
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".MainActivity">
<app.rive.runtime.kotlin.RiveAnimationView
android:id="#+id/animationView"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:riveResource="#raw/loading_bar" />
</androidx.constraintlayout.widget.ConstraintLayout>
Kotlin file
package com.example.basicriveapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.startup.AppInitializer
import app.rive.runtime.kotlin.RiveAnimationView
import app.rive.runtime.kotlin.RiveInitializer
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
AppInitializer.getInstance(this)
.initializeComponent(RiveInitializer::class.java);
var animationView = findViewById<RiveAnimationView>(R.id.animationView);
animationView.pause();
}
}
Since I am trying to pause the Animation, it is not working and Can you please explain how to use play() and stop() methods with RiveAnimationView
You need to specify the animation name you want to play/pause inside the parentheses:
animationView.pause("animation name");
animationView.play("animation name");
You can get the animation name from the rive editor under the panel called "Animations"
I faced an error that actually mustn't occur, because I do exactly the same thing in my project in another screen, and it works there, but doesn't want to work in another screen.
The problem is the following: from an Activity in a result of some action I open up a DialogFragment which contains an image and other views in its layout file. Now I can't understand why, but it works in the first case (you'll see below) but doesn't work in the second...
First case:
Layout XML file (dialog_character_selector.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="dialogViewModel"
type="neptun.jxy1vz.cluedo.ui.menu.character_selector.CharacterSelectorViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Spinner
android:id="#+id/spinnerCharacter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/ivCharacterCard"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="20dp"
android:src="#drawable/szereplo_hatlap"
app:layout_constraintBottom_toTopOf="#+id/btnStart"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.7"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/spinnerCharacter" />
<Button
android:id="#+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/start"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:onClick="#{()->dialogViewModel.startGame()}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
The DialogFragment's Kotlin source code (CharacterSelectorDialog.kt):
package neptun.jxy1vz.cluedo.ui.menu.character_selector
import android.animation.AnimatorInflater
import android.animation.AnimatorSet
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.appcompat.app.AlertDialog
import androidx.core.animation.doOnEnd
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.DialogFragment
import neptun.jxy1vz.cluedo.R
import neptun.jxy1vz.cluedo.databinding.DialogCharacterSelectorBinding
class CharacterSelectorDialog : DialogFragment(), AdapterView.OnItemSelectedListener {
private lateinit var dialogCharacterSelectorBinding: DialogCharacterSelectorBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
dialogCharacterSelectorBinding = DataBindingUtil.inflate(
LayoutInflater.from(context),
R.layout.dialog_character_selector,
null,
false
)
dialogCharacterSelectorBinding.spinnerCharacter.adapter = ArrayAdapter<String>(
context!!,
android.R.layout.simple_spinner_dropdown_item,
resources.getStringArray(R.array.characters)
)
dialogCharacterSelectorBinding.spinnerCharacter.onItemSelectedListener = this
//I do this due to a card flipping animation, it's not important, not part of my problem
val scale = resources.displayMetrics.density
dialogCharacterSelectorBinding.ivCharacterCard.cameraDistance = 8000 * scale
dialogCharacterSelectorBinding.dialogViewModel = CharacterSelectorViewModel(context!!)
return AlertDialog.Builder(context!!, R.style.Theme_AppCompat_Light_Dialog).setView(dialogCharacterSelectorBinding.root).setTitle(resources.getString(R.string.dialog_character_title)).create()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
dialogCharacterSelectorBinding.ivCharacterCard.setImageResource(R.drawable.szereplo_hatlap)
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
dialogCharacterSelectorBinding.ivCharacterCard.setImageResource(R.drawable.szereplo_hatlap)
(AnimatorInflater.loadAnimator(context, R.animator.card_flip) as AnimatorSet).apply {
setTarget(dialogCharacterSelectorBinding.ivCharacterCard)
start()
doOnEnd {
dialogCharacterSelectorBinding.dialogViewModel!!.setPlayer(position)
val img = when (position) {
0 -> R.drawable.szereplo_ginny
1 -> R.drawable.szereplo_harry
2 -> R.drawable.szereplo_hermione
3 -> R.drawable.szereplo_ron
4 -> R.drawable.szereplo_luna
else -> R.drawable.szereplo_neville
}
dialogCharacterSelectorBinding.ivCharacterCard.setImageResource(img)
}
}
}
}
Second case:
Layout XML file (dialog_helper_card.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="helperCardDialogViewModel"
type="neptun.jxy1vz.cluedo.ui.dice.card_dialog.helper.HelperCardViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/ivHelperCard"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="20dp"
android:src="#drawable/mento_hatlap"
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>
I think in the main parts it's just the same as the previous one.
Kotlin source file (HelperCardDialog.kt):
package neptun.jxy1vz.cluedo.ui.dice.card_dialog.helper
import android.animation.AnimatorInflater
import android.animation.AnimatorSet
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.core.animation.doOnEnd
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.DialogFragment
import neptun.jxy1vz.cluedo.R
import neptun.jxy1vz.cluedo.databinding.DialogHelperCardBinding
class HelperCardDialog(private val cardResource: Int) : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog {
val dialogHelperCardBinding = DataBindingUtil.inflate<DialogHelperCardBinding>(LayoutInflater.from(context), R.layout.dialog_helper_card, null, false)
dialogHelperCardBinding.helperCardDialogViewModel = HelperCardViewModel()
(AnimatorInflater.loadAnimator(context, R.animator.card_flip) as AnimatorSet).apply {
setTarget(dialogHelperCardBinding.ivHelperCard)
start()
doOnEnd {
dialogHelperCardBinding.ivHelperCard.setImageResource(cardResource)
}
}
return AlertDialog.Builder(context!!, R.style.Theme_AppCompat_Dialog).setTitle(resources.getString(R.string.got_helper_card)).setNeutralButton(resources.getString(R.string.ok)
) { dialog, _ ->
dialog.dismiss()
}.create()
}
}
That's it. These are my most important files in my problem. Sorry for the lot of code...
I hope you will see where the problem is and tell me what's the solution for it.
Finally I found the error in my code. I left the setView() function call from the second AlertDialog.Builder().
The correct code snippet is:
return AlertDialog.Builder(context!!, R.style.Theme_AppCompat_Dialog)
.setView(dialogHelperCardBinding.root)
.setTitle(resources.getString(R.string.got_helper_card)).setNeutralButton(
resources.getString(R.string.ok)
) { dialog, _ ->
dialog.dismiss()
}.create()
I referred to this document.
SettingsActivity.kt:
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceFragmentCompat
class SettingsActivity : AppCompatActivity() {
class DispatcherFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
this.setPreferencesFromResource(R.xml.settings_items, rootKey)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
this.supportFragmentManager
.beginTransaction()
.replace(R.id.content, DispatcherFragment())
.commit()
}
}
settings_items.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreferenceCompat
app:key="notifications"
app:title="Enable message notifications"/>
<Preference
app:key="feedback"
app:title="Send feedback"
app:summary="Report technical issues or suggest new features"/>
</androidx.preference.PreferenceScreen>
When I ran the program, I got an error:Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f07004c (<my_package_name>:id/content) for fragment DispatcherFragment{24598125 (ae4eec60-a4c6-404b-b899-7fb0e6b378f2) id=0x7f07004c}
It seems that I did the same thing as Google Docs, but did not get the expected results.
Is there anything missing from this? Or are there other matters needing attention that are not mentioned in the document?
Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f07004c (:id/content) for fragment DispatcherFragment{24598125 (ae4eec60-a4c6-404b-b899-7fb0e6b378f2) id=0x7f07004c}
It means that this.supportFragmentManager.replace(R.id.content, DispatcherFragment()) is not able to find the view defined with R.id.content.
The id passed into supportFragmentManager.replace(), in your case R.id.content, must be a child of the layout specified in setContentView() of your Activity.
Something like:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//...
}
where the layout is:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
I am trying to implement a settings screen within my app which contains 2 nested preference screens namely "Backup" and "About". I tried to follow the guides from this link: Organize your Settings
Please see my code below:
activity_settings.xml
<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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.settings.SettingsActivity">
<ImageButton
android:id="#+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="#string/ContentDescription_Icon_Back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_back_dark" android:layout_marginStart="16dp"
android:layout_marginTop="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="Settings"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/back_button"
style="#style/Screen_Title_Default" android:id="#+id/textView"
app:layout_constraintBottom_toBottomOf="#+id/back_button"/>
<fragment
android:id="#+id/fragment_cont"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:name="com.th3pl4gu3.lifestyle.ui.settings.SettingsMainFragment"
app:layout_constraintTop_toBottomOf="#+id/textView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
SettingsActivity.kt
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.th3pl4gu3.lifestyle.R
import com.th3pl4gu3.lifestyle.databinding.ActivitySettingsBinding
class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat?, pref: Preference): Boolean {
// Instantiate the new Fragment
val args = pref.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
pref.fragment
)
fragment.arguments = args
fragment.setTargetFragment(caller, 0)
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_cont, fragment)
.addToBackStack(null)
.commit()
return true
}
private lateinit var _binding: ActivitySettingsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = DataBindingUtil.setContentView(this, R.layout.activity_settings)
}
override fun onStart() {
super.onStart()
_binding.backButton.setOnClickListener {
onBackPressed()
}
}
}
preferences_settings_main.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:key="backup_local"
app:title="Backup"
app:summary="Create and restore backups"
app:fragment="com.th3pl4gu3.lifestyle.ui.settings.SettingsBackupFragment"
android:icon="#drawable/ic_backup_dark"/>
<Preference
app:key="about"
app:title="About"
app:summary="About this application"
android:icon="#drawable/ic_info_dark"/>
</PreferenceScreen>
SettingsMainFragment.kt
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import com.th3pl4gu3.lifestyle.R
class SettingsMainFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences_settings_main, rootKey)
}
}
preferences_settings_backup.xml
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="Backup">
<EditTextPreference
android:defaultValue="internal/Android"
android:key="path"
android:summary="The path to create local backup"
android:title="Backup Path"/>
<Preference
app:title="Create Backup Locally"
app:summary="Creates a backup locally and saves to specified path."/>
<Preference
app:title="Create Backup in Cloud"
app:summary="Creates a backup and saves to Google Drive"/>
</PreferenceCategory>
<PreferenceCategory app:title="Restore">
<Preference
app:title="Restore Locally"
app:summary="Restore a Backup Locally"/>
<Preference
app:title="Restore from Cloud"
app:summary="Restore a Backup from Google Drive"/>
</PreferenceCategory>
What i wanted was when i click on "Backup" on the main preference screen, it would replace the whole fragment and show only the backup preference fragment. Instead, i am having this output:
It is showing the fragment on the same screen which i do not want. Can someone help me please?
I keep getting the binding error when trying to use the #BindingAdapter. Try for 3 days and follow numerous online articles on this subject, but still getting the below error.
#BindingAdapter("focusableColor")
fun setFocusableColor(v:CardView, color:Int) {
println("hello")
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding:ActivityMainBinding =
DataBindingUtil.setContentView(this,R.layout.activity_main)
etc...
}
In current_task_layout.xml
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="task" type="com.edenhan.simplytask.Task">
</variable>
</data>
<android.support.v7.widget.CardView
android:id="#+id/card_view">
.....
focusableColor="#{1}"/>
Error encountered:
Found data binding errors.
****/ data binding error ****msg:Cannot find the setter for attribute ‘focusableColor’ with parameter type int on
android.support.v7.widget.CardView.
file:D:\…….\app\src\main\res\layout\current_task_layout.xml
Have you tried moving the binding out of the companion object?
You should put it in a kotlin file and make it a top level function. For example:
Bindings.kt
#BindingAdapter("focusableColor")
fun setFocusableColor(v:CardView, color:Int) {..}
And put the binding xml in the app namespace
Also, see Kotlin custom attribute databinding
edit: full example
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
#BindingAdapter("focusableColor")
fun setColor(card: CardView, #ColorInt color: Int) {
// or whatever
card.setBackgroundColor(color)
}
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"
>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.CardView
android:id="#+id/card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:focusableColor="#{1}"/>
</android.support.constraint.ConstraintLayout>
</layout>
Below defined full code for load image using BindingAdapter with Kotlin
ImageLoader.kt
import android.widget.ImageView
import androidx.databinding.BindingAdapter
import androidx.databinding.ObservableField
class ImageLoader {
val imageResource = ObservableField(R.drawable.ic_launcher_background)
companion object {
#JvmStatic
#BindingAdapter("android:src")
fun setImage(imageView: ImageView, imageRes: Int) {
imageView.setImageResource(imageRes)
}
}
}
activity_home.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="imageLoader" type="com.sample.testdemo.ImageLoader"/>
</data>
<RelativeLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/app_name"
android:src="#{imageLoader.imageResource}"
android:layout_centerInParent="true"/>
</RelativeLayout>
</layout>
HomeActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.sample.testdemo.databinding.ActivityHomeBinding
class HomeActivity : AppCompatActivity() {
lateinit var binding: ActivityHomeBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_home)
binding.imageLoader = ImageLoader()
}
}
Note: Don't forget to add below line at the top of app level build.gradle
apply plugin: 'kotlin-kapt'