All the pieces You Must Know About RecyclerView | Cult Tech

roughly All the pieces You Must Know About RecyclerView will cowl the newest and most present suggestion kind of the world. manner in slowly appropriately you comprehend properly and accurately. will development your data adroitly and reliably

Earlier than you begin, sureYou’ll be able to confer with the Youtube demo video to know what we are going to do on this article. We are going to implement RecyclerView with,

  • State administration with a number of view sorts (loading, error, pagination, and many others.)
  • see binding
  • Pull to refresh
  • tough
  • Pagination
  • glitter loading animation
  • Scroll to the highest FAB
  • favourite button
  • error dealing with
  • popup menu
  • Delete/Replace/Insert merchandise

I wished to cowl every thing you may want in your undertaking. We hope this text helps you perceive extra about RecyclerView. It’s open to enhancements and feedback. Please let me know in case you have any.

Desk of Contents

We cannot be utilizing something fancy on this article, however I will assume you understand the fundamentals of RecyclerView, View Holder, Stay Knowledge and tips on how to implement it.

I’m going to leap some components of the codeso if you wish to see the supply codeyou will discover the hyperlink on the finish of this text.

software stage construct.gradle proceedings,

android 
//...
buildFeatures
viewBinding true

dependencies
//...
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation "com.fb.shimmer:shimmer:0.5.0"

response wrapper,

sealed class NetworkResponse<out T> 
knowledge class Loading(
val isPaginating: Boolean = false,
): NetworkResponse<Nothing>()

knowledge class Success<out T>(
val knowledge: T,
val isPaginationData: Boolean = false,
): NetworkResponse<T>()

knowledge class Failure(
val errorMessage: String,
val isPaginationError: Boolean = false,
): NetworkResponse<Nothing>()

You’ll be able to study extra about it at this hyperlink, Dealing with success knowledge and error callback responses from a community for Android tasks utilizing Sandwich | by Jae Woong Eum | ProAndroidDev

This enum class to assist us with view sorts, you will perceive higher once we truly use it. The use could be very easy.

enum class RecyclerViewEnum(val worth: Int) 
Empty(0),
Loading(1),
Error(2),
View(3),
PaginationLoading(4),
PaginationExhaust(5),

Operation it is going to assist us with Insert, Delete and Replace “operations”, it is going to make issues simpler for us to deal with upcoming adjustments.

knowledge class Operation<out T>(
val knowledge: T,
val operationEnum: OperationEnum
)

enum class OperationEnum
Insert,
Delete,
Replace,

Lastly, RecyclerViewModel knowledge class,

knowledge class RecyclerViewModel(
var id: String,
var content material: String = "",
var isLiked: Boolean = false,
)
val textual content: String
get() = "ID: $id"

override enjoyable equals(different: Any?): Boolean
if (this === different)
return true
if (different !is RecyclerViewModel)
return false
return different.id == id

override enjoyable hashCode() = Objects.hash(id)

Previously, I used to make use of notifyDataSetChanged and it was the best option to replace the RecyclerView, however I observed that it created efficiency points and prompted a nasty consumer expertise.

This occasion doesn’t specify what has modified within the knowledge set, forcing any observer to imagine that each one present parts and buildings are not legitimate. LayoutManagers shall be pressured to completely rebind and relay all seen views.

In the event you’re writing an adapter, it is at all times extra environment friendly to make use of the extra particular change occasions when you can. Depend upon notifyDataSetChanged() as a final resort.

First, it refreshes your entire RecyclerView and causes efficiency points, and needs to be a final resort, because the Android documentation factors out.

Second, it has no animation and your entire listing glints and causes a nasty consumer expertise.

DiffUtil is a utility class that calculates the distinction between two lists and generates a listing replace operation that converts the primary listing to the second.

DiffUtil involves the rescue. Calculate the adjustments within the listing and replace solely the mandatory parts.

class RecyclerViewDiffUtilCallBack(
non-public val oldList: Record<RecyclerViewModel>,
non-public val newList: Record<RecyclerViewModel>,
): DiffUtil.Callback()
override enjoyable getOldListSize() = oldList.dimension

override enjoyable getNewListSize() = newList.dimension

override enjoyable areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean
return oldList[oldItemPosition].id == newList[newItemPosition].id

