Shared element comes to front of all view when activity transition - android

Hello everyone i have little problem about shared element.
I have using shared element at activity transition.
When click to recyclerView item that view comes to front of all view.
as you can see when i click to lowermost picture
begin transition fragment --> activity
private fun itemClicked(pos: Int, view: View) {
val intent = Intent(context, DetailActivity::class.java)
val title = view.findViewById<TextView>(R.id.title)
val photo = view.findViewById<ImageView>(R.id.photo)
intent.putExtra(IMAGE_TRANSITION_NAME, photo.transitionName)
intent.putExtra(TITLE_TRANSITION_NAME, title.transitionName)
val pair1 =
Pair.create(
photo as View,
ViewCompat.getTransitionName(photo).toString()
)
val pair2 =
Pair.create(
title as View,
ViewCompat.getTransitionName(title).toString()
)
val options = activity?.let {
ActivityOptionsCompat.makeSceneTransitionAnimation(it, pair2, pair1)
}
startActivity(intent, options?.toBundle())
}
my custom view holder
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="0dp"
app:contentPaddingBottom="0dp"
app:contentPaddingLeft="0dp"
app:contentPaddingRight="0dp"
app:contentPaddingTop="0dp"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:maxLines="2"
app:autoSizeMaxTextSize="#dimen/primary_text_medium"
app:autoSizeMinTextSize="#dimen/primary_text_small"
app:autoSizeTextType="uniform"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/photo"
tools:text="Deniz subaşı" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

Related

Adding Views Programatically in Kotlin

I've followed some previous questions and I've even solved this issue in some other projects, but for some reason I can't solve it here.
I have an app which creates "tasks" and creates a countdown for each one.
I have a view model with a list, and its observable via LiveData
val tasksList = mutableListOf<Task>()
private val _tasksListData = MutableLiveData(tasksList)
val tasksListData : LiveData<MutableList<Task>>
get() = _tasksListData
fun addNewTask(task : Task){
tasksList.add(task)
_tasksListData.value = tasksList
}
I have already check that the items are created via a log statement. So that's working alright.
Then in the fragment I'm observing this live data and trying to add dynamically each tag, but for some reason these are not shown:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_history,
container,
false
)
taskListContainer = binding.tasksListContainer
tasksViewModel = ViewModelProvider(requireActivity()).get(TasksViewModel::class.java)
//Checks if the list has some items, otherwise displays a message
checkTasksList()
tasksViewModel.tasksListData.observe(viewLifecycleOwner,{
for (item in it) {
val view: IndividualTaskViewBinding = DataBindingUtil.inflate(
inflater, R.layout.individual_task_view, container, false
)
view.taskTitle.text = item.name
view.taskDateCreated.text = item.dateCreated
view.taskTertiaryText.text = item.cyclesCompleted.toString()
taskListContainer.addView(view.root)
}
checkTasksList()
})
setHasOptionsMenu(true)
return binding.root
}
private fun checkTasksList(){
if(taskListContainer.childCount == 0 ){
binding.emptyListText.setVisibility(View.VISIBLE)
} else{
binding.emptyListText.setVisibility(View.GONE)
}
}
}
Here's the layout for each individual task:
<?xml version="1.0" encoding="utf-8"?>
<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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:minHeight="88dp">
<ImageView
android:id="#+id/task_item_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentStart="true"
android:paddingTop="8dp"
app:srcCompat="#drawable/tomato" />
<TextView
android:id="#+id/task_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_toEndOf="#id/task_item_icon"
android:paddingTop="16dp"
android:paddingEnd="16dp"
android:maxLines="1"
tools:text="Title"
android:textAppearance="?attr/textAppearanceSubtitle1"
/>
<TextView
android:id="#+id/task_date_created"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/task_title"
android:layout_gravity="center_vertical"
android:layout_toEndOf="#id/task_item_icon"
android:paddingEnd="16dp"
android:maxLines="1"
tools:text="Date created"
android:textAppearance="?attr/textAppearanceBody2"
/>
<TextView
android:id="#+id/task_tertiary_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/task_date_created"
android:layout_gravity="center_vertical"
android:layout_toEndOf="#id/task_item_icon"
android:paddingEnd="16dp"
android:maxLines="1"
tools:text="task_tertiary_text"
android:textAppearance="?attr/textAppearanceBody2"
/>
</RelativeLayout>
</layout>
And here's the layour of the fragment:
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".FragmentHistory">
<!-- using constraint layout so I can have the views floating in the screen-->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/empty_list_text"
style="#style/TextAppearance.MaterialComponents.Body1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/list_empty_text"
android:textAlignment="center"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="#+id/scrollView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/scrollView" />
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
<LinearLayout
android:id="#+id/tasks_list_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
As I mentioned before, the tasks are added to the list correclty, and the LiveData is also updated everytime a new task is added. But then the observer is not working, or the problem is when the layout is inflated.
Thank you very much for your help.
The entire project is here: https://github.com/arieldipietro/PomodoroTechnique
I just found that the problem is with the observer so I'm posting a new question Adding an Observer in a Tabbed Activity

