I have created a custom input dialog for my application, and in terms of funcionality it works, but every time it has a sort of square background which distones from the actual dialog content. I tried to set a background color to tranparent e to a custom background to remove it, but it did not work. I would like help to know how can I make it so only the actual dialog appears without this background. I'm also using Material components to create the dialog, with MaterialCardView for the base, MaterialTextView and MaterialButton.
This is my dialog xml
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView 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:id="#+id/material_name_input_field"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:theme="#style/Theme.MaterialComponents.DayNight.Dialog.Alert"
app:cardCornerRadius="16dp"
app:cardElevation="1dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!-- -->
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/input_field"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/input_name_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="#string/input_serie_name"
android:textSize="16pt"
app:layout_constraintEnd_toStartOf="#+id/name_input_field"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.MaterialAutoCompleteTextView
android:id="#+id/name_input_field"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:text="#string/empty_text_input_field"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/input_name_title"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="#+id/negative"
style="#style/Widget.Material3.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="#string/cancel"
android:textSize="8pt"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/name_input_field" />
<com.google.android.material.button.MaterialButton
android:id="#+id/positive"
style="#style/Widget.Material3.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:text="#string/done"
android:textSize="8pt"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/name_input_field" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
Creating dialog here:
var inputDialog: InputDialog = InputDialog(parent)
inputDialog
.setCallbackFunction {
doSetSeriesName(series, it.toString(), onCardCreatedCallback)
inputDialog.dismiss()
}
.setTitle("Series Name:")
.show()
Dialog code
class InputDialog(
private var activity: Activity) : Dialog(activity), View.OnClickListener {
companion object {
private var TAG = "InputDialog"
}
private lateinit var textView: EditText
private lateinit var titleTextView: TextView
private lateinit var positive: MaterialButton
private lateinit var negative: MaterialButton
private lateinit var callbackFunction: (value: Any) -> Unit
fun setCallbackFunction(callbackFunction: (value: Any) -> Unit): InputDialog {
this.callbackFunction = callbackFunction
return this
}
fun setTitle(title: String): InputDialog {
titleTextView = findViewById(R.id.input_name_title)
titleTextView.text = title
return this
}
override fun onClick(view: View?) {
when (view?.id) {
R.id.positive -> {
callbackFunction(textView.text)
}
R.id.negative -> {
dismiss()
}
R.id.name_input_field -> {
SCLog.d(TAG, "Editing Name")
textView.text.clear()
}
else -> {
SCLog.d(TAG, "onClick: Unknown view.id")
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
SCLog.d(TAG, "onCreate: creating dialog")
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.input_dialog)
textView = findViewById(R.id.name_input_field)
textView.text.clear()
textView.setHint(R.string.series_name_title)
positive = findViewById(R.id.positive)
negative = findViewById(R.id.negative)
positive.setOnClickListener(this)
negative.setOnClickListener(this)
}
}
And this is a image of how it currently is:
Related
I have an activity that has two fragments. I have created a layout that is reusable as following:
Here is the xml of custom layout
<?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="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvFormTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black1"
android:textSize="#dimen/ssp_10"
android:visibility="visible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Email" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/clForm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/sdp_4"
android:background="#drawable/sh_all_round_form"
android:paddingStart="#dimen/sdp_12"
android:paddingEnd="#dimen/sdp_12"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvFormTitle">
<androidx.appcompat.widget.AppCompatEditText
android:id="#+id/etForm"
style="#style/et_form"
android:layout_width="0dp"
android:layout_weight="1"
app:layout_constraintEnd_toStartOf="#+id/ivSwitchPassword"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/ivSwitchPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingStart="#dimen/sdp_8"
android:paddingTop="#dimen/sdp_8"
android:paddingEnd="#dimen/sdp_2"
android:paddingBottom="#dimen/sdp_8"
android:src="#drawable/ic_eye"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="#+id/etForm"
app:layout_constraintEnd_toStartOf="#+id/ivCancel"
app:layout_constraintTop_toTopOf="#+id/etForm" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/ivCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingStart="#dimen/sdp_12"
android:paddingTop="#dimen/sdp_12"
android:paddingBottom="#dimen/sdp_12"
android:src="#drawable/white_close"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="#+id/etForm"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/etForm"
app:tint="#color/grey_shade5" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/sdp_5"
android:textColor="#color/colorError"
android:textSize="#dimen/ssp_10"
android:visibility="visible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/clForm"
tools:text="This field is required" />
</androidx.constraintlayout.widget.ConstraintLayout>
I am using this custom la in Fragment A as follow:
<include
android:id="#+id/email"
layout="#layout/layout_form_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/sdp_36"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvDescription" />
<include
android:id="#+id/password"
layout="#layout/layout_form_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/sdp_12"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/email" />
I am using Fragment navigation to move from Fragment A to B. Entering values in email and password and move to Fragment B and get back to Fragment A by pressing back or navigateUp(). Email field contains the value of password field.
Edit:
Same layout it used in Custom Compound class as following getting same issue.
class FormView #JvmOverloads
constructor(
private val ctx: Context,
private val attributeSet: AttributeSet? = null,
private val defStyleAttr: Int = 0
) : ConstraintLayout(ctx, attributeSet, defStyleAttr) {
private var formTitle = ""
private var passwordType = false
private var showMessage = false
init {
val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val attributes = ctx.obtainStyledAttributes(attributeSet, R.styleable.FormView)
attributes.getString(R.styleable.FormView_formTitle)?.let { formTitle = it }
passwordType = attributes.getBoolean(R.styleable.FormView_passwordType, passwordType)
showMessage = attributes.getBoolean(R.styleable.FormView_showErrorMessage, false)
attributes.recycle()
inflater.inflate(R.layout.layout_form_edittext, this)
setTitle(formTitle)
setPasswordType(passwordType)
errorMessageVisibility(showMessage)
borderVisibility(false)
ivSwitchPassword.setOnClickListener {
updatePasswordVisibility()
}
ivCancel.setOnClickListener {
etForm.text?.clear()
clearError()
}
}
fun showError(msg: String) {
msg?.let {
tvMessage.text = it
cancelBtnVisibility(true)
errorMessageVisibility(true)
borderVisibility(true)
}
}
fun clearError() {
tvMessage.text = ""
cancelBtnVisibility(false)
errorMessageVisibility(false)
borderVisibility(false)
}
private fun errorMessageVisibility(flag: Boolean) {
if (flag) tvMessage.visible() else tvMessage.gone()
}
private fun cancelBtnVisibility(flag: Boolean) {
if (flag) ivCancel.visible() else ivCancel.gone()
}
private fun borderVisibility(flag: Boolean) {
val drawable = clForm.background as GradientDrawable
if(flag) drawable.setStroke(1, Color.parseColor("#c32329"))
else drawable.setStroke(0, Color.TRANSPARENT)
}
fun setPasswordType(passwordType: Boolean) {
if(!passwordType) ivSwitchPassword.gone()
else {
ivSwitchPassword.visible()
etForm.inputType = InputTypeUtils.getInputTypeByProperty("textPassword")
}
}
fun setTitle(title: String) {
tvFormTitle.text = title
}
private fun updatePasswordVisibility() {
if (etForm.transformationMethod is PasswordTransformationMethod) {
etForm.transformationMethod = null
} else {
etForm.transformationMethod = PasswordTransformationMethod()
}
etForm.setSelection(etForm.length())
}
}
This is because include edit text has one id for both field, solution is to generate new id add this code on your onViewCreated method:
email.etForm.id = View.generateViewId()
password.etForm.id = View.generateViewId()
package com.example.colormyviews
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setListeners()
}
private fun setListeners(){
val boxOneText = findViewById<TextView>(R.id.box_one_text)
val boxTwoText = findViewById<TextView>(R.id.box_two_text)
val boxThreeText = findViewById<TextView>(R.id.box_three_text)
val boxFourText = findViewById<TextView>(R.id.box_four_text)
val boxFiveText = findViewById<TextView>(R.id.box_five_text)
val rootConstraintLayout = findViewById<View>(R.id.info_text)
val redButton = findViewById<Button>(R.id.red_button)
val greenButton = findViewById<Button>(R.id.green_button)
val yellowButton = findViewById<Button>(R.id.yellow_button)
val clickableViews: List<View> =
listOf(
boxOneText, boxTwoText, boxThreeText,
boxFourText, boxFiveText, rootConstraintLayout,
redButton, greenButton, yellowButton
)
for (item in clickableViews){
item.setOnClickListener{makeColored(it)}
}
}
private fun makeColored(view: View){
when (view.id) {
// Boxes using Color class colors for the background
R.id.box_one_text -> view.setBackgroundColor(Color.DKGRAY)
R.id.box_two_text -> view.setBackgroundColor(Color.GRAY)
R.id.box_three_text -> view.setBackgroundColor(Color.BLUE)
R.id.box_four_text -> view.setBackgroundColor(Color.MAGENTA)
R.id.box_five_text -> view.setBackgroundColor(Color.BLUE)
R.id.red_button -> box_three_text.setBackgroundResource(R.color.my_red)
R.id.yellow_button -> box_four_text.setBackgroundResource(R.color.my_yellow)
R.id.green_button -> box_five_text.setBackgroundResource(R.color.my_green)
else -> view.setBackgroundColor(Color.LTGRAY)
}
}
}
XML code.
<?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:id="#+id/constraint_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/box_one_text"
style="#style/whiteBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="#dimen/margin_wide"
android:layout_marginRight="16dp"
android:text="#string/box_one"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/box_two_text"
style="#style/whiteBox"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="#string/box_two"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/box_one_text" />
<TextView
android:id="#+id/box_three_text"
style="#style/whiteBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_wide"
android:layout_marginEnd="#dimen/margin_wide"
android:text="#string/box_three"
app:layout_constraintBottom_toTopOf="#+id/box_four_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/box_two_text"
app:layout_constraintTop_toTopOf="#+id/box_two_text" />
<TextView
android:id="#+id/box_four_text"
style="#style/whiteBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_wide"
android:layout_marginTop="#dimen/margin_wide"
android:layout_marginEnd="#dimen/margin_wide"
android:layout_marginBottom="#dimen/margin_wide"
android:text="#string/box_four"
app:layout_constraintBottom_toTopOf="#+id/box_five_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/box_two_text"
app:layout_constraintTop_toBottomOf="#+id/box_three_text" />
<TextView
android:id="#+id/box_five_text"
style="#style/whiteBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_wide"
android:layout_marginEnd="#dimen/margin_wide"
android:text="#string/box_five"
app:layout_constraintBottom_toBottomOf="#+id/box_two_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/box_two_text"
app:layout_constraintTop_toBottomOf="#+id/box_four_text" />
<TextView
android:id="#+id/label_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:fontFamily="#font/roboto"
android:text="#string/how_to_play"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBaseline_toBaselineOf="#+id/info_text"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="#+id/info_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:fontFamily="#font/roboto"
android:text="#string/tap_the_boxes_and_buttons"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="#+id/label_text"
app:layout_constraintTop_toBottomOf="#+id/box_two_text"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="#+id/red_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="#string/button_red"
app:layout_constraintBaseline_toBaselineOf="#+id/yellow_button"
app:layout_constraintEnd_toStartOf="#+id/yellow_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/yellow_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="#string/button_yellow"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/green_button"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/red_button"
app:layout_constraintTop_toBottomOf="#+id/info_text"
app:layout_constraintVertical_bias="1.0"/>
<Button
android:id="#+id/green_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:text="#string/button_green"
app:layout_constraintBaseline_toBaselineOf="#+id/yellow_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/yellow_button" />
</androidx.constraintlayout.widget.ConstraintLayout>
In makeColored() function, while calling setBackgroundResource() on box_three_text, box_four_text, box_five_text. It throws me an ' Unresolved reference error '. However id's with same name has been declared in XML file. I can't understand where the problem lies, Please help me to understand what's going on and why it is unable to read id's in Mainactivity.kt which has been declared in Mainactivity.xm.
instead of id use reference
R.id.red_button -> boxThreeText.setBackgroundResource(R.color.my_red)
R.id.yellow_button -> boxFourText.setBackgroundResource(R.color.my_yellow)
R.id.green_button -> boxFiveText.setBackgroundResource(R.color.my_green)
and make these buttons global variable. You can directly use ids if you are using kotlin synthetic, however I can't see any such import in your code. (And anyway you should not be using be kotlin synthetic as Kotlin-extension plugin is deprecated)
Instead of using id you have to define global variable, like this :
class MainActivity : AppCompatActivity() {
private lateinit var boxOneText: View
private lateinit var boxTwoText: View
private lateinit var boxThreeText: View
private lateinit var boxFourText: View
private lateinit var boxFiveText: View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setListeners()
}
private fun makeColored(view: View) {
when (view.id) {
R.id.box_one_text -> view.setBackgroundColor(Color.DKGRAY)
R.id.box_two_text -> view.setBackgroundColor(Color.GRAY)
R.id.box_three_text -> view.setBackgroundColor(Color.BLUE)
R.id.box_four_text -> view.setBackgroundColor(Color.MAGENTA)
R.id.box_five_text -> view.setBackgroundColor(Color.BLUE)
R.id.red_button -> boxThreeText.setBackgroundResource(R.color.my_red)
R.id.yellow_button -> boxFourText.setBackgroundResource(R.color.my_yellow)
R.id.green_button -> boxFiveText.setBackgroundResource(R.color.my_green)
else -> view.setBackgroundColor(Color.LTGRAY)
}
}
private fun setListeners() {
boxOneText = findViewById<TextView>(R.id.box_one_text)
boxTwoText = findViewById<TextView>(R.id.box_two_text)
boxThreeText = findViewById<TextView>(R.id.box_three_text)
boxFourText = findViewById<TextView>(R.id.box_four_text)
boxFiveText = findViewById<TextView>(R.id.box_five_text)
val rootConstraintLayout = findViewById<View>(R.id.constraint_layout)
val redButton = findViewById<Button>(R.id.red_button)
val greenButton = findViewById<Button>(R.id.green_button)
val yellowButton = findViewById<Button>(R.id.yellow_button)
val clickableViews: List<View> =
listOf(
boxOneText, boxTwoText, boxThreeText,
boxFourText, boxFiveText, rootConstraintLayout,
redButton, greenButton, yellowButton
)
for (item in clickableViews) {
item.setOnClickListener { makeColored(it) }
}
}
}
In my app I'm using custom view containing a TextInputLayout with the following code:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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/input_layout"
style="#style/UbiInput2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="-"
android:orientation="horizontal"
app:boxBackgroundColor="#color/white">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/input_value"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="textPersonName" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
And the kotlin
class TextInputView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
var errorMessage: String? = ""
init {
inflate(context, R.layout.text_input_view, this)
val attributes = context.obtainStyledAttributes(attrs, R.styleable.TextInputView)
val inputLayout = findViewById<TextInputLayout>(R.id.input_layout)
val inputValue = findViewById<TextInputEditText>(R.id.input_value)
inputLayout.hint = attributes.getString(R.styleable.TextInputView_hint)
inputValue.hint = attributes.getString(R.styleable.TextInputView_placeholderText)
inputLayout.isExpandedHintEnabled =
attributes.getBoolean(R.styleable.TextInputView_expandedHintEnabled, true)
errorMessage = attributes.getString(R.styleable.TextInputView_errorMessage)
inputLayout.isHelperTextEnabled = false
inputValue.inputType =
attributes.getInt(
R.styleable.TextInputView_android_inputType,
InputType.TYPE_CLASS_TEXT
)
if (attributes.hasValue(R.styleable.TextInputView_android_maxLength)) {
inputValue.filters += InputFilter.LengthFilter(
attributes.getInt(
R.styleable.TextInputView_android_maxLength,
100
)
)
}
inputValue.gravity =
attributes.getInt(R.styleable.TextInputView_android_gravity, Gravity.START)
if (attributes.getBoolean(R.styleable.TextInputView_android_gravity, false)) {
inputLayout.helperText = attributes.getString(R.styleable.TextInputView_helperText)
}
if (attributes.getBoolean(R.styleable.TextInputView_helperTextEnabled, false)) {
inputLayout.isHelperTextEnabled = true
inputLayout.helperText = attributes.getString(R.styleable.TextInputView_helperText)
}
inputLayout.startIconDrawable =
attributes.getDrawable(R.styleable.TextInputView_startIconDrawable)
attributes.recycle()
}
}
#BindingAdapter("textValue")
fun TextInputView.setTextValue(value: String?) {
value?.let {
setValue(value)
}
}
#InverseBindingAdapter(attribute = "textValue")
fun TextInputView.getTextValue(): String {
return value()
}
#BindingAdapter("textValueAttrChanged")
fun TextInputView.setListener(textAttrChanged: InverseBindingListener) {
val inputValue = findViewById<TextInputEditText>(R.id.input_value)
inputValue.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
textAttrChanged.onChange()
}
})
}
I have the following screen which go to the next fragment on button click. Using Navigation component.
But from the next screen, when I'm pressing back button to come back to the search form, the TextInputLayout values for hint, and helperText are all the same.
The only place I set those is inside the custom view. And from debugging I can see that all the correct values are set at that time.
I'm a bit out of ideas about what's going on there. Any hints would be appreciated.
Material library version used: 1.3.0-alpha04
All codebase has been migrated to view binding according the latest changes
The View is used as followed:
<?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="viewModel"
type="com.ubigo.features.v2.products.taxi.SearchViewModel" />
<variable
name="dateFormat"
type="com.ubigo.ubicore.date.UbiDate" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/rental_search_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background">
<androidx.cardview.widget.CardView
android:id="#+id/rental_search_form"
style="#style/WhiteCardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textView10">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constraintLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.ubigo.ubicore.ui.TextInputView
android:id="#+id/pickup"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
app:hint="#string/product_start"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:startIconDrawable="#drawable/ic_calendar"
app:textValue="#{dateFormat.getPrettyDate(viewModel.pickupDateTime)}" />
<View
android:id="#+id/divider6"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="?android:attr/listDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/pickup" />
<com.ubigo.ubicore.ui.TextInputView
android:id="#+id/dropoff"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:hint="#string/product_end"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/divider6"
app:startIconDrawable="#drawable/ic_calendar"
app:textValue="#{dateFormat.getPrettyDate(viewModel.destinationDatetime)}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<com.ubigo.ubicore.ui.LoaderButton
android:id="#+id/rental_search_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="16dp"
android:text="#string/product_rental_show_car"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/rental_search_location" />
<androidx.cardview.widget.CardView
android:id="#+id/rental_search_location"
style="#style/WhiteCardView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/rental_search_form">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/constraintLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.ubigo.ubicore.ui.TextInputView
android:id="#+id/user_location"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:helperText="#string/product_rental_location"
app:helperTextEnabled="true"
app:hint="#string/product_pickup_location"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:startIconDrawable="#drawable/ic_location_on_black_24dp"
app:textValue="#{viewModel.depAddress}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<TextView
android:id="#+id/textView10"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="32dp"
android:text="#string/product_rental_weekend"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
And the initialization of the Fragment:
class RentalSearchFragment : Fragment() {
val viewModel: SearchViewModel by viewModel()
private val binding get() = _binding!!
private var _binding: FragmentRentalSearchBinding? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (_binding == null) {
_binding = FragmentRentalSearchBinding.inflate(inflater, container, false)
binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = viewModel
binding.dateFormat = UbiDate()
}
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
I was able to solve this exact problem by implementing onSaveInstanceState, onRestoreInstanceState, dispatchSaveInstanceState, dispatchRestoreInstanceState, and setValues as described here
http://www.devexchanges.info/2016/03/custom-compound-view-in-android.html
The linked above goes into all the necessary detail about how to implement these functions. There's also undoubtedly countless other sources you can find about how to implement this android paradigm.
My click listener are not working even if I check with a Toast inside of them, it use to work but after I made a couple of change in my viewModel it stop working, I can't figure out what went wrong. This happen in my detail activity only, but work on the recyclerview that call this detail activity via intent. I'm using Viewmodel, Livedata, databinding and Room. The recyclerview and the detail view are using the same viewmodel.
This is the code of my Detail activity:
class BuyDetailActivity : AppCompatActivity() {
private lateinit var sharedViewModel: BuySharedViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lateinit var buy: Buy
sharedViewModel = ViewModelProviders.of(this).get(BuySharedViewModel::class.java)
val position = intent.getIntExtra("position", 0)
sharedViewModel.allBuys.observe(this, Observer<List<Buy>> { buys ->
buy = buys[position]
val binding: com.example.drake.kunuk.databinding.ActivityBuyDetailBinding =
DataBindingUtil.setContentView(this, com.example.drake.kunuk.R.layout.activity_buy_detail)
binding.buy = buy
val agentNumber = buy.agentNumber
bnvContactAgent.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
com.example.drake.kunuk.R.id.action_call -> {
val callNumberUri = Uri.parse("tel:$agentNumber")
val callIntent = Intent(Intent.ACTION_DIAL, callNumberUri)
startActivity(callIntent)
}
com.example.drake.kunuk.R.id.action_sms -> {
val smsNumberUri = Uri.parse("sms:$agentNumber")
val smsIntent = Intent(Intent.ACTION_SENDTO, smsNumberUri)
startActivity(smsIntent)
}
com.example.drake.kunuk.R.id.action_email -> {
val uriText = "mailto:xxxxxxxx#gmail.com" +
"?subject=" + Uri.encode("I'm interested in $agentNumber") +
"&body=" + Uri.encode("Hello, ")
val uri = Uri.parse(uriText)
val sendIntent = Intent(Intent.ACTION_SENDTO)
sendIntent.data = uri
startActivity(Intent.createChooser(sendIntent, "Send email"))
}
}
false
}
// set animation duration via code, but preferable in your layout files by using the animation_duration attribute
expandableTextView.setAnimationDuration(750L)
// set interpolators for both expanding and collapsing animations
expandableTextView.setInterpolator(OvershootInterpolator())
// or set them separately
expandableTextView.expandInterpolator = OvershootInterpolator()
expandableTextView.collapseInterpolator = OvershootInterpolator()
// toggle the ExpandableTextView
buttonToggle.setOnClickListener {
buttonToggle.setText(if (expandableTextView.isExpanded) com.example.drake.kunuk.R.string.more else com.example.drake.kunuk.R.string.less)
expandableTextView.toggle()
}
// but, you can also do the checks yourself
buttonToggle.setOnClickListener {
if (expandableTextView.isExpanded) {
expandableTextView.collapse()
buttonToggle.setText(com.example.drake.kunuk.R.string.more)
} else {
expandableTextView.expand()
buttonToggle.setText(com.example.drake.kunuk.R.string.less)
}
}
//Open photoView activity when clicked
ivHouseDetail.setOnClickListener {
applicationContext
.startActivity(
Intent(
applicationContext,
ViewPagerActivity::class.java
)
.putExtra("imageList", buy.propertyImage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
}
})
}
}
Here's my SharedViewmodel, use by both the fragment calling the detail activity and the detail activity.
class BuySharedViewModel(application: Application) : AndroidViewModel(application) {
private val repository: BuyRepository
var allBuys: LiveData<List<Buy>>
init {
val buyDao = KunukRoomDatabase.getDatabase(application, viewModelScope).buyDao()
val buyRemote = BuyRemote()
repository = BuyRepository.getInstance(buyDao , buyRemote)
//Use async because it return a result
viewModelScope.async { getAllBuys() }
allBuys = buyDao.loadAllBuys()
}
private suspend fun getAllBuys() {
repository.getBuys()
}
}
And finally this is the xml of the detail activity:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="buy" type="com.example.drake.kunuk.data.model.Buy"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent" android:layout_width="match_parent"
>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bnvContactAgent"
android:layout_width="match_parent"
android:background="#color/colorPrimary"
app:itemIconTint="#color/colorSecondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_nav_contact_agent"
android:layout_height="wrap_content"
app:layout_constraintHorizontal_bias="1.0"/>
<ScrollView
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_height="0dp" android:layout_width="0dp"
app:layout_constraintBottom_toTopOf="#+id/bnvContactAgent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".ui.buy.BuyDetailActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="230dp"
tools:srcCompat="#tools:sample/backgrounds/scenic"
android:id="#+id/ivHouseDetail"
android:scaleType="centerCrop"
android:contentDescription="#string/house"
app:imageUrl="#{buy.propertyImage}"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
app:formatToUSD="#{buy.price}"
android:id="#+id/tvPriceDetail"
android:textStyle="bold"
android:textColor="#color/colorPrimaryText"
android:textSize="20sp"
tools:ignore="HardcodedText"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="#+id/ivHouseDetail" android:layout_marginStart="8dp"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:text="#{buy.address}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvAddressDetail"
android:textColor="#color/colorSecondaryText"
app:layout_constraintTop_toBottomOf="#+id/tvPriceDetail"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"/>
<TextView
android:text="#{Integer.toString(buy.numberOfRoom)}"
android:maxLength="3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvBedroom"
android:layout_marginTop="12dp"
android:textStyle="bold"
android:textColor="#color/colorPrimaryText"
app:layout_constraintTop_toBottomOf="#+id/tvAddressDetail"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:srcCompat="#drawable/ic_bed"
android:id="#+id/ivBedroom"
android:contentDescription="#string/bedroom_icon"
app:layout_constraintStart_toEndOf="#+id/tvBedroom"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="#+id/tvAddressDetail"/>
<TextView
android:text="#{Integer.toString(buy.numberOfBath)}"
android:maxLength="3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvBathroom"
android:textStyle="bold"
android:textColor="#color/colorPrimaryText"
app:layout_constraintStart_toEndOf="#+id/ivBedroom"
android:layout_marginStart="20dp" app:layout_constraintTop_toTopOf="#+id/ivBedroom"
android:layout_marginTop="4dp"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp" app:srcCompat="#drawable/ic_bathtub"
android:id="#+id/imageView2"
android:contentDescription="#string/bathroom_icon"
app:layout_constraintStart_toEndOf="#+id/tvBathroom"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="#+id/tvAddressDetail"/>
<TextView
android:text="#{Integer.toString(buy.numberOfCar)}"
android:maxLength="3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvGarage"
android:textStyle="bold"
android:textColor="#color/colorPrimaryText"
app:layout_constraintStart_toEndOf="#+id/imageView2"
android:layout_marginStart="20dp" app:layout_constraintTop_toTopOf="#+id/imageView2"
android:layout_marginTop="4dp"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:srcCompat="#drawable/ic_garage"
android:id="#+id/imageView3"
android:contentDescription="#string/garage_icon"
app:layout_constraintStart_toEndOf="#+id/tvGarage"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="#+id/tvAddressDetail"/>
<View
android:id="#+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"
tools:layout_editor_absoluteY="281dp" tools:layout_editor_absoluteX="8dp"
app:layout_constraintBottom_toTopOf="#+id/tvDescTitle"
android:layout_marginBottom="4dp"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvDescTitle"
android:text="#string/description"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:textStyle="bold"
android:textSize="18sp"
android:textColor="#color/colorSecondaryText"
app:layout_constraintTop_toBottomOf="#+id/imageView3"
app:layout_constraintBottom_toTopOf="#id/expandableTextView"
app:layout_constraintStart_toStartOf="parent"/>
<at.blogc.android.views.ExpandableTextView
android:text="#{buy.propertyDesc}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/expandableTextView"
android:textColor="#color/colorSecondaryText"
android:maxLines="5"
android:ellipsize="end"
app:animation_duration="750"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toBottomOf="#+id/tvDescTitle"
app:layout_constraintEnd_toEndOf="parent"/>
<com.google.android.material.button.MaterialButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/buttonToggle"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:text="#string/more"
app:goneUnless="#{true}"
app:layout_constraintTop_toBottomOf="#+id/expandableTextView"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"/>
<TextView
app:photoCounter="#{buy.propertyImage}"
android:background="#99000000"
android:elevation="4dp"
android:padding="4dp"
android:textColor="#ffafffff"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="#+id/ivHouseDetail"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" tools:layout_editor_absoluteY="189dp"
tools:layout_editor_absoluteX="323dp" android:id="#+id/tvPhotoCounter"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
This code is my repository class, where I use the coroutines.
class BuyRepository (private val buyDao: BuyDao, private val buyRemote: BuyRemote) {
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.Default + job)
companion object {
//For singleton instantiation
#Volatile private var instance: BuyRepository? = null
fun getInstance(buyDao: BuyDao, buyRemote: BuyRemote) =
instance ?: synchronized(this) {
instance ?: BuyRepository(buyDao, buyRemote)
.also { instance = it}
}
}
suspend fun getBuys(){
refresh()
}
private suspend fun refresh(){
val list = scope.async {buyRemote.loadBuys()}
list.await().forEach { buy -> insert(buy) }
}
//#WorkerThread
private fun insert(buy: Buy) {
buyDao.insertBuy(buy)
}
}
// toggle the ExpandableTextView
buttonToggle.setOnClickListener { // <- Set listener here
buttonToggle.setText(if (expandableTextView.isExpanded) com.example.drake.kunuk.R.string.more else com.example.drake.kunuk.R.string.less)
expandableTextView.toggle()
}
// but, you can also do the checks yourself
buttonToggle.setOnClickListener { // <- And overwritten here - seems bad
if (expandableTextView.isExpanded) {
expandableTextView.collapse()
buttonToggle.setText(com.example.drake.kunuk.R.string.more)
} else {
expandableTextView.expand()
buttonToggle.setText(com.example.drake.kunuk.R.string.less)
}
}
Looks to me like you're overwriting the click listener. So ... don't do that :)
I have a question about how the visibility of an object in the ViewModel will change.
I'll tell you my case: I have a login interface that has two Edittexts and two buttons, a button and an Edittext are invisible by default, and I want the button that is visible to make the first Edittext and the button that I clicked invisible and make the second button and the second Edittext visible. And here's the problem, I could do all this in Activity, but I need to do it in ViewModel and I have no idea how to access the xml components from there.
I know all this is messy so I'll send the classes and if someone could tell me how to do this I'd appreciate it. Thank you. Thank you.
Login XML:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.quobis.sippo.ecco.viewmodel.LoginViewModel"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="LoginUser">
<ImageView
android:layout_width="250dp"
android:layout_height="200dp"
android:src="#drawable/logom"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"
/>
<EditText
android:id="#+id/usr"
android:layout_width="200dp"
android:layout_height="50dp"
android:hint="#string/hint_user"
android:textSize="18sp"
android:textColorPrimary="#color/colorLetterLogin"
android:backgroundTint="#color/colorBackButtLogin"
android:elevation="20dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="60dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6"
app:addTextChangedListener="#{viewModel.emailTextWatcher}"
/>
<Button
android:id="#+id/btn_usr"
android:layout_width="55dp"
android:layout_height="50dp"
android:background="#color/colorBackButtLogin"
android:drawableBottom="#drawable/ic_keyboard_arrow_right"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="260dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6"
android:onClick="#{viewModel::onUserClicked}"
/>
<EditText
android:id="#+id/pass"
android:layout_width="200dp"
android:layout_height="50dp"
android:hint="#string/hint_pass"
android:textSize="18sp"
android:shape="rectangle"
android:inputType="textPassword"
android:textColorPrimary="#color/colorLetterLogin"
android:backgroundTint="#color/colorBackButtLogin"
android:elevation="20dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="60dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6"
android:visibility="invisible"
android:onClick="#{viewModel::onLoginClicked}"
/>
<Button
android:id="#+id/btn_pass"
android:layout_width="55dp"
android:layout_height="50dp"
android:background="#color/colorBackButtLogin"
android:drawableBottom="#drawable/ic_keyboard_arrow_right"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="260dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6"
android:visibility="invisible"
/>
<Spinner
android:id="#+id/spinner_usr"
android:layout_width="120dp"
android:layout_height="40dp"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginLeft="40dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.85"
/>
</android.support.constraint.ConstraintLayout>
</layout>
ViewModel:
class LoginViewModel(private val listener: LoginResultCallbacks) :
ViewModel() {
private val user: UserModel
var userp ="jorge"
init {
this.user= UserModel(email = "")
}
fun emailTextWatcher(): TextWatcher {
return object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
user.setEmail(s.toString())
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable) {
}
}
}
fun onUserClicked(v: View) {
}
fun onLoginClicked(v:View) {
if (user.getEmail() == userp)
listener.onSucces("Correcto")
else
listener.onError("Fallo")
}
}
Note: the method to change the visibility would be the onUserClicked.
Main activity:
class LoginUser : AppCompatActivity(), LoginResultCallbacks {
lateinit var binding: ActivityLoginUserBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_login_user)
binding.viewModel = ViewModelProviders.of(this, LoginViewModelFactory(this)).get(LoginViewModel::class.java)
var languages = arrayOf("English", "EspaƱol", "Galego")
val spinner = binding.spinnerUsr
if (spinner != null) {
val arrayAdapter = ArrayAdapter(this, R.layout.spinner_item, languages)
spinner.adapter = arrayAdapter
}
}
override fun onSucces(message: String) {
Toast.makeText(this,"Login bueno", Toast.LENGTH_SHORT).show()
}
#SuppressLint("ResourceAsColor")
override fun onError(message: String) {
binding.btnUsr
btn_usr.setBackgroundColor(R.color.colorFailLogin)
}
}
You can use Android databinding. I will provide a rough example.
You need to create ObservableFields that your views in XML can bind to.
For example
val isVisible : ObservableField<Boolean> = ObservableField();
Then create a binding adapter
#BindingAdapter("customVisibility")
fun setVisibility(view : View, visible : Boolean) {
view.visibility = if (visible) View.VISIBLE else View.INVISIBLE
}
Then bind in your XML
app:customVisibility="#{viewModel.isVisible}"
Then you can change the visibility of the views just by modifying the isVisible property of your view model.
I have wrote a primer in Android Databinding and Functional MVVM. You can check it for further details (written in Kotlin)
https://medium.com/tompee/android-data-binding-and-functional-mvvm-b311e4c98d