override enjoyable areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean
return when
oldList[oldItemPosition].id != newList[newItemPosition].id -> false
oldList[oldItemPosition].content material != newList[newItemPosition].content material -> false
oldList[oldItemPosition].isLiked != newList[newItemPosition].isLiked -> false
else -> true


areContentsTheSame known as to examine if two parts have the identical knowledge.

areItemsTheSame known as to examine if two objects symbolize the identical aspect.

Earlier than we start, we’ll create two adapters. first is generic BaseAdapter<T> that many of the implementation shall be right here and the second is RecyclerViewAdapter. We may use a single adapter however having BaseAdapter makes issues a lot simpler for future makes use of. If in case you have multiple RecyclerView with comparable wants, as an alternative of repeating the identical code, we will create a base adapter and lengthen it.

@Suppress("UNCHECKED_CAST")
@SuppressLint("NotifyDataSetChanged")
summary class BaseAdapter<T>(open val interplay: Interplay<T>): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
non-public var errorMessage: String? = null
var isLoading = true
var isPaginating = false
var canPaginate = true

protected var arrayList: ArrayList<T> = arrayListOf()

protected summary enjoyable handleDiffUtil(newList: ArrayList<T>)

override enjoyable onBindViewHolder(holder: RecyclerView.ViewHolder, place: Int)
when(getItemViewType(place))
RecyclerViewEnum.View.worth ->
(holder as ItemViewHolderBind<T>).bind(arrayList[position], place, interplay)

RecyclerViewEnum.Error.worth ->
(holder as ErrorViewHolderBind<T>).bind(errorMessage, interplay)

RecyclerViewEnum.PaginationExhaust.worth ->
(holder as PaginationExhaustViewHolderBind<T>).bind(interplay)


override enjoyable getItemViewType(place: Int) : Int
return if (isLoading)
RecyclerViewEnum.Loading.worth
else if (errorMessage != null)
RecyclerViewEnum.Error.worth
else if (isPaginating && place == arrayList.dimension)
RecyclerViewEnum.PaginationLoading.worth
else if (!canPaginate && place == arrayList.dimension)
RecyclerViewEnum.PaginationExhaust.worth
else if (arrayList.isEmpty())
RecyclerViewEnum.Empty.worth
else
RecyclerViewEnum.View.worth