Click events not working inside Custom PopupWindow

I am using PopupWindow with a custom view having 2 TextViews, I am trying to response against click event but click event is not triggering, following is the code that I am using
/* Get the binding object */
val binding: XYZBinding = XYZBinding.inflate(
LayoutInflater.from(applicationContext),
null,
false
)
binding.clickHandler = this
/* Set the popup menu window */
popupWindow = PopupWindow(binding.root)
popupWindow.contentView = LayoutInflater.from(applicationContext)
.inflate(R.layout.popup_menu_gang, null, false)
popupWindow.isTouchable = true
popupWindow.isFocusable = true
popupWindow.isOutsideTouchable = true
popupWindow.width = WindowManager.LayoutParams.WRAP_CONTENT
popupWindow.height = WindowManager.LayoutParams.WRAP_CONTENT
popupWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
popupWindow.setOnDismissListener(PopupWindow.OnDismissListener {
window.attributes.alpha = alpha
window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
window.decorView.invalidate()
})
popupWindow.showAsDropDown(binding.layoutHeader.imageViewMenu)
I have also tried a direct onClickListener but it doesn't work as well
binding.textViewGangPopupRenameButtons.setOnClickListener(View.OnClickListener {
Toast.makeText(applicationContext, "working", Toast.LENGTH_SHORT).show()
})
Following is the xml I am using
<?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>
<import type="xyz.BaseActivity" />
<variable
name="clickHandler"
type="BaseActivity" />
</data>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:layout_marginEnd="16dp"
app:cardCornerRadius="16dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/textViewGangPopupDelete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:fontFamily="#font/montserrat_medium"
android:onClick="#{(view) -> clickHandler.onClick(view)}"
android:paddingStart="16dp"
android:paddingTop="16dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:text="#string/delete"
android:textColor="#color/textColorBlue"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textViewGangPopupRenameButtons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:fontFamily="#font/montserrat_medium"
android:onClick="#{(view) -> clickHandler.onClick(view)}"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp"
android:text="#string/rename_buttons"
android:textColor="#color/textColorBlue"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/textViewGangPopupDelete" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</FrameLayout>
</layout>
Set the Id of Your Text View with the PopupView.. Like this
` val layoutInflater = activity!!
.getSystemService(AppCompatActivity.LAYOUT_INFLATER_SERVICE) as
LayoutInflater
val popupView: View =
layoutInflater.inflate(R.layout.custom_grid_bottomnav, null)
val popupWindow = PopupWindow(
popupView,
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
// popupWindow.dismiss()
val tx = popupView.findViewById<TextView>(R.id.text1) //change
tx.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
//Do what you want
}
}`

Horizontal recyclerview with snaphelper, how to center first and last element?

