I have a list that load in RecyclerView with CardView and in CardView I have a RecyclerView that have (max) 10 items, I load it now, but it has lag:
My First LessonContentListAdapter.kt:
class LessonContentListAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var onItemClickListener: ((LessonsContentList) -> Unit)? = null
fun setOnItemClickListener(listener: (LessonsContentList) -> Unit) {
onItemClickListener = listener
}
private val callback = object : DiffUtil.ItemCallback<LessonsContentList>() {
override fun areItemsTheSame(
oldItem: LessonsContentList,
newItem: LessonsContentList
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: LessonsContentList,
newItem: LessonsContentList
): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, callback)
override fun getItemCount(): Int {
return differ.currentList.size
}
inner class LessonContentListItems(private val lessonContentListItemsBinding: LessonContentListItemsBinding) :
RecyclerView.ViewHolder(lessonContentListItemsBinding.root) {
fun bind(lessons: LessonsContentList) {
lessonContentListItemsBinding.txtContentTitleO.text = lessons.titleOriginal
lessonContentListItemsBinding.txtContentTitleT.text = lessons.titleTranslate
lessonContentListItemsBinding.txtTime.text = lessons.timeLaps
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val view =
LessonContentListItemsBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return LessonContentListItems(view)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as LessonContentListItems).bind(differ.currentList[position])
val childLessonContentListVectorsAdapter =
ChildLessonContentListVectorsAdapter(
differ.currentList[position].imgLevels
)
holder.itemView.recyclerLessonsContentListVectors.layoutManager = LinearLayoutManager(
holder.itemView.recyclerLessonsContentListVectors.context,
LinearLayoutManager.HORIZONTAL,
false
)
holder.itemView.recyclerLessonsContentListVectors.setHasFixedSize(true)
holder.itemView.recyclerLessonsContentListVectors.adapter =
childLessonContentListVectorsAdapter
}
}
Second ChildLessonContentListVectorsAdapter.kt:
class ChildLessonContentListVectorsAdapter(imgLevels: List<ImgLevelsDetalis>) :
RecyclerView.Adapter<ChildLessonContentListVectorsAdapter.MyViewHolder>() {
var childModelArrayList: List<ImgLevelsDetalis> = imgLevels
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var heroImage: ImageView
init {
heroImage = itemView.findViewById(R.id.imgHaveStudied)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view: View = LayoutInflater.from(parent.context)
.inflate(R.layout.child_lessons_content_list, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem: ImgLevelsDetalis = childModelArrayList[position]
holder.heroImage.setImageResource(currentItem.img)
}
override fun getItemCount(): Int {
return childModelArrayList.size
}
}
First fragment_lesson_content_list.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:clickable="true"
android:fitsSystemWindows="true"
android:focusable="true"
tools:context=".presentation.ui.lessoncontentlist.LessonContentListFragment">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbarLessonContentList"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/purple_500"
android:contentInsetStart="0dp"
android:contentInsetLeft="0dp"
android:minHeight="?attr/actionBarSize"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<ImageButton
android:id="#+id/imgBackContent"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:background="#null"
android:paddingLeft="10dp"
android:src="#drawable/ic_baseline_arrow_back_24" />
<TextView
android:id="#+id/txtTitleContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:textColor="#color/white"
android:textStyle="bold" />
</RelativeLayout>
</androidx.appcompat.widget.Toolbar>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerLessonsContentList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/toolbarLessonContentList" />
</androidx.constraintlayout.widget.ConstraintLayout>
second lesson_content_list_items.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
card_view:cardBackgroundColor="#color/purple_700"
card_view:cardCornerRadius="4dp"
card_view:layout_constraintLeft_toLeftOf="parent"
card_view:layout_constraintRight_toRightOf="parent"
card_view:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:weightSum="10">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="5"
android:orientation="horizontal"
android:weightSum="10">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="8"
android:orientation="vertical">
<TextView
android:id="#+id/txtContentTitleO"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Grammer"
android:textColor="#color/white"
android:textStyle="bold" />
<TextView
android:id="#+id/txtContentTitleT"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="مکالمه"
android:textColor="#color/white" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:gravity="right"
android:orientation="horizontal">
<TextView
android:id="#+id/txtTime"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:text="2Min"
android:textColor="#color/white"
android:textStyle="bold" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="5dp"
android:adjustViewBounds="true"
android:scaleType="center"
android:src="#drawable/ic_baseline_timelapse_24" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:gravity="right"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerLessonsContentListVectors"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:orientation="horizontal" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
Third child_lessons_content_list.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="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right">
<ImageView
android:id="#+id/imgHaveStudied"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Firstly, you can use setInitialItemPrefetchCount() for a prefetching feature for nested RecyclerView. for more information please check this article
I think, the main reason, loading images from the server blocks the main thread. You can do this asynchronously. please check this article too.
Related
I trying to practice some android lessons that contains recyclerview topic, currently I succeed to implement all api and response but there's one problem with my item_article_preview.xml.
The title and description of news doesn't shows in emulator like it's in design preview
After running the app
here's my xml row
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:padding="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2"
android:orientation="horizontal">
<ImageView
android:id="#+id/ivArticleImage"
android:layout_width="0dp"
android:layout_height="90dp"
android:layout_weight="0.8"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.2"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#color/black"
android:textSize="15sp"
android:textStyle="bold"
tools:text="TITLE" />
<TextView
android:id="#+id/tvDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:maxLines="3"
android:textColor="#color/black"
android:text="DESCRIPTION" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="#+id/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="SOURCE"
android:textColor="#android:color/black" />
<TextView
android:id="#+id/tvPublishedAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="PUBLISHED AT"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSource" />
</LinearLayout>
I tried other row design but it didn't show the title and descreption at all
<?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"
android:padding="8dp">
<ImageView
android:id="#+id/ivArticleImage"
android:layout_width="160dp"
android:layout_height="90dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="SOURCE"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/ivArticleImage" />
<TextView
android:id="#+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="3"
android:text="TITLE"
android:textColor="#android:color/black"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="#+id/ivArticleImage"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/tvDescription"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:maxLines="5"
android:text="DESCRIPTION"
android:textColor="#android:color/black"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/ivArticleImage"
app:layout_constraintTop_toBottomOf="#+id/tvTitle" />
<TextView
android:id="#+id/tvPublishedAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="PUBLISHED AT"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSource" />
</androidx.constraintlayout.widget.ConstraintLayout>
RecyclerView 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">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvBreakingNews"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/paginationProgressBar"
style="?attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:background="#android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
my adapter class
private const val TAG = "NewsAdapter"
class NewsAdapter : RecyclerView.Adapter<NewsAdapter.ArticleViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
val binding = ItemRowBinding.inflate(LayoutInflater.from(parent.context))
return ArticleViewHolder(binding)
}
override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
val article = differ.currentList[position]
// holder.bind(article)
holder.binding.apply {
Glide.with(this.root).load(article.urlToImage).into(ivArticleImage)
tvSource.text = article.source.name
tvTitle.text = article.title
tvDescription.text = article.description
tvPublishedAt.text = article.publishedAt
this#NewsAdapter.setOnItemClickListener {
onItemClickListener?.let {
it(article)
}
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
inner class ArticleViewHolder( val binding: ItemRowBinding) :
RecyclerView.ViewHolder(binding.root) {
private var onItemClickListener: ((Article) -> Unit)? = null
private fun setOnItemClickListener(listener: (Article) -> Unit) {
onItemClickListener = listener
}
private val diffCallBack = object : DiffUtil.ItemCallback<Article>() {
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
val differ = AsyncListDiffer(this, diffCallBack)
}
ACTIVITY:
val list : MutableList<Item> = mutableListOf()
list.add(Item("TITLE", "DESCRITION", "ESPN", "2022-08-02T14:32:47Z"))
val rv = findViewById<RecyclerView>(R.id.rvBreakingNews)
rv.layoutManager = LinearLayoutManager(applicationContext)
rv.adapter = RvAdapter(list)
ADAPTER
class RvAdapter(private var list : List<Item>) : RecyclerView.Adapter<RvAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.title.setText(list[position].getTitle())
holder.desc.setText(list[position].getDescription())
holder.source.setText(list[position].getSource())
holder.published.setText(list[position].getPublished())
}
// return the number of the items in the list
override fun getItemCount(): Int {
return list.size
}
// Holds the views for adding it to image and text
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val title : TextView = itemView.findViewById(R.id.tvTitle)
val desc : TextView = itemView.findViewById(R.id.tvDescription)
val source : TextView = itemView.findViewById(R.id.tvSource)
val published : TextView = itemView.findViewById(R.id.tvPublishedAt)
val imageView : ImageView = itemView.findViewById(R.id.ivArticleImage)
}
}
ACTIVITY XML (SAME AS YOURS):
<?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">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/paginationProgressBar"
style="?attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
android:background="#android:color/transparent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
ITEM XML(SAME AS YOURS):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:orientation="vertical"
android:padding="8dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="2"
android:orientation="horizontal">
<ImageView
android:id="#+id/ivArticleImage"
android:layout_width="0dp"
android:layout_height="90dp"
android:layout_weight="0.8"
android:background="#android:drawable/sym_def_app_icon"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.2"
android:orientation="vertical">
<TextView
android:id="#+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#color/black"
android:textSize="15sp"
android:textStyle="bold"
tools:text="TITLE" />
<TextView
android:id="#+id/tvDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:ellipsize="end"
android:maxLines="3"
android:textColor="#color/black"
android:text="DESCRIPTION" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="#+id/tvSource"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="SOURCE"
android:textColor="#android:color/black" />
<TextView
android:id="#+id/tvPublishedAt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="PUBLISHED AT"
android:textColor="#android:color/black"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tvSource" />
</LinearLayout>
I found the problem causes this spilled of screen, here in this line
val binding = ItemRowBinding.inflate(LayoutInflater.from(parent.context))
you just inflated the inflater of a parent but there are two parameters is missing,
the viewGroup which it "parent and attachToRoot = false
edit your onCreateViewHolder like this
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ItemRowBinding.inflate(inflater,parent,false)
return ArticleViewHolder(binding)
}
I have horizontal recycler view in which each child has nested scroll view in which I have another horizontal recycler view. View seems to bo displaying fine but I am not able to scroll child recycler view. When I am trying to scroll - parent recycler view is scrolling, which is not what I want. Already was trying to set android:nestedScrollingEnabled="false” but it’s not working.
Main view 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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".views.home.WeatherView">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_WeatherRecycler"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="1dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="1dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ProgressBar
android:id="#+id/pb_WeatherLoading"
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>
Parent recycler view item xml:
<?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="match_parent"
android:layout_margin="8dp"
app:cardCornerRadius="40dp"
app:cardElevation="5dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:srcCompat="#drawable/ic_location">
<ImageView
android:id="#+id/iv_CityImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:srcCompat="#tools:sample/avatars"
/>
<androidx.core.widget.NestedScrollView
android:id="#+id/sv_ScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/iv_LocationIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
app:layout_constraintEnd_toStartOf="#+id/tv_CityName"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="#drawable/ic_location" />
<TextView
android:id="#+id/tv_CityName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="#+id/iv_LocationIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/iv_LocationIcon"
app:layout_constraintTop_toTopOf="#+id/iv_LocationIcon" />
<TextView
android:id="#+id/tv_CurrentTemp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="400dp"
android:text="TextView"
android:textSize="48sp"
app:layout_constraintBottom_toTopOf="#+id/tv_CurrentWeatherDesc"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/iv_LocationIcon"
app:layout_constraintVertical_chainStyle="spread" />
<TextView
android:id="#+id/tv_CurrentWeatherDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="TextView"
android:textSize="20sp"
app:layout_constraintBottom_toTopOf="#+id/tv_SunriseLabel"
app:layout_constraintEnd_toEndOf="#+id/tv_CurrentTemp"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/tv_CurrentTemp"
app:layout_constraintTop_toBottomOf="#+id/tv_CurrentTemp" />
<TextView
android:id="#+id/tv_SunriseLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="Sunrise"
app:layout_constraintBottom_toTopOf="#+id/tv_SunsetLabel"
app:layout_constraintEnd_toStartOf="#+id/tv_SunriseValue"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_CurrentWeatherDesc" />
<TextView
android:id="#+id/tv_SunsetLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="32dp"
android:text="Sunset"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/tv_SunsetValue"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_SunriseLabel" />
<TextView
android:id="#+id/tv_SunriseValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:text="SunriseVal"
app:layout_constraintBaseline_toBaselineOf="#+id/tv_SunriseLabel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/tv_SunriseLabel" />
<TextView
android:id="#+id/tv_SunsetValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:text="SunsetVal"
app:layout_constraintBaseline_toBaselineOf="#+id/tv_SunsetLabel"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/tv_SunsetLabel" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_HourlyForecastRecycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="32dp"
android:scrollbars="horizontal|vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_SunsetLabel" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Child item xml:
<?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="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="10dp"
app:cardElevation="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/tv_HourlyForecast_Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
app:layout_constraintBottom_toTopOf="#+id/iv_ForecastHourly_WeatherIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/iv_ForecastHourly_WeatherIcon"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="#+id/tv_HourlyForecast_Temp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/tv_HourlyForecast_Time"
app:srcCompat="#drawable/ic_error" />
<TextView
android:id="#+id/tv_HourlyForecast_Temp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/iv_ForecastHourly_WeatherIcon" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Main view code:
#AndroidEntryPoint
class WeatherView : Fragment() {
private var _binding: FragmentWeatherViewBinding? = null
private val binding: FragmentWeatherViewBinding get() = _binding!!
private val viewModel by viewModels<WeatherViewModel>()
private lateinit var weatherAdapter: WeatherAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentWeatherViewBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val cities = getSavedCitiesFromFirebase()
viewModel.getWeatherAndImageForCities(cities)
setupRecyclerView()
observeWeatherData()
}
private fun observeWeatherData() {
viewModel.citiesLoadingLiveData.observe(viewLifecycleOwner, { isLoading ->
if (isLoading) {
showLoading(true)
} else {
showLoading(false)
}
})
viewModel.citiesDataLiveData.observe(viewLifecycleOwner, { cities ->
if (cities != null) {
weatherAdapter.setCities(cities)
}
})
viewModel.cityFetchErrorLiveData.observe(viewLifecycleOwner, {
/* To Do */
})
}
private fun setupRecyclerView() {
weatherAdapter = WeatherAdapter()
binding.rvWeatherRecycler.apply {
layoutManager = LinearLayoutManager(
requireContext(), RecyclerView.HORIZONTAL, false
)
adapter = weatherAdapter
}
}
private fun showLoading(isLoading: Boolean) {
binding.pbWeatherLoading.visibility = if (isLoading) View.VISIBLE else View.GONE
}
private fun getSavedCitiesFromFirebase(): List<String> {
return listOf("Berlin", "Amsterdam")
}
}
Parent recycler view adapter code:
class WeatherAdapter: RecyclerView.Adapter<WeatherAdapter.WeatherViewHolder>() {
private var cities: MutableList<CityData> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeatherViewHolder {
val itemBinding = ItemWeatherBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return WeatherViewHolder(itemBinding.root, itemBinding)
}
override fun onBindViewHolder(holder: WeatherViewHolder, position: Int) {
holder.bind(cities[position])
}
override fun getItemCount(): Int {
return cities.size
}
fun setCities(newCities: List<CityData>) {
cities.clear()
cities.addAll(newCities)
notifyDataSetChanged()
}
class WeatherViewHolder(private val itemView: View, private val itemBinding: ItemWeatherBinding): RecyclerView.ViewHolder(itemBinding.root) {
fun bind(item: CityData) {
itemBinding.rvHourlyForecastRecycler.apply {
layoutManager = LinearLayoutManager(
itemView.context, RecyclerView.HORIZONTAL, false
)
adapter = HourlyForecastAdapter(item.forecastModel.list)
setHasFixedSize(true)
}
itemBinding.tvCityName.text = item.weatherModel.name
itemBinding.tvCurrentTemp.text = TemperatureConverter.convertKelvinToCelsius(item.weatherModel.main.temp).toString()
itemBinding.tvCurrentWeatherDesc.text = item.weatherModel.weather[0].description
itemBinding.tvSunriseValue.text = TimeConverter.convertTime(item.weatherModel.sys.sunrise)
itemBinding.tvSunsetValue.text = TimeConverter.convertTime(item.weatherModel.sys.sunset)
Glide
.with(itemBinding.ivCityImage)
.load(item.cityImg)
.error(R.drawable.ic_error)
.centerCrop()
.into(itemBinding.ivCityImage)
}
}
}
Child recycler view adapter code:
class HourlyForecastAdapter(private val forecast: List<WeatherForecast>): RecyclerView.Adapter<HourlyForecastAdapter.HourlyForecastViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HourlyForecastViewHolder {
val itemBinding = ItemWeatherHourlyForecastBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return HourlyForecastViewHolder(itemBinding)
}
override fun onBindViewHolder(holder: HourlyForecastViewHolder, position: Int) {
holder.bind(forecast[position])
}
override fun getItemCount(): Int {
return forecast.size
}
class HourlyForecastViewHolder(private val itemBinding: ItemWeatherHourlyForecastBinding): RecyclerView.ViewHolder(itemBinding.root) {
fun bind(item: WeatherForecast) {
Timber.d("DT: ${item.dt}")
itemBinding.tvHourlyForecastTime.text = TimeConverter.convertTime(item.dt.toInt())
itemBinding.tvHourlyForecastTemp.text = TemperatureConverter.convertKelvinToCelsius(item.main.temp).toString()
Glide
.with(itemBinding.ivForecastHourlyWeatherIcon)
.load("https://openweathermap.org/img/wn/${item.weather[0].icon}#2x.png")
.error(R.drawable.ic_error)
.centerCrop()
.into(itemBinding.ivForecastHourlyWeatherIcon)
}
}
}
So hello, I have a little problem here.
I can't implement my binding properly into adapter for RecycleView. I need it to display my products in cart as you can see in the code below. I am a beginner with adapter, so please help me.
CartItemsListAdapter.kt *here is where I want to implement binding*
class CartItemsListAdapter(
private val context: Context,
private var list: ArrayList<CartItem>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
RecyclerView.ViewHolder {
return MyViewHolder(
LayoutInflater.from(context).inflate(
R.layout.item_cart_layout,
parent,
false
)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val model = list[position]
if (holder is MyViewHolder) {
Glide.with(context)
.load(model.image)
.placeholder(R.drawable.ic_launcher)
.into(/*binding.ivCartItemImage*/)
//binding.tvCartItemPrice.text = model.price
//binding.tvCartItemTitle.text = model.title
}
}
override fun getItemCount(): Int {
return list.size
}
private class MyViewHolder(view: View) : RecyclerView.ViewHolder(view)
}
activity_cart_list.xml *xml file for reference and from where I want to take those bindings*
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activities.CartListActivity">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar_cart_list_activity"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="?attr/colorSecondary">
<ImageView
android:id="#+id/arrow_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/ic_arrow_left"
android:hapticFeedbackEnabled="true"
android:layout_marginTop="16sp"
android:padding="24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_gravity="top"
android:contentDescription="#string/back_button" />
<com.example.trieskask.utils.OswaldBold
android:id="#+id/tv_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="My cart"
android:textSize="26sp"
android:elevation="3dp"
android:textStyle="bold" />
</androidx.appcompat.widget.Toolbar>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_cart_items_list"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="#id/ll_checkout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar_cart_list_activity" />
<com.example.trieskask.utils.OswaldRegular
android:id="#+id/tv_no_cart_item_found"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="No cart item found!"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="#id/ll_checkout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/toolbar_cart_list_activity" />
<LinearLayout
android:id="#+id/ll_checkout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:elevation="4dp"
android:orientation="vertical"
android:padding="16dp"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.example.trieskask.utils.OswaldLight
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Subtotal:" />
<com.example.trieskask.utils.OswaldLight
android:id="#+id/tv_sub_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
tools:text="$100" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.example.trieskask.utils.OswaldLight
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Shipping charge:" />
<com.example.trieskask.utils.OswaldLight
android:id="#+id/tv_shipping_charge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
tools:text="$10" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.example.trieskask.utils.OswaldBold
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Total Amount" />
<com.example.trieskask.utils.OswaldBold
android:id="#+id/tv_total_amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
tools:text="$110" />
</LinearLayout>
<com.example.trieskask.utils.OswaldButton
android:id="#+id/btn_checkout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="16dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="16dp"
android:background="#drawable/btn_ripple_effect"
android:foreground="?attr/selectableItemBackground"
android:gravity="center"
android:text="Checkoutt"
android:textColor="#android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Thanks for any kind of help
You can refactor your MyViewHolder class to require an ActivityCartListBinding as a constructor argument. Then your onCreateViewHolder function will look like:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ActivityCartListBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return MyViewHolder(binding)
}
And finally your onBindViewHolder:
override fun onBindViewHolder(
holder: RecyclerView.ViewHolder,
position: Int
) {
val model = list[position]
if (holder is MyViewHolder) {
Glide.with(context)
.load(model.image)
.placeholder(R.drawable.ic_launcher)
.into(/*binding.ivCartItemImage*/)
holder.getBinding().tvCartItemPrice.text = model.price
holder.getBinding().tvCartItemTitle.text = model.title
}
}
View Holder
private class MyViewHolder(val binding: ActivityCartListBinding) : RecyclerView.ViewHolder(binding.root)
This should solve your issue.
I have recyclerview to show my order items but it has design issue and after 3 days changing it I have no other solution for it!
screenshot
Issues
Recyclerview is not covering page full height
Items have space same as recyclerview height (it shows 1 item per page!)
Code
fragment_order.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/orderItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.OrdersFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/orders_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
order_items.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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.cardview.widget.CardView
android:id="#+id/cardView2"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_marginBottom="5dp"
app:cardElevation="2dp"
android:layout_margin="5dp">
<FrameLayout
android:background="#color/orders"
android:layout_width="4dp"
android:layout_height="match_parent"/>
<TextView
android:id="#+id/order_Iid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:gravity="start|top"
android:text="#string/order_ID"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:id="#+id/order_status_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:layout_marginStart="10dp"
android:layout_marginTop="35dp"
android:text="#string/order_status"
android:textColor="#5CDCBD"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="#+id/order_price_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="10dp"
android:text="#string/price"
android:textSize="12sp"
android:textStyle="bold" />
</androidx.cardview.widget.CardView>
</LinearLayout>
OrdersFragment.kt
class OrdersFragment : Fragment() {
lateinit var sesssion: SessionManager
lateinit var laundriesRecycler: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val root = inflater.inflate(R.layout.fragment_orders, container, false)
sesssion = SessionManager(context)
laundriesRecycler = root.findViewById(R.id.orders_list)
getOrders()
return root
}
private fun getOrders() {
var session = SessionManager(context)
session.checkLogin()
var user = session.getUserDetails()
var token: String? = user.get(SessionManager.KEY_ACCESS_TOKEN)
val tokenFull = "Bearer $token"
val queue = Volley.newRequestQueue(context)
val url = "https://example.com/api/orders"
val stringReq : StringRequest =
object : StringRequest(
Method.GET, url,
Response.Listener { response ->
val list = Gson().fromJson(response, OrderArr::class.java)
laundriesRecycler.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
laundriesRecycler.adapter = OrdersAdapter(context, list)
},
Response.ErrorListener {
Toast.makeText(context, R.string.errorMessage, Toast.LENGTH_LONG)
.show()
}
){
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers["Content-Type"] = "application/json"
headers["Authorization"] = tokenFull
return headers
}
}
queue.add(stringReq)
}
}
Any idea?
Update
OrdersAdapter.kt
class OrdersAdapter(
val context: Context?,
private var orderList: OrderArr
) : RecyclerView.Adapter<OrdersAdapter.OrderViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrdersAdapter.OrderViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.orders_items,
parent,
false
)
//fixing width issue
val outMetrics = DisplayMetrics()
val display = parent.display
display?.getRealMetrics(outMetrics)
itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT)
return OrdersAdapter.OrderViewHolder(itemView)
}
override fun onBindViewHolder(holder: OrdersAdapter.OrderViewHolder, position: Int) {
val currentItem = orderList.data[position]
holder.orderId.text = "ID: " + currentItem.id
holder.price.text = if(currentItem.amount!= null){"Rp. " + currentItem.amount + " /KG"}else{"Not provided"}
holder.status.text = if(currentItem.lastProgress!= null) {currentItem.lastProgress.progress.name} else{"Unknown"}
holder.itemView.setOnClickListener {
val i: Intent = Intent(context, OrdersActivity::class.java)
i.putExtra("orderIDArgument", currentItem.id.toString())
it.context.startActivity(i);
}
}
override fun getItemCount() = orderList.data.size
class OrderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val orderId: TextView = itemView.findViewById(R.id.order_Iid)
val status: TextView = itemView.findViewById(R.id.order_status_text)
val price: TextView = itemView.findViewById(R.id.order_price_text)
}
}
Update 2
Activity_main.xml
Every fragment will replace each other inside this activity
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="56dp">
<androidx.fragment.app.FragmentContainerView
android:id="#+id/fragmentFragmentId"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/main_graphs"
tools:context=".MainActivity" />
</ScrollView>
<!--bottom navigation bar with items-->
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#color/colorPrimaryNewTheme"
android:backgroundTint="#color/colorPrimaryNewTheme"
app:backgroundTint="#android:color/white"
app:fabAlignmentMode="end"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="20dp"
app:fabCradleVerticalOffset="14dp"
app:hideOnScroll="true"
app:menu="#menu/bottom_menu"
tools:ignore="BottomAppBar,MissingConstraints" />
<!--Floating action button which is anchored to the bottom navigation button-->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="#color/colorPrimaryNewTheme"
android:contentDescription="#string/app_name"
android:src="#drawable/order"
app:backgroundTint="#color/colorPrimaryNewTheme"
app:layout_anchor="#id/bottomAppBar"
app:layout_dodgeInsetEdges="bottom"
tools:ignore="MissingConstraints" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Update 3
fragment_main.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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".main.MainFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/header_imageP"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/himage"
android:scaleType="centerCrop"
android:src="#drawable/main_header"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginStart="42dp"
android:layout_marginTop="31dp"
android:textColor="#FFFFFF"
android:text="#string/nameHint" />
<TextView
android:id="#+id/useremail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/username"
android:layout_alignParentStart="true"
android:layout_marginStart="42dp"
android:layout_marginTop="8dp"
android:textColor="#FFFFFF"
android:text="#string/emailHint" />
<ImageView
android:id="#+id/logo"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_below="#+id/useremail"
android:layout_alignParentStart="true"
android:layout_marginStart="41dp"
android:layout_marginTop="13dp"
android:contentDescription="#string/himage"
android:src="#drawable/logo" />
<TextView
android:id="#+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginStart="21dp"
android:layout_marginTop="118dp"
android:layout_toEndOf="#+id/logo"
android:text="#string/app_name"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold" />
<RelativeLayout
android:id="#+id/t1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="#+id/header_imageP"
android:layout_marginTop="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="6dp"
android:text="HIIII" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/t2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="#+id/t1"
android:layout_marginTop="4dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="6dp"
android:text="BYEEEE" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
First remove code for customizing width and height of recycler item view inside Adapter.
Like:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrdersAdapter.OrderViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.order_item,
parent,
false
)
//fixing width issue
/*val outMetrics = DisplayMetrics()
val display = parent.display
display?.getRealMetrics(outMetrics)
itemView.layoutParams = RecyclerView.LayoutParams(outMetrics.widthPixels, RecyclerView.LayoutParams.MATCH_PARENT)*/
return OrdersAdapter.OrderViewHolder(itemView)
}
Second, you are not putting any constraint to FragmentContainerView thats why it goes to (0,0) position by default and you have set it's height to wrap_content, so your recycler view looks like the posted image. And it is not recommended to use recycler view inside scroll view. Try with customizing Activity_main.xml as below:
<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/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.bottomappbar.BottomAppBar
android:id="#+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:fabAlignmentMode="end"
app:fabCradleMargin="10dp"
app:fabCradleRoundedCornerRadius="20dp"
app:fabCradleVerticalOffset="14dp"
app:hideOnScroll="true"
app:menu="#menu/bottom_menu"
tools:ignore="BottomAppBar,MissingConstraints"
app:layout_constraintBottom_toBottomOf="parent"/>
<fragment
android:id="#+id/nav_view"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toTopOf="#+id/bottomAppBar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/main_graphs" />
<!-- put FAB here -->
</androidx.constraintlayout.widget.ConstraintLayout>
I am building an android app which has follow and unfollow feature. I have 3 pages inside ViewPager in main home. Feed consist of post of the users based on interest.
For example, user A follows user B, that posts the article in 3 different interest food, travel and tech. In this case, user A will be able to see his all the post in the 3 different places. What I want is that if user A who follows B unfollow the user B from any of the page it will just get removed from all the pages and refresh the feed.
I want to observe that follow and unfollow event based on the user action and refresh the feed.
How to build observer for this pattern. I am open to use anything expect BroadcastReceiver.
feed_item.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:fresco="http://schemas.android.com/apk/res-auto"
android:id="#+id/parent_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
app:cardCornerRadius="4dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="6dp"
android:orientation="horizontal">
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/profilePicture"
android:layout_width="40dp"
android:layout_height="40dp"
fresco:roundedCornerRadius="#dimen/feed_rect_card_radius" />
<LinearLayout
android:id="#+id/linearlayout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:orientation="vertical">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:maxLines="1"
android:textColor="#color/darkTextColor" />
<TextView
android:id="#+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:fontFamily="#font/noto_sans_bold"
android:textColor="#747474"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton
android:id="#+id/followBtn"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
android:layout_marginEnd="32dp"
android:fontFamily="#font/noto_sans_bold"
android:gravity="center"
android:text="#string/follow"
android:textColor="#color/green"
android:textSize="10sp"
app:rippleColor="#color/green"
app:strokeColor="#color/green" />
<ImageView
android:id="#+id/pop_up_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|top"
android:layout_marginTop="4dp"
android:contentDescription="#null"
android:padding="2dp"
android:src="#drawable/ic_more_dark" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="4dp"
android:paddingTop="8dp"
android:paddingEnd="4dp"
android:paddingBottom="8dp">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp">
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/image"
android:layout_width="124dp"
android:layout_height="80dp"
fresco:roundedCornerRadius="#dimen/feed_rect_card_radius" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="4dp"
android:contentDescription="#null"
android:src="#drawable/ic_play_circle_feature" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="#dimen/item_offset">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/post_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:ellipsize="end"
android:fontFamily="#font/noto_sans_bold"
android:gravity="start|top"
android:maxLines="2"
android:textColor="#color/darkTextColor"
android:textSize="14sp"
android:textStyle="bold" />
<TextView
android:id="#+id/post_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="#font/noto_sans"
android:gravity="start"
android:lineSpacingExtra="4dp"
android:maxLines="2"
android:padding="2dp"
android:textSize="12sp"
android:visibility="gone" />
</LinearLayout>
<LinearLayout
android:id="#+id/categoryLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="horizontal" />
<FrameLayout
android:id="#+id/whatsAppShare"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:foreground="?attr/selectableItemBackground"
android:padding="4dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="#null"
android:src="#drawable/ic_whatsapp_fill" />
</FrameLayout>
</FrameLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
FeedAdapter
class FeedAdapter(private val mContext: Context, val fg: FragmentManager, val nodes: ArrayList<Feed.Item>, val tagId: Int) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var showLoader: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ViewTypes.FEED -> FeedItemVH(LayoutInflater.from(mContext).inflate(R.layout.feed_item, parent, false))
else -> FooterViewHolder(LayoutInflater.from(mContext).inflate(R.layout.layout_footer, parent, false))
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is FeedItemVH -> feedItemView(holder, nodes[position].fragments().feedItem())
else -> {
if (showLoader) (holder as FooterViewHolder).itemView.footerLoader.visibility = View.VISIBLE
else (holder as FooterViewHolder).itemView.footerLoader.visibility = View.GONE
}
}
}
private fun feedItemView(holder: FeedItemVH, feed: FeedItem) {
holder.followBtn.setOnClickListener {
//API call to follow/unfollow user and broadcast the result.
}
}
override fun getItemCount(): Int {
return when (nodes.size) {
0 -> 0
else -> nodes.size + 1
}
}
override fun getItemViewType(position: Int): Int {
return when {
position != 0 && position == itemCount - 1 -> ViewTypes.LOADER
else -> {
ViewTypes.FEED
}
}
}
fun showLoader(status: Boolean) {
showLoader = status
Handler().post { this.notifyDataSetChanged() }
}
interface ViewTypes {
companion object {
const val FEED = 1
const val LOADER = 2
}
}
}
Any type of help would be appreciated. Thanks!