override enjoyable getItemCount(): Int
return if (isLoading

enjoyable setError(errorMessage: String, isPaginationError: Boolean)
//...

enjoyable setLoadingView(isPaginating: Boolean)
//...

enjoyable handleOperation(operation: Operation<T>)
//...

enjoyable setData(newList: ArrayList<T>, isPaginationData: Boolean = false)
//...

non-public enjoyable setState(rvEnum: RecyclerViewEnum)
//...

We are going to implement the features mentioned later. Let’s examine one after the other.

handleDiffUtil it is going to be applied in every adapter with the corresponding fashions. We are going to hold it as summary.

errorMessage, isLoading, isPaginating Y canPaginate the values ​​shall be used for the view sorts.

  • When errorMessage isn’t null, we are going to present Error view sort.
  • When isLoading it is true, let’s present Loading view sort.
  • When isPaginating is true and the place is the same as the dimensions of the listing, we are going to show PaginationLoading view sort.
  • When canPaginate is fake and the place is the same as the dimensions of the listing, we are going to show PaginationExhaust view sort.

getItemViewType returns the view sort of the aspect in place for the needs of seeing recycling. Think about using identification assets to uniquely establish aspect view sorts.

In getItemViewType we’re utilizing RecyclerViewEnum that we created earlier. We may simply cross numbers like 0, 1, 2, and many others. however to make issues simpler to learn we’re utilizing the enum class.

Let’s begin implementing the features mentioned.

enjoyable setErrorView(errorMessage: String, isPaginationError: Boolean) 
if (isPaginationError)
setState(RecyclerViewEnum.PaginationExhaust)
notifyItemInserted(itemCount)
else
setState(RecyclerViewEnum.Error)
this.errorMessage = errorMessage
notifyDataSetChanged()

enjoyable setLoadingView(isPaginating: Boolean)
if (isPaginating)
setState(RecyclerViewEnum.PaginationLoading)
notifyItemInserted(itemCount)
else
setState(RecyclerViewEnum.Loading)
notifyDataSetChanged()

Each of them setErrorView Y setLoadingView they’ve comparable implementations for various circumstances. Whether it is pagination, we name notifyItemInserted and add the corresponding view to the top of the listing. If it isn’t pagination, we set the state and use notifyDataSetChanged. We’re minimizing the usage of notifyDataSetChanged however on this case it’s essential.

enjoyable handleOperation(operation: Operation<T>) 
val newList = arrayList.toMutableList()

when(operation.operationEnum)
OperationEnum.Insert ->
newList.add(operation.knowledge)

OperationEnum.Delete ->
newList.take away(operation.knowledge)

OperationEnum.Replace ->
val index = newList.indexOfFirst
it == operation.knowledge

newList[index] = operation.knowledge

handleDiffUtil(newList as ArrayList<T>)

First, we copy the listing with toMutableList to keep away from the reference step and take the mandatory measures based on the operation. After that, we cross a brand new listing to handleDiffUtil and DiffUtil does its “magic”.

enjoyable setData(newList: ArrayList<T>, isPaginationData: Boolean = false) 
setState(RecyclerViewEnum.View)

if (!isPaginationData)
if (arrayList.isNotEmpty())
arrayList.clear()
arrayList.addAll(newList)
notifyDataSetChanged()
else
notifyItemRemoved(itemCount)

newList.addAll(0, arrayList)
handleDiffUtil(newList)

This operate shall be used to insert new knowledge into the listing. If we aren’t paginating, we clear the listing and add all new objects and at last replace the listing. If we’re paging, notifyItemRemoved to take away the paging view on the backside of the listing and add new objects and notify DiffUtil.

non-public enjoyable setState(rvEnum: RecyclerViewEnum) 
when(rvEnum)
RecyclerViewEnum.Empty ->
isLoading = false
isPaginating = false
errorMessage = null

RecyclerViewEnum.Loading ->
isLoading = true
isPaginating = false
errorMessage = null
canPaginate = true

RecyclerViewEnum.Error ->
isLoading = false
isPaginating = false

RecyclerViewEnum.View ->
isLoading = false
isPaginating = false
errorMessage = null

RecyclerViewEnum.PaginationLoading ->
isLoading = false
isPaginating = true
errorMessage = null

RecyclerViewEnum.PaginationExhaust ->
isLoading = false
isPaginating = false
canPaginate = false


Lastly, this operate merely units the values ​​based on the state. Once more, this operate is to make it simpler to know.

That is all for BaseAdapterwe’re going to implement RecyclerViewAdapter.

@Suppress("UNCHECKED_CAST")
class RecyclerViewAdapter(
override val interplay: Interplay<RecyclerViewModel>,
non-public val extraInteraction: RecyclerViewInteraction,
): BaseAdapter<RecyclerViewModel>(interplay)

override enjoyable onCreateViewHolder(guardian: ViewGroup, viewType: Int): RecyclerView.ViewHolder
return when(viewType)
RecyclerViewEnum.View.worth -> ItemViewHolder(CellItemBinding.inflate(LayoutInflater.from(guardian.context), guardian, false), extraInteraction)
RecyclerViewEnum.Loading.worth -> LoadingViewHolder(CellLoadingBinding.inflate(LayoutInflater.from(guardian.context), guardian, false))
RecyclerViewEnum.PaginationLoading.worth -> PaginationLoadingViewHolder(CellPaginationLoadingBinding.inflate(LayoutInflater.from(guardian.context), guardian, false))
RecyclerViewEnum.PaginationExhaust.worth -> PaginationExhaustViewHolder(CellPaginationExhaustBinding.inflate(LayoutInflater.from(guardian.context), guardian, false))
RecyclerViewEnum.Error.worth -> ErrorItemViewHolder(CellErrorBinding.inflate(LayoutInflater.from(guardian.context), guardian, false))
else -> EmptyViewHolder(CellEmptyBinding.inflate(LayoutInflater.from(guardian.context), guardian, false))

override enjoyable handleDiffUtil(newList: ArrayList<RecyclerViewModel>)
val diffUtil = RecyclerViewDiffUtilCallBack(
arrayList,
newList,
)
val diffResults = DiffUtil.calculateDiff(diffUtil, true)

arrayList = newList.toList() as ArrayList<RecyclerViewModel>

diffResults.dispatchUpdatesTo(this)

Since now we have carried out all of the implementations in BaseAdapter, it is extremely straightforward to create an adapter. We simply must cross within the view holders and implement handleDiffUtil.

little notes, interplay Y extraInteraction They’re interfaces for dealing with actions. You’ll be able to examine them from the supply code.

See typographic designs

It is already an extended article, so I will skip the implementations of view holders, apart from ItemViewHolder. You’ll be able to question different view holders from the supply code. If in case you have any questions, be happy to ask.

class ItemViewHolder(
non-public val binding: CellItemBinding,
non-public val extraInteraction: RecyclerViewInteraction,
): RecyclerView.ViewHolder(binding.root), ItemViewHolderBind<RecyclerViewModel> {
override enjoyable bind(merchandise: RecyclerViewModel, place: Int, interplay: Interplay<RecyclerViewModel>) {

val textual content = "Place: $place $merchandise.textual content"
binding.contentTV.textual content = merchandise.content material.ifBlank textual content
binding.idTV.textual content = merchandise.id
binding.favButton.setImageDrawable(ContextCompat.getDrawable(binding.root.context, if (merchandise.isLiked) R.drawable.ic_heart else R.drawable.ic_empty_heart))

binding.moreButton.setOnClickListener {
val popupMenu = PopupMenu(binding.root.context, binding.moreButton)
popupMenu.inflate(R.menu.popup_menu)

popupMenu.setOnMenuItemClickListener
when(it.itemId)
R.id.delete ->
strive
extraInteraction.onDeletePressed(merchandise)
catch (e: Exception)
Toast.makeText(
binding.root.context,
"Please wait earlier than doing any operation.",
Toast.LENGTH_SHORT
).present()

[email protected] true

R.id.replace ->
strive
extraInteraction.onUpdatePressed(merchandise)
catch (e: Exception)
Toast.makeText(
binding.root.context,
"Please wait earlier than doing any operation.",
Toast.LENGTH_SHORT
).present()

[email protected] true

else ->
[email protected] false


popupMenu.present()
}

binding.favButton.setOnClickListener
extraInteraction.onLikePressed(merchandise)

binding.root.setOnClickListener
strive
interplay.onItemSelected(merchandise)
catch (e: Exception)
Toast.makeText(
binding.root.context,
"Please wait earlier than doing any operation.",
Toast.LENGTH_SHORT
).present()


}
}

In bind operate, we arrange the UI parts and click on occasions. As soon as once more, there may be nothing “magic” about this.

const val PAGE_SIZE = 50

class MainRepository {

non-public val tempList = arrayListOf<RecyclerViewModel>().apply
for (i in 0..PAGE_SIZE)
add(RecyclerViewModel(UUID.randomUUID().toString(), "Content material $i"),)

enjoyable fetchData(web page: Int): Movement<NetworkResponse<ArrayList<RecyclerViewModel>>> = move {
emit(NetworkResponse.Loading(web page != 1))

kotlinx.coroutines.delay(2000L)

strive {
if (web page == 1)
emit(NetworkResponse.Success(tempList.toList() as ArrayList<RecyclerViewModel>))
else
val tempPaginationList = arrayListOf<RecyclerViewModel>().apply
for (i in 0..PAGE_SIZE)
add(RecyclerViewModel(UUID.randomUUID().toString(), "Content material $i * 2"),)

if (web page < 4)
emit(NetworkResponse.Success(
tempPaginationList,
isPaginationData = true,
))
else
emit(NetworkResponse.Failure(
"Pagination failed.",
isPaginationError = true
))


} catch (e: Exception)
emit(NetworkResponse.Failure(
e.message ?: e.toString(),
isPaginationError = web page != 1
))

}.flowOn(Dispatchers.IO)

enjoyable deleteData(merchandise: RecyclerViewModel): Movement<NetworkResponse<Operation<RecyclerViewModel>>> = move
kotlinx.coroutines.delay(1000L)

strive
emit(NetworkResponse.Success(Operation(merchandise, OperationEnum.Delete)))
catch (e: Exception)
emit(NetworkResponse.Failure(e.message ?: e.toString()))

.flowOn(Dispatchers.IO)

enjoyable updateData(merchandise: RecyclerViewModel): Movement<NetworkResponse<Operation<RecyclerViewModel>>> = move
kotlinx.coroutines.delay(1000L)

strive
merchandise.content material = "Up to date Content material $(0..10).random()"
emit(NetworkResponse.Success(Operation(merchandise, OperationEnum.Replace)))
catch (e: Exception)
emit(NetworkResponse.Failure(e.message ?: e.toString()))

.flowOn(Dispatchers.IO)

enjoyable toggleLikeData(merchandise: RecyclerViewModel): Movement<NetworkResponse<Operation<RecyclerViewModel>>> = move
kotlinx.coroutines.delay(1000L)

strive
merchandise.isLiked = !merchandise.isLiked
emit(NetworkResponse.Success(Operation(merchandise, OperationEnum.Replace)))
catch (e: Exception)
emit(NetworkResponse.Failure(e.message ?: e.toString()))

.flowOn(Dispatchers.IO)

enjoyable insertData(merchandise: RecyclerViewModel): Movement<NetworkResponse<Operation<RecyclerViewModel>>> = move
emit(NetworkResponse.Loading())

kotlinx.coroutines.delay(1000L)

strive
emit(NetworkResponse.Success(Operation(merchandise, operationEnum = OperationEnum.Insert)))
catch (e: Exception)
emit(NetworkResponse.Failure(e.message ?: e.toString()))

.flowOn(Dispatchers.IO)
}

We’ll attempt to fake we’re making a community request, ready for it to complete and current the information. We are going to use flows to current NetworkResponse.

for instance in fetchData first we ship the state of cost with NetworkResponse.Loading and wait 2 seconds. After ready, if the web page quantity is 1, which implies we’re updating or it is an preliminary fetch, we ship NetworkResponse.Success with knowledge If the web page quantity is completely different from 1, it implies that we’re paging and sending NetworkResponse.Success with isPaginationData = true.

Since we mimic the community request, if the web page quantity is 4, we exhaust paging and ship NetworkResponse.Failure with isPaginationError = true to show the pagination escape view.

We even have comparable logic for different features. The one distinction is that, in some circumstances, we use NetworkResponse with Operation. These features are used to imitate insert, replace, and delete.

class MainViewModel : ViewModel() {
non-public val repository = MainRepository()

non-public val _rvList = MutableLiveData<NetworkResponse<ArrayList<RecyclerViewModel>>>()
val rvList: LiveData<NetworkResponse<ArrayList<RecyclerViewModel>>> = _rvList

non-public val _rvOperation = MutableLiveData<NetworkResponse<Operation<RecyclerViewModel>>>()
val rvOperation: LiveData<NetworkResponse<Operation<RecyclerViewModel>>> = _rvOperation

non-public var web page: Int = 1

init
fetchData()

enjoyable refreshData()
web page = 1
fetchData()

enjoyable fetchData() = viewModelScope.launch(Dispatchers.IO)
repository.fetchData(web page).gather state ->
withContext(Dispatchers.Predominant)
_rvList.worth = state

if (state is NetworkResponse.Success)
web page += 1



enjoyable deleteData(merchandise: RecyclerViewModel) = viewModelScope.launch(Dispatchers.IO)
repository.deleteData(merchandise).gather state ->
withContext(Dispatchers.Predominant)
_rvOperation.worth = state


enjoyable updateData(merchandise: RecyclerViewModel) = viewModelScope.launch(Dispatchers.IO)
repository.updateData(merchandise).gather state ->
withContext(Dispatchers.Predominant)
_rvOperation.worth = state


enjoyable toggleLikeData(merchandise: RecyclerViewModel) = viewModelScope.launch(Dispatchers.IO)
repository.toggleLikeData(merchandise).gather state ->
withContext(Dispatchers.Predominant)
_rvOperation.worth = state


enjoyable insertData(merchandise: RecyclerViewModel) = viewModelScope.launch(Dispatchers.IO)
repository.insertData(merchandise).gather state ->
withContext(Dispatchers.Predominant)
_rvOperation.worth = state


enjoyable throwError() = viewModelScope.launch(Dispatchers.Predominant)
_rvList.worth = NetworkResponse.Failure("Error occured!")

enjoyable exhaustPagination() = viewModelScope.launch(Dispatchers.Predominant)
_rvList.worth = NetworkResponse.Failure(
"Pagination Exhaust",
true
)

}

View mannequin is simply right here to current the information to the consumer interface. We can have two LiveData, rvList Y rvOperation. rvList shall be used to hear for adjustments to our listing and rvOperation shall be used to hear for operations, eg a brand new aspect is inserted and we are going to hear for that operation and deal with it within the UI.

class MainFragment : BaseFragment<FragmentMainBinding>() {
non-public lateinit var viewModel: MainViewModel
non-public var recyclerViewAdapter: RecyclerViewAdapter? = null
non-public var loadingDialog: Dialog? = null

//OnCreate and OnCreateView commented.

override enjoyable onViewCreated(view: View, savedInstanceState: Bundle?)
tremendous.onViewCreated(view, savedInstanceState)

setDialog(view.context)
setListeners()
setRecyclerView()
setObservers()

non-public enjoyable setDialog(context: Context)
loadingDialog = Dialog(context)
loadingDialog?.setCancelable(false)
loadingDialog?.setContentView(R.format.dialog_loading)
loadingDialog?.window?.setBackgroundDrawable(ColorDrawable(Colour.TRANSPARENT))

non-public enjoyable setListeners()
binding.swipeRefreshLayout.setOnRefreshListener
viewModel.refreshData()

binding.swipeRefreshLayout.isRefreshing = false

binding.errorButton.setOnClickListener
viewModel.throwError()

binding.appendButton.setOnClickListener
if (recyclerViewAdapter?.canPaginate == true && recyclerViewAdapter?.isPaginating == false)
viewModel.fetchData()

binding.mainRV.scrollToPosition(recyclerViewAdapter?.itemCount ?: 0)

binding.insertButton.setOnClickListener
viewModel.insertData(RecyclerViewModel(UUID.randomUUID().toString()))

binding.paginateErrorButton.setOnClickListener
viewModel.exhaustPagination()

binding.fab.setOnClickListener
viewLifecycleOwner.lifecycleScope.launch
binding.mainRV.quickScrollToTop()


non-public enjoyable setObservers()
viewModel.rvList.observe(viewLifecycleOwner) response ->
binding.swipeRefreshLayout.isEnabled = when (response)
is NetworkResponse.Success ->
true

is NetworkResponse.Failure ->
response.isPaginationError

else -> false

when(response)
is NetworkResponse.Failure ->
recyclerViewAdapter?.setErrorView(response.errorMessage, response.isPaginationError)

is NetworkResponse.Loading ->
recyclerViewAdapter?.setLoadingView(response.isPaginating)

is NetworkResponse.Success ->
recyclerViewAdapter?.setData(response.knowledge, response.isPaginationData)


viewModel.rvOperation.observe(viewLifecycleOwner) response ->
when(response)
is NetworkResponse.Failure ->
if (loadingDialog?.isShowing == true)
loadingDialog?.dismiss()

is NetworkResponse.Loading ->
if (recyclerViewAdapter?.isLoading == false)
loadingDialog?.present()

is NetworkResponse.Success ->
if (loadingDialog?.isShowing == true)
loadingDialog?.dismiss()
recyclerViewAdapter?.handleOperation(response.knowledge)



non-public enjoyable setRecyclerView()
//... Later

}

we are going to implement setRecyclerView operate later,

setListeners The operate is to configure the press or replace listeners. A lot of the buttons are for testing functions and will not be actually wanted. binding.fab is to maneuver to the highest button. quickScrollToTop is customized operate by patrick elmquist. You’ll be able to examine his article at this hyperlink.

In rvList.observe,

  • We set the swipeRefreshLayout.isEnabled since we do not need the consumer to replace once more once we are already loading the information.
  • In when(response)we confirm NetworkResponse write and name the wanted operate with recyclerViewAdapter.

similar logic in rvOperation.observe,

  • We examine the reply in when(response) and name the required operate.
    The one distinction is that we present both dismiss load dialog.
load dialog
non-public enjoyable setRecyclerView() {
binding.mainRV.apply {
val linearLayoutManager = LinearLayoutManager(context)
layoutManager = linearLayoutManager
addItemDecoration(DividerItemDecoration(context, linearLayoutManager.orientation))
recyclerViewAdapter = RecyclerViewAdapter(object: Interplay<RecyclerViewModel>
override enjoyable onItemSelected(merchandise: RecyclerViewModel)
Toast.makeText(context, "Merchandise $merchandise.content material", Toast.LENGTH_SHORT).present()

override enjoyable onErrorRefreshPressed()
viewModel.refreshData()

override enjoyable onExhaustButtonPressed()
viewLifecycleOwner.lifecycleScope.launch
quickScrollToTop()


, object: RecyclerViewInteraction
override enjoyable onUpdatePressed(merchandise: RecyclerViewModel)
viewModel.updateData(merchandise.copy())

override enjoyable onDeletePressed(merchandise: RecyclerViewModel)
viewModel.deleteData(merchandise)

override enjoyable onLikePressed(merchandise: RecyclerViewModel)
viewModel.toggleLikeData(merchandise.copy())

)
adapter = recyclerViewAdapter

var isScrolling = false
addOnScrollListener(object: RecyclerView.OnScrollListener()
override enjoyable onScrollStateChanged(recyclerView: RecyclerView, newState: Int)
tremendous.onScrollStateChanged(recyclerView, newState)
isScrolling = newState != AbsListView.OnScrollListener.SCROLL_STATE_IDLE

override enjoyable onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) dy >= 60)
binding.fab.conceal()

recyclerViewAdapter?.let
if (
isScrolling &&
lastVisibleItemPosition >= itemCount.minus(5) &&
it.canPaginate &&
!it.isPaginating
)
viewModel.fetchData()



)
}
}

Lastly, setRecyclerView operate. We create and configure recyclerViewAdapter a binding.mainRV.

We additionally implement addScrollListener which shall be used to indicate/conceal fab and activate pagination.

  • For fab.present, we examine if now we have scrolled sufficient and a sure variety of seen parts. In that case, if now we have additionally shifted some quantity within the damaging course. fab.conceal it is the reverse of that. You’ll be able to check it your self and set numbers your self.
  • For pagination, we examine if we’re scrolling and if we’re at a sure quantity earlier than the final seen merchandise and if canPaginate & if we aren’t already paging.

We are going to separate the glow into two components, the primary would be the regular design half and the second shall be ShimmerFrameLayout,

<?xml model="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"
android:layout_marginVertical="6dp">

<TextView
android:id="@+id/shimmerIdTV"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="12dp"
android:textColor="@colour/black"
android:background="@colour/shimmer_color"
app:layout_constraintEnd_toStartOf="@+id/shimmerFavButton"
app:layout_constraintStart_toStartOf="guardian"
app:layout_constraintTop_toTopOf="guardian" />

<TextView
android:id="@+id/shimmerContentTV"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="12dp"
android:layout_marginBottom="8dp"
android:background="@colour/shimmer_color"
android:textColor="@colour/black"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="guardian"
app:layout_constraintEnd_toStartOf="@+id/shimmerFavButton"
app:layout_constraintStart_toStartOf="guardian"
app:layout_constraintTop_toBottomOf="@+id/shimmerIdTV" />

<ImageView
android:id="@+id/shimmerFavButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="8dp"
android:background="@colour/shimmer_color"
app:layout_constraintBottom_toBottomOf="@+id/shimmerMoreButton"
app:layout_constraintEnd_toStartOf="@+id/shimmerMoreButton"
app:layout_constraintTop_toTopOf="@+id/shimmerMoreButton"
app:layout_constraintVertical_bias="0.407" />

<ImageView
android:id="@+id/shimmerMoreButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="8dp"
android:background="@colour/shimmer_color"
app:layout_constraintBottom_toBottomOf="guardian"
app:layout_constraintEnd_toEndOf="guardian"
app:layout_constraintTop_toTopOf="guardian"/>
</androidx.constraintlayout.widget.ConstraintLayout>

simmerColor the code is #BFBDBD

We merely copy and paste the format of the RecyclerView aspect and add background=”@colour/shimmer_color” every one among them.

<?xml model="1.0" encoding="utf-8"?>
<com.fb.shimmer.ShimmerFrameLayout
android:id="@+id/shimmerLoadingLayout"
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"
app:shimmer_auto_start="true"
app:shimmer_duration="1300">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
<embody format="@format/cell_shimmer"/>
</LinearLayout>
</com.fb.shimmer.ShimmerFrameLayout>

Inside ShimmerFrameLayoutwe set auto_start="true" to begin the animation routinely. period is the time it takes to complete the animation. You’ll be able to see extra about it right here.

You’ll be able to lower or enhance the variety of designs included. I’ve tried so as to add as little as potential to cowl your entire display. Much less is best for efficiency I feel 🙂

That is it! I hope you have got been useful. 👋👋

MrNtlu/RecyclerView-Information (github.com)

I want the article kind of All the pieces You Must Know About RecyclerView provides keenness to you and is beneficial for rely to your data

Everything You Need to Know About RecyclerView