I've made a little sample of something I'm trying to do in a real app, and I can't figure out how to solve my issue. The current solution looks like this.
So I have a vertical list of movie categories, where within each genre, I have a horizontal list of movies. The first row, is showing The Exorcist as the first element, but it's not centered. The second row in Action, shows how it looks when I've scrolled a bit to the right. Last row is showing how the end of the row looks like.
I'd like to have the first and last of the rows, to be centered as well when they're "selected".
My main activity looks like this:
<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"
android:background="#android:color/white">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/moviesListRecyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="visible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#layout/movie_category_item_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
The movie_category_item_view looks like this:
<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/movieListLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/movieCategoryTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="40dp"
android:textColor="#android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Horror" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/moviesRecyclerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:orientation="horizontal"
android:visibility="visible"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/movieCategoryTitle"
tools:listitem="#layout/movie_horizontal_item_view" />
</androidx.constraintlayout.widget.ConstraintLayout>
And the movie_horizontal_item_view like this:
<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="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/movieTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="#android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Horror" />
<androidx.appcompat.widget.AppCompatImageView
android:id="#+id/image"
android:layout_width="237dp"
android:layout_height="209dp"
android:background="#android:color/black"
android:src="#drawable/ic_launcher_foreground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/movieTitle"
tools:src="#drawable/ic_launcher_foreground" />
</androidx.constraintlayout.widget.ConstraintLayout>
Hopefully what I'm asking for makes sense!
In case you want to try it out for yourself and see what I mean, it can be found on github here
use carouselview.CarouselView
<alirezat775.lib.carouselview.CarouselView
android:id="#+id/carousel_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
the adapter
class MyAdapter(var ctx: Context) : CarouselAdapter() {
private var vh: CarouselViewHolder? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CarouselViewHolder {
val inflater = LayoutInflater.from(parent.context)
val v = inflater.inflate(R.layout.home_list_item, parent, false)
vh = MyViewHolder(v)
return vh as MyViewHolder
}
override fun onBindViewHolder(holder: CarouselViewHolder, position: Int) {
}
inner class MyViewHolder(itemView: View) : CarouselViewHolder(itemView) {
}
}
the activity
class MainActivity : AppCompatActivity() {
var carousel: Carousel? = null
val adapter = MyAdapter(this)
override fun onCreate(savedInstanceState: Bundle?) {
carousel = Carousel(this, carousel_view, adapter)
carousel!!.setOrientation(CarouselView.HORIZONTAL, false)
// carousel!!.autoScroll(true, 5000, true)
// carousel!!.scaleView(true)
}
}

Access buttons from layout programmatically inflated within another layout

I am inflating a list of layouts programmatically from a xml into another layout.
The end result looks like the following image.
The number of checkboxes is different on each run, how can i get their state and also add listeners to the image button? Ideally i want only one listener that has an id of the selected layout.
This is the xml code.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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/chk_item_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="#+id/checkBox_chkitem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView_chkitem"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:text="TextView"
app:layout_constraintEnd_toStartOf="#+id/imageButton_chkitem"
app:layout_constraintStart_toEndOf="#+id/checkBox_chkitem"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="#+id/imageButton_chkitem"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#android:drawable/stat_notify_more" />
</android.support.constraint.ConstraintLayout>
And this is how i inflate the layouts
val checkitemlist = listOf<ChecklistItem>(ChecklistItem("Categoria", "conteudo"),
ChecklistItem("Categoria", "conteudo"),
ChecklistItem("Categoria", "conteudo"),
ChecklistItem("Categoria", "conteudo"))
for (item in checkitemlist) {
val inflater = LayoutInflater.from(context)
val layout = inflater.inflate(io.ubivis.ier.R.layout.checklistitem_layout, null, false) as ConstraintLayout
layout.textView_chkitem.text = item.textSimple
checklist_content_layout.addView(layout)
}
replace your code
for (item in checkitemlist) {
checklist_content_layout.removeAllViews()
val inflater = LayoutInflater.from(context)
val layout = inflater.inflate(io.ubivis.ier.R.layout.checklistitem_layout, null, false) as ConstraintLayout
layout.textView_chkitem.text = item.textSimple
checklist_content_layout.addView(layout)
}

MVVM notify View about loading state

I’m using LiveData by Google now and they recomend to use a MVVM patter design. For some of my requests I use RxJava2, and listen for responses in SubscribeWith(…).
For example, when I press a button to send some data to the remote data source, I’m showing some loading animation and want to hide it onComplete() event (inside subscribeWith(…)). The problem is that I don’t have an access to the View from ModelView. How it’s possible to let the View know that loading animation should be hidden?
My current idea is to create in interface inside ViewModel and implement it in View. But it ruins the concept of View and ViewModel separation.
Well you can use liveData for this :D
At your ViewModel class you can create a live data object like this
MutableLiveData<Boolean> isLoading = new MutableLiveData<>();
and for example make a function called downloadFinished and call it in the onComplete
for your remote code
private void downloadFinished() {
isLoading.setValue(true);
}
At your activity that use the view model you observe the value of the loading and hide the progress or what ever you want
TestViewModel viewModel = ViewModelProviders.of(this).get(TestViewModel.class);
viewModel.isLoading.observe(this, new Observer<Boolean>() {
#Override
public void onChanged(#Nullable Boolean isLoading) {
if (isLoading != null) {
if (isLoading) {
// hide your progress bar
}
}
}
});
you can use DataBinding for that too
make a separate layout to reuse it everywhere
laoding_state_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="match_parent">
<View
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:id="#+id/progressBar2"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
then include it inside your desired layout
<?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="android.view.View" />
<variable
name="viewModel"
type="com.blogspot.soyamr.notforgotagain.view.signin.SignInViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.signin.SignInFragment">
<include
android:id="#+id/include"
layout="#layout/toolbar_application"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/signInButtonView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="68dp"
android:layout_marginEnd="16dp"
android:onClick="#{() -> viewModel.logIn()}"
android:text="#string/sign_in"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/passwordTextInputLayout" />
<TextView
android:id="#+id/noAccountTextview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="4dp"
android:text="#string/no_account"
android:textColor="#android:color/black"
app:layout_constraintEnd_toStartOf="#+id/createAccountTextView"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/signInButtonView" />
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/emailTextInputLayout"
style="#style/myTextInputLayoutStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="80dp"
android:layout_marginEnd="16dp"
app:errorEnabled="true"
app:errorText="#{viewModel.emailErrorMessage}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/include">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/email"
android:inputType="textEmailAddress"
android:text="#={viewModel.emailText}" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/passwordTextInputLayout"
style="#style/myTextInputLayoutStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
app:errorText="#{viewModel.passwordErrorMessage}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/emailTextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="#string/password"
android:inputType="textPassword"
android:text="#={viewModel.passwordText}" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="#+id/createAccountTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:text="#string/create_one"
android:textColor="#color/textBlue"
app:layout_constraintBottom_toBottomOf="#+id/noAccountTextview"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/noAccountTextview"
app:layout_constraintTop_toTopOf="#+id/noAccountTextview" />
<!-- **here is the important include**-->
<include
android:id="#+id/here_must_be_id_or_no_databinding"
android:visibility="#{viewModel.isLoading ? View.VISIBLE : View.GONE}"
layout="#layout/loading_state" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
i included the whole XML for clarification.
then in your view model add this
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
// Override ViewModelProvider.NewInstanceFactory to create the ViewModel (VM).
class SignInViewModelFactory(private val repository: NoteRepository) :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T = SignInViewModel(repository) as T
}
class SignInViewModel(val repository: NoteRepository) : ViewModel() {
private val _isLoading = MutableLiveData(true)
val emailText = MutableLiveData("")
val passwordText = MutableLiveData("")
val isLoading: LiveData<Boolean> = _isLoading
fun logIn() {
//start loading, this will make the view start loading directly
_isLoading.value = true
if (isValidInput()) {
val res = repository.logIn(LoginUser(emailText.value!!, passwordText.value!!))
}//remove loading view
_isLoading.value = false
}
//code ..
}
notice that you are observing isLoading variable inside the XML so whenever its value is changed the view will observe the change and start act on it.

Categories

